This document provides essential information for AI coding agents working on the RecoilEngine codebase.
RecoilEngine is an open-source real-time strategy (RTS) game engine written in C++23. It is a fork and continuation of the Spring RTS engine (version 105.0).
Using Docker (Recommended):
# Build for Linux
docker-build-v2/build.sh linux
# Build for Windows
docker-build-v2/build.sh windows
# Build with custom CMake options
docker-build-v2/build.sh linux -DCMAKE_BUILD_TYPE=DEBUGWithout Docker:
# Create build directory
mkdir -p build && cd build
# Configure
cmake ..
# Build specific target
cmake --build . --target engine-headless -j$(nproc)
# Build all
cmake --build . -j$(nproc)DEBUG- Debug build with full symbols and no optimizationRELEASE- Optimized release buildRELWITHDEBINFO- Release with debug info (default)PROFILE- Profiling build
engine-legacy- Main engine buildengine-headless- Headless server buildengine-dedicated- Dedicated server buildtests- Build all test executablescheck- Build and run all testsspring-content- Build game content packages
The project uses Catch2 for unit testing. Test files are located in the test/ directory.
Build and run all tests:
# From build directory
make tests # Build all test executables
make check # Build and run all tests via CTest
make test # Alternative: run via CTestRun a single test:
# Tests are built as executable binaries in the build directory
# Pattern: test_<TestName>
# Run specific test executable
./test_Float3
./test_Matrix44f
./test_SyncedPrimitive
./test_UDPListener
# Run with verbose output
./test_Float3 -s
# Run specific test case
./test_Float3 "TestSection"Run via CTest:
# Run specific test by name
ctest -R Float3 -V
# Run with regex pattern
ctest -R Matrix -V
# List all available tests
ctest -N- Unit tests:
test/engine/ - Test sources use
#include <catch_amalgamated.hpp> - Each test is compiled as a separate executable named
test_<TestName>
- Use tabs for indentation (see
.editorconfig) - Tab width: configure your editor to display tabs as you prefer
- Line endings: platform-appropriate (LF on Linux, CRLF on Windows)
All source files must begin with the GPL license header:
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */Use #pragma once for new headers, migrate ifdef guards to #pragma once whenever you edit a header file.
Classes and Structs:
- PascalCase:
Button,GameVersion,RectangleOverlapHandler - Descriptive names: avoid abbreviations unless widely known
Functions and Methods:
- PascalCase for public methods:
DrawSelf(),HandleEvent() - Getters/setters:
GetMajor(),Label()
Variables:
- Member variables: camelCase or snake_case:
label,clicked,hovered - Local variables: camelCase preferred
- Boolean variables: often use
is,hasprefixes or simple names:Hovered,Clicked
Constants:
- Compile-time constants: UPPER_CASE or PascalCase
- const variables: camelCase
Namespaces:
- lowercase:
agui,spring,springversion
Macros:
- UPPER_CASE with underscores:
LOG_LEVEL_DEBUG,CR_DECLARE_STRUCT
Functions:
// Opening brace on new line
void ClassName::MethodName()
{
// body
}Control structures:
// Opening brace on same line
if (condition) {
// body
} else {
// body
}
for (int i = 0; i < n; ++i) {
// body
}
switch (value) {
case CASE_ONE:
// handle
break;
default:
// handle
}Classes:
class ClassName : public BaseClass
{
public:
ClassName();
virtual ~ClassName();
void PublicMethod();
private:
void privateMethod();
int memberVariable;
};Order:
- Corresponding header (for .cpp files)
- System/STL headers (angle brackets)
- Library headers (angle brackets)
- Project headers (quotes)
Example:
#include "ClassName.h" // Corresponding header
#include <cassert> // System headers
#include <string>
#include <vector>
#include <SDL2/SDL.h> // Library headers
#include "System/Log/ILog.h" // Project headers
#include "Rendering/GL/myGL.h"Include paths:
- Use relative paths from
rts/directory - Example:
#include "System/float3.h"
Assertions:
#include <cassert>
assert(pointer != nullptr);
assert(index >= 0 && index < size);Logging: Use the built-in logging system with severity levels:
#include "System/Log/ILog.h"
LOG_L(L_DEBUG, "Debug message: %s", value);
LOG_L(L_INFO, "Info message");
LOG_L(L_WARNING, "Warning: %d items", count);
LOG_L(L_ERROR, "Error occurred in %s", functionName);
LOG_L(L_FATAL, "Fatal error - cannot continue");Log levels (defined in System/Log/Level.h):
L_DEBUG- Fine-grained debug infoL_INFO- General informationL_NOTICE- Always outputted (default level)L_DEPRECATED- Deprecation warningsL_WARNING- Potentially harmful situationsL_ERROR- Errors that allow continued executionL_FATAL- Severe errors causing abort
Exceptions:
#include <stdexcept>
throw std::runtime_error("Description of error");Custom exceptions may be defined in specific modules.
File-level:
- GPL license header (required)
- Brief description of file purpose
Documentation:
/**
* @brief Brief description
*
* Detailed description of the function/class.
*
* @param paramName Description of parameter
* @return Description of return value
*/Inline comments:
// Single-line comments for brief notes
// Use // for C++ code, /* */ for C codeC++ Standard: C++23
Modern C++ usage:
- Use
constexprfor compile-time constants - Prefer
autofor type deduction when type is obvious - Use range-based for loops
- Use smart pointers where appropriate
- Use
nullptrinstead ofNULLor0
Synced code: The engine has special macros for synchronized multiplayer code:
ENTER_SYNCED_CODE();
// synced operations
LEAVE_SYNCED_CODE();Use preprocessor directives for platform-specific code:
#ifdef WIN32
// Windows-specific code
#endif
#ifdef HEADLESS
// Headless build code
#endif
#if defined(__GNUC__)
// GCC-specific code
#endif- Follow
.cmakelintrcconfiguration - Use tabs for indentation in CMake files
- Keep lines reasonably short
In test/CMakeLists.txt:
set(test_name TestName)
set(test_src
"${CMAKE_CURRENT_SOURCE_DIR}/path/to/TestFile.cpp"
${test_Common_sources}
)
set(test_libs
library_name
)
add_spring_test(${test_name} "${test_src}" "${test_libs}" "${test_flags}")rts/- Main engine source coderts/System/- Core system coderts/Game/- Game logicrts/Sim/- Simulation coderts/Rendering/- Graphics renderingrts/Lua/- Lua scripting interfacerts/aGui/- GUI componentsrts/lib/- External libraries
test/- Unit teststools/- Utility toolsAI/- AI interface codecont/- Content filesdoc/- Documentation
IMPORTANT: This project has a strict AI usage policy. See AI_POLICY.md for full details.
Key requirements:
- Disclose all AI usage - State the tool used and extent of assistance
- PRs must reference accepted issues - No drive-by AI-generated PRs
- Human verification required - All AI-generated code must be tested by a human
- No AI-generated media - Only text and code allowed
- Human-in-the-loop required - Review and edit all AI-generated content
Maintainers are exempt from these rules; they use AI at their discretion.
The engine uses deterministic simulation for multiplayer. Code that affects game state must maintain sync across clients. Look for SYNCCHECK and streflop references.
The engine uses custom thread pools. See THREADPOOL define and related code.
- For Lua changes: write a test widget
- For other changes: manual testing procedure required
- Automated tests are encouraged but not always required due to complexity
- Test your changes thoroughly
- Reference an accepted issue
- Document what testing was performed
- Follow the workflow in
contributing.md - Disclose any AI assistance used
- Official website: https://recoilengine.org
- Documentation: https://recoilengine.org/docs/
- Build guide: https://recoilengine.org/development/building-without-docker/
- Discord: https://discord.gg/GUpRg6Wz3e
- GitHub issues: https://github.com/beyond-all-reason/RecoilEngine/issues