Chained Decos is the game project built on top of Chained Engine, a modular C++23 engine with editor tooling, runtime packaging, ECS architecture, physics, and managed gameplay scripting.
Note
Active development is ongoing. Features and workflows continue to evolve, but this README is maintained to reflect the current repository state.
- Overview
- Developer Resources (Deep Dives)
- Editor and Simulation Workflow
- Engine Feature Highlights
- Architecture
- Working with Projects
- Project Structure
- Dependencies
- Prerequisites
- Quick Start
- Build
- Run
- Gameplay Scripting (C#)
- Assets and Resources
- Physics and Collisions
- In-Game UI
- Extending the Engine (C++)
- Debugging and Profiling
- Testing
- CI/CD
- Troubleshooting
- Known Issues
- Contributing
- License
Chained Decos and Chained Engine currently target Windows and Linux.
Main capabilities:
- OpenGL 4.3+ rendering pipeline with system-specific asset loader registration.
- ECS-driven scene model using EnTT.
- YAML-based project and scene serialization with deep configuration support.
- Editor workflow with hierarchy/inspector/panels and in-editor play mode.
- Flexible bootstrapping via
ProjectLauncherfor Headless, Runtime, and Editor modes. - Managed C# gameplay scripting through Coral (.NET/CoreCLR host).
For a more detailed look at specific engine systems, please refer to the following guides:
- Engine Architecture: Bootstrapping, system initialization (SRP), and the main loop.
- Component Reference: Complete list of available ECS components and their roles.
- Scripting API Guide: Detailed reference for managed C# development.
The editor is the main authoring environment for scene creation, iteration, and play-mode testing.
Important
Simulation controls:
- Press PLAY to enter simulation and capture cursor.
- Press Escape to leave simulation control and return to editor interaction.
Warning
ChainedRuntime is a dedicated wrapper executable for loading and running your project data without the full editor UI.
- High-performance OpenGL renderer with custom shader workflows.
- EnTT-based ECS architecture for scalable scene/entity management.
- Managed C# gameplay scripting through Coral and CoreCLR.
- BVH-assisted collision and physics systems for gameplay diagnostics.
- YAML scene/project serialization with UUID-centered identity tracking.
- Editor undo/redo command history for common content workflows.
- Asset loading pipeline with dedup-oriented task handling.
- Virtual file system support is currently planned/in-progress.
Chained Engine follows a layered architecture with a Hazel-inspired service/singleton baseline, adapted for this project's engine/editor/runtime split.
Core layers:
- Engine Core: Rendering, scene, physics, audio, assets, platform abstractions.
- Bootstrapping:
ProjectLauncherutility that handles headless/runtime/editor initialization using a data-driven approach. - Editor: Content workflows, scene inspection/manipulation, panel-based tooling.
- Runtime: Lightweight executable that loads and runs a project based on its
.chprojectmetadata. - Scripting Bridge: C++/C# interop through Coral.Native and managed assemblies.
The game selection itself is build-time, not runtime: CH_ACTIVE_GAME chooses which game folder is added to the build graph, while the .chproject file decides what the runtime opens.
The engine supports multiple game projects inside the same repository. Right now, there are two:
chaineddecos: the main parkour game.testproject: a lightweight sandbox project to test features safely.
To keep compile times fast, only one game project is generated in the build graph at a time. This is controlled by the CH_ACTIVE_GAME CMake variable.
How to switch:
- Command Line: Run CMake with
-DCH_ACTIVE_GAME=....cmake -S . -B build/windows-ninja -DCH_ACTIVE_GAME=testproject - VS Code: Open the Command Palette (
Ctrl+Shift+P), chooseCMake: Edit CMake Cache (UI), findCH_ACTIVE_GAME, change it, and save.
After changing the game, just rebuild the project. The executable name and assets will automatically switch to the new game.
Want to start a new game from scratch? Here is how to hook it up:
- Create the folder structure: Make a new directory
game/mygame. - Add a CMake script: Create
game/mygame/CMakeLists.txtand use the engine's helper macro:chained_add_game(MyGameTarget PROJECT_GAME mygame CSHARP_PROJECT "scripts/MyGame.Scripts.csproj" # Omit if you don't use C# yet )
- Add the entry point: Create
game/mygame/src/main.cpp. The engine uses a modularProjectLauncherto bootstrap the application:#include "engine/core/application.h" #include "engine/core/entry_point.h" #include "engine/core/project_launcher.h" namespace CHEngine { Application* CreateApplication(ApplicationCommandLineArgs args) { // Prepare runtime specifications from project data auto details = ProjectLauncher::PrepareRuntime(args); return new Application(details.Spec); } }
- Register it: Open the root
CMakeLists.txt, find theif(CH_ACTIVE_GAME STREQUAL "...")block, and add your new game to the list.
- engine/: core engine modules (graphics, scene, physics, audio, platform, assets).
- editor/: ChainedEditor application and editor panels/tools.
- runtime/: ChainedRuntime application and runtime layer.
- scripting/: script host, glue bindings, and managed build integration.
- game/chaineddecos/: main game project, gameplay scripts under src/, and managed scripts/tests under scripts/.
- game/testproject/: alternate standalone game project used for project switching and smaller experiments.
- tests/: native C++ test target (EngineTests).
- include/: third-party dependencies as git submodules.
This repository relies on git submodules for core third-party libraries (for example EnTT, Assimp, Coral, ImGui, GLFW, GLM, yaml-cpp, GoogleTest, and others under include/).
Always initialize/update submodules before configuring CMake:
git submodule update --init --recursive| Tool | Version | Notes |
|---|---|---|
| CMake | 3.31+ | Required by top-level CMake configuration. |
| Compiler | C++23 | GCC 14+, Clang 18+, or MSYS2/MinGW-w64 GCC and Clang on Windows. |
| Ninja | Latest | Recommended for fast parallel builds. |
| .NET SDK | 9.0.x | Required for managed scripting/test workflows. |
| Graphics Driver | OpenGL 4.3+ | Needed for editor/runtime rendering. |
Linux packages used by CI (Ubuntu reference):
sudo apt-get update
sudo apt-get install -y build-essential cmake ninja-build \
libgl1-mesa-dev libx11-dev libxrandr-dev libxinerama-dev \
libxcursor-dev libxi-dev libasound2-dev libglu1-mesa-dev \
pkg-config libgtk-3-dev libdrm-dev libgbm-dev \
xvfb libxkbcommon-x11-0 libgl1-mesa-dri mesa-utils- Clone with submodules:
git clone --recurse-submodules https://github.com/IOleg-crypto/Chained-Decos.git
cd Chained-Decos
git submodule update --init --recursive- Configure (examples):
# Linux (Ninja)
cmake --preset linux-clang
# Windows (MSYS2 GCC)
cmake --preset windows-gcc
# Windows (MSYS2 Clang)
cmake --preset windows-clang- Build:
# Ninja presets
cmake --build --preset linux-clang --parallel
cmake --build --preset windows-gcc --parallel
cmake --build --preset windows-clang --parallel- Run editor:
# Linux
./build/linux-clang/bin/ChainedEditor
# Windows
.\build\windows-gcc\bin\ChainedEditor.exeCMake presets defined in CMakePresets.json:
- linux-gcc
- linux-clang
- windows-gcc
- windows-clang
Notes:
- BUILD_TESTS defaults to ON in presets.
- If you switch presets or major toolchains, do a clean configure for that build directory.
CH_ACTIVE_GAMEdefaults tochaineddecosin CMakePresets.json. Set it totestprojectwhen you want the alternate game.- Optional compiler cache support is built in through ccache/sccache integration in CI and CMake options.
- If you use Clang on Windows and see Intellisense errors in VS Code, ensure that
.vscode/settings.jsonpoints to the correct build directory forclangd:"clangd.arguments": [ "--compile-commands-dir=${workspaceFolder}/build/windows-ninja" ]
Binary outputs are generated under build/{preset}/bin.
Editor:
# Linux
./build/linux-clang/bin/ChainedEditor
# Windows
.\build\windows-gcc\bin\ChainedEditor.exeRuntime:
# Positional project path
./build/linux-clang/bin/ChainedRuntime path/to/project.chproject
# Or explicit flag form
./build/linux-clang/bin/ChainedRuntime --project path/to/project.chproject
./build/linux-clang/bin/ChainedRuntime --project path/to/project.chproject --name "My Runtime" --width 1600 --height 900
# Windows example
.\build\windows-gcc\bin\ChainedRuntime.exe --project path\to\project.chproject --name "My Runtime" --width 1600 --height 900Runtime CLI flags currently supported:
- --project or -p
- --name
- --width
- --height
When you build the alternate game project, the executable name changes with the active target. The runtime still discovers the .chproject file from the executable/project directory.
Editor play-mode note:
- Enter Play mode to capture cursor.
- Press Escape to return control to editor interaction.
Chained Engine uses managed C# for gameplay, powered by Coral (.NET/CoreCLR). This means you write your game logic in C# while the heavy lifting (rendering, physics) stays in C++.
Scripts live inside your game's source folder (e.g., game/chaineddecos/src). Here is a practical example of a basic script:
using System;
using CHEngine;
namespace ChainedDecos
{
public class PlayerController : Script
{
public float Speed = 5.0f;
private TransformComponent _transform;
protected override void OnCreate()
{
// Called once when the Entity is initialized
_transform = GetComponent<TransformComponent>();
Log.Info("Player Controller initialized!");
}
protected override void OnUpdate(float deltaTime)
{
// Called every frame
if (Input.IsKeyDown(KeyCode.W))
{
Vector3 pos = _transform.Translation;
pos.Z -= Speed * deltaTime;
_transform.Translation = pos;
}
}
}
}Once you've written your magical gameplay code, how does the engine know about it?
- Build the scripts: Either rebuild the project through CMake/Ninja, or navigate to your
.csprojfolder and rundotnet build. - Open the Editor and select the Entity you want to control.
- Add Component: In the Inspector panel, click Add Component and choose Managed Script Component.
- Link it: In the
Class Nametext field, type the fully qualified name of your script — namespace included (for example:ChainedDecos.PlayerController). - Play: Hit the Play button in the editor. The engine will instantly instantiate your C# class and execute your lifecycle methods!
If you are modifying the engine itself, you will find the native-to-managed bridge here:
- Native Host: scripting/scriptengine.h initializes Coral and loads assemblies.
- Interops: Native C++ calls are exposed to C# via
script_glue.cpp. - Discovery: At startup,
ScriptTypeRegistry::Discover()scans the game DLL for classes deriving fromCHEngine.Script. - Lifecycle:
SceneScriptinginstantiates your script in C++, calls__Init()to cache delegates, and smoothly passes events from the C++ Scene to C#.
- scripting/managed/src/Script.cs defines the script lifecycle base class.
- scripting/managed/src/Entity.cs exposes entity/component access.
- scripting/managed/src/SceneAndApplication.cs exposes scene, audio, application, time, and window helpers.
- scripting/managed/src/Input.cs wraps input queries.
- scripting/managed/src/Log.cs wraps logging.
- scripting/managed/src/Math.cs provides vector and scalar helpers.
- scripting/managed/src/UI.cs exposes minimal UI helpers.
Managed artifacts are built as part of the scripting target when dotnet is available.
All of your 3D models, textures, animations, and sound files must go into your game's assets/ or resources/ folder. The engine uses a unified Asset Manager to register files and assign a UUID to them so they are not loaded multiple times.
- Importing: Drag and drop your source file (e.g.,
.gltfmodel,.pngtexture) directly into the Content Browser Panel in the Editor. The system registers it. - Usage: Select the Entity in your scene, find the relevant Component (like
MeshComponent), and assign the newly loaded asset from the browser.
Chained Engine uses a built-in 3D physics simulation, which is heavily used by parkour traversal scripts in chaineddecos.
To add physical behavior to an Entity in the Editor:
- Click Add Component and select RigidBodyComponent. This determines if the object falls (Dynamic) or stays still (Kinematic/Static).
- Add a physical shape like a BoxColliderComponent or SphereColliderComponent.
If you are writing a C# script (inherited from CHEngine.Script), you can hook into these collisions directly:
protected override void OnCollisionEnter(Entity other)
{
Log.Info($"Hit something: {other.Name}");
if (other.HasComponent<DamageZone>())
{
// Example: Handle player taking damage
}
}While the Editor UI is drawn using ImGui, the gameplay (In-Game) UI meant for players is accessed through the managed scripting wrapper.
To draw simple HUDs or text menus:
- Override the
OnGUImethod in your C# script. - Call static helpers from the
UIclass.
protected override void OnGUI()
{
// Draw some simple text on screen
UI.DrawText("Stamina: 100", new Vector2(10.0f, 10.0f), Color.White);
// Render a button and check if clicked
if (UI.DrawButton("Restart Parkour", new Vector2(100.0f, 200.0f)))
{
// Restart logic here
}
}Need performance that scripting can't provide, or want to create a brand new foundational Component? Here is the flow for a native ECS update:
- Define the Data: Add a fast
structinengine/scene/components.h. We useEnTT, so components are simple structs.struct ParkourStateComponent { float Stamina = 100.0f; bool IsWallRunning = false; };
- Support Serialization: If you want editors to save or load it with the level, update
scene_serializer.cpporyaml_extensionsso YAML knows how to read/write it. - Expose It to the Editor: Open
editor/editor_panels.cppand add theImGuidraw logic forParkourStateComponent. - Register Loaders (if needed): If your component needs a custom asset type, register its loader in the appropriate system (e.g.,
Renderer::Init()for graphics assets) to maintain Single Responsibility Principle compliance.
If Chained Decos ever suffers a frame-rate drop (a lag spike), do not optimize blindly. Use the tools:
- Built-in Editor Profiler: Open the Profiler panel. It displays a breakdown (in
ms) of where your frame time went —Rendering,Physics Update, orScripting Update. Check this first. - C# Debugging with CoreCLR: Because the engine wraps .NET via Coral, you can attach a C# IDE debugger (like Visual Studio or Rider) to the running Engine/Editor process. Your breakpoints inside
OnUpdateorOnCreatewill pause the simulation.
There are two test layers.
Native tests (GoogleTest + CTest):
# Build native test target
cmake --build --preset windows-gcc --target EngineTests --parallel
# Windows Clang variant
cmake --build --preset windows-clang --target EngineTests --parallel
# Linux variant
cmake --build --preset linux-clang --target EngineTests --parallel
# Run native tests
ctest --test-dir build/windows-gcc --output-on-failure
# Windows Clang variant
ctest --test-dir build/windows-clang --output-on-failure
# Linux variant
ctest --test-dir build/linux-clang --output-on-failureManaged gameplay tests (xUnit):
dotnet restore ./game/chaineddecos/scripts/tests/ChainedDecos.Scripts.Tests.csproj
dotnet test ./game/chaineddecos/scripts/tests/ChainedDecos.Scripts.Tests.csproj -c Release --no-restoreCI workflow (.github/workflows/ci.yml):
- Dispatches native builds to
.github/workflows/linux.ymland.github/workflows/windows.yml. - Dispatches managed tests to
.github/workflows/managed.yml. - Runs CTest for native tests.
- Runs managed script tests with .NET 9.0.x.
- Uses software rendering setup for Linux test execution (xvfb + Mesa environment variables).
Deploy workflow (.github/workflows/deploy-sdk.yml):
- Triggered by v* tags or manual dispatch.
- Runs managed tests.
- Builds and packages ChainedEditor and ChainedRuntime artifacts for Linux/Windows.
Submodule errors during configure/build:
git submodule update --init --recursiveGenerator switch conflicts:
- If reusing a build directory with another generator family, reconfigure from a clean build folder for that preset.
Managed build not available:
- Ensure dotnet SDK 9.0.x is installed and available in PATH.
Headless Linux test issues:
- Install the Linux packages listed in Prerequisites.
- Use xvfb and Mesa software rendering for CI-like environments.
Changing CH_ACTIVE_GAME without reconfiguring the build tree can leave stale generated files behind. Reconfigure the same build directory when you switch between chaineddecos and testproject.
- Some native test areas are currently being reworked and may be skipped or gated in CI depending on environment constraints.
- Runtime and editor workflows are under active iteration.
- Virtual file system support is planned/in-progress and should not be treated as fully delivered yet.
Contributions are welcome.
- Open issues for bugs/regressions.
- Submit pull requests for fixes and improvements.
- Platform/build workflow improvements are especially helpful.
- Keep documentation changes in this README or in nearby code comments when the detail is local.
This project is licensed under MIT. See license for details.



