# World2 Game Project - Agent Guide ## Project Overview World2 is a 3D life simulation game built using the OGRE3D rendering engine. The project features an Entity-Component-System (ECS) architecture powered by Flecs, with Jolt Physics for simulation, Lua scripting for story content, and ImGui for user interfaces. ## Technology Stack ### Core Dependencies - **Rendering**: OGRE3D 14.x+ (Object-Oriented Graphics Rendering Engine) - **ECS Framework**: Flecs (Fast Lightweight Entity Component System) - **Physics**: Jolt Physics with double precision support (JPH_DOUBLE_PRECISION) - **Scripting**: Lua 5.4 with LPEG library - **Audio**: miniaudio (single-header audio library) - **UI**: ImGui (integrated via Ogre::ImGuiOverlay) - **Model Loading**: Assimp with pugixml - **Navigation**: Recast/Detour for crowd simulation - **Procedural Generation**: OgreProcedural - **Profiling**: Tracy frame profiler ### Build Requirements - CMake 3.13+ - C++17 compatible compiler - Blender (for asset processing, path configurable via `BLENDER` CMake variable) - OGRE SDK with components: Bites, Paging, Terrain, MeshLodGenerator ## Project Structure ``` / ├── CMakeLists.txt # Main build configuration ├── resources.cfg # OGRE resource locations ├── .clang-format # Linux kernel code style config │ ├── Game.cpp # Main game executable entry point (legacy) ├── Editor.cpp # World editor executable (legacy) ├── Procedural.cpp # Procedural generation test / character controller demo (legacy) ├── Bootstrap.cpp # Legacy character controller demo (legacy) ├── terrain.cpp # Terrain system test executable (legacy) │ ├── src/ # Source code │ ├── gamedata/ # Core ECS modules and game logic (legacy) │ │ ├── GameData.cpp/h # ECS world setup and management (legacy) │ │ ├── Components.h # ECS component definitions (legacy) │ │ ├── *Module.cpp/h # Individual ECS modules (legacy) │ │ └── items/ # Game item implementations (harbour, temple, town, etc.) (legacy) │ ├── lua/ # Lua integration │ │ ├── lua-5.4.8/ # Lua source code │ │ └── lpeg-1.1.0/ # LPEG parsing library │ ├── physics/ # Jolt Physics wrapper (physics.h/cpp) (legacy - for buildiung legacy code only) │ ├── sound/ # Audio system (miniaudio) │ ├── crowd/ # Recast/Detour navigation │ │ ├── include/ # Crowd headers (OgreRecast, OgreDetourCrowd, etc.) │ │ └── src/ # Crowd implementations │ ├── editor/ # Editor-specific code (legacy) │ │ ├── EditorGizmoModule.h/cpp │ │ ├── EditorInputModule.h/cpp │ │ └── main.cpp │ ├── features/ # Feature modules │ │ ├── characters/ # Character rendering test │ │ ├── editScene/ # Scene editor with ECS, it has game mode and all features, current work is here │ │ └── sceneEditor/ # some other editor code │ ├── world/ # World generation and GOAP AI (legacy) │ ├── terrain/ # Terrain system (legacy) │ ├── tests/ # Test utilities │ ├── text_editor/ # ImGui text editor component │ ├── miniaudio/ # Audio library │ ├── sceneloader/ # Scene loading utilitie (legacy) │ ├── aitoolkit/ # AI utilities (GOAP, FSM, Behavior Trees) (legacy) │ └── vehicles/ # Vehicle definitions (legacy) │ ├── assets/ # Source assets (Blender files) │ ├── blender/ # Blender source files │ │ ├── buildings/ # Building models (.blend) │ │ ├── characters/ # Character models and clothes (characters asset pipeline) │ │ ├── vehicles/ # Vehicle models │ │ ├── scripts/ # Blender Python scripts for export │ │ └── world/ # World terrain models │ ├── textures/ # Source textures │ └── fonts/ # Game fonts │ ├── lua-scripts/ # Lua game scripts │ ├── narrator/ # Ink narrative parser │ ├── stories/ # Story scripts (.ink format, compiled to .lua) │ └── json/ # JSON library for Lua │ ├── water/ # Water rendering system (legacy) │ ├── water.h/cpp # Water class │ ├── *.frag, *.vert # GLSL shaders │ └── water.compositor # OGRE compositor script │ ├── skybox/ # Sky rendering resources ├── resources/ # Runtime resources (build output) ├── audio/ # Audio resources ├── morph/ # Character morphing data └── build/ # build directory └── build-vscode/ # VSCode build directory ``` ## Critical Constraints & Rules - The source code is the only source of truth. Please check code as documentation might be out of sync. - Do not modify legacy code. Current code is at src/features/editScene and its dependencies. - Please ask questions if anything is unclear. - Please update tests, documentation and examples every time API or modules and systems change. ## Build Instructions ### Prerequisites 1. Install OGRE3D SDK with Bites, Paging, Terrain, MeshLodGenerator components 2. Install dependencies: Jolt Physics, Flecs, Assimp, pugixml, OgreProcedural, Tracy, SDL2, ZLIB 3. Set `CMAKE_PREFIX_PATH` to OGRE installation 4. Configure Blender path in CMake (default: `${CMAKE_SOURCE_DIR}/../../blender-bin/bin/blender`) ### Build Commands ```bash # Configure (adjust paths as needed) cmake -B build -S . -DCMAKE_PREFIX_PATH=/path/to/ogre-sdk # Build all targets cmake --build build # Build specific targets cmake --build build --target Game # Main game executable (legacy) cmake --build build --target Editor # World editor (legacy) cmake --build build --target Procedural # Procedural test (legacy) cmake --build build --target TerrainTest # Terrain test (legacy) cmake --build build --target TerrainTest # Terrain test (legacy) cmake --build build --target editSceneEditor # Current executable for scene editor and game cmake --build build --target demoLuaSceneScript # Demo: game-mode inline scene/prefab Lua scripts cmake --build build --target demoSceneSwitchingExtra # Demo: scene switching with CellGrid interior cmake --build build --target demoSokoban # Demo: forklift sokoban activity (vehicle + crates + quest HUD) cmake --build build --target demoTaxi # Demo: taxi driver (procedural town, sedans, NPC traffic, fare chain) ``` ### Build Outputs - `build/Game` - Main game executable (legacy) - `build/Editor` - World editor executable (legacy) - `build/Procedural` - Procedural generation test (legacy) - `build/TerrainTest` - Terrain system test (legacy) - `build//src/features/editScene/editSceneEditor` - current executable - `build//src/features/editScene/demos/demo-lua-scene-script/demoLuaSceneScript` - SceneScriptComponent demo (game mode, inline Lua); self-contained runtime staged in the same directory - `build//src/features/editScene/demos/demo-scene-switching-extra/demoSceneSwitchingExtra` - Scene-switching demo with a CellGrid interior (own-entity ProceduralMaterial/ProceduralTexture); self-contained runtime staged in the same directory - `build//src/features/editScene/demos/demo-interior-exterior-dynamics/demoInteriorExteriorDynamics` - Same scene-switching demo, but the exterior scene has a streaming terrain (baseNoise archipelago - a large island at the content site amid an ocean with more islands) + sky + water instead of the flat floor; self-contained runtime staged in the same directory - `build//src/features/editScene/demos/demo-sokoban/demoSokoban` - Forklift sokoban activity demo (drivable Jolt VehicleConstraint forklift, pushable crates, target pads, completion HUD); based on demo-interior-exterior-dynamics, see demos/demo-sokoban/PLAN.md; self-contained runtime staged in the same directory - `build//src/features/editScene/demos/demo-taxi/demoTaxi` - Taxi driver demo (procedurally generated town, drivable sedans, passenger/foot-traffic/vehicle-traffic NPCs, chained timed fares with doubling payout); based on demo-interior-exterior-dynamics with vehicle ideas from demo-sokoban, see demos/demo-taxi/PLAN.md; self-contained runtime staged in the same directory - `build/resources/` - Staged game resources - `build/characters/` - Processed character models - `build/water/` - Water assets (legacy) ## Code Style Guidelines This project follows the **Linux Kernel Coding Style** for C++: ### Formatting Rules - **Indentation**: 8-character tabs (UseTab: Always) - **Line Length**: 80 characters maximum - **Braces**: - Functions: Opening brace on new line - Control structures: Opening brace on same line - **Pointer Alignment**: Right (`int *ptr` not `int* ptr`) - **Namespaces**: No indentation inside namespaces ### Example ```cpp void myFunction(int arg) { if (arg > 0) { doSomething(); return; } for (int i = 0; i < arg; i++) { process(i); } } ``` ### Running clang-format ```bash clang-format -i src/gamedata/*.cpp src/gamedata/*.h ``` ## Architecture ### ECS (Entity Component System) The game uses Flecs for ECS architecture. Core systems: #### Components (src/gamedata/Components.h) (legacy) - `GameData` - Global game state - `EngineData` - Engine configuration (SceneManager, delta time, debug draw) - `Input` - Input state (keyboard, mouse, controls) - `Camera` - Camera node and configuration - `RenderWindow` - Window and DPI information - `CollisionShape` - Physics shape references - `EditorSceneSwitch` - Editor scene switching - `GameState` - Game running state #### Modules (src/gamedata/*Module.h) (legacy) Modules are ECS systems organized by functionality: | Module | Purpose | |--------|---------| | AppModule | Application context management | | GUIModule | ImGui interface management | | EditorGUIModule | Editor UI | | PhysicsModule | Jolt physics integration | | CharacterModule | Character spawning and management | | CharacterManagerModule | Player/NPC character management | | CharacterAnimationModule | Animation state machines | | CharacterAIModule | AI behavior (GOAP-based) | | TerrainModule | Terrain generation and rendering | | WaterModule | Water surface and physics | | SunModule | Day/night cycle and lighting | | WorldMapModule | World map overlay | | QuestModule | Quest system | | EventModule | Game event handling | | EventTriggerModule | Event triggers | | SlotsModule | Inventory slot management | | BoatModule | Boat physics and control | | VehicleManagerModule | Vehicle management | | PlayerActionModule | Player action handling | | LuaModule | Lua scripting integration | | StaticGeometryModule | Static geometry management | ### EditScene Modules (`src/features/editScene`) The editor/game mode executable adds its own ECS components. The editor/game mode executable adds its own ECS modules: | Module | Purpose | |--------|---------| | CharacterSlotSystem | Catalog-driven multi-slot character mesh builder | | CharacterSpawnerSystem | Distance-based spawn/despawn of registry characters | | TerrainPrefabSpawnerSystem | Distance-based terrain prefab spawn/despawn, terrain snap and compliance flattening | | PlayerControllerSystem | Player input, camera, locomotion and animation state | | ActuatorSystem | Player interaction prompts and smart-object/item actions | | DoorSystem | Swing animation and collider toggle for CellGrid door entities | | EditorUISystem | ImGui property panels and scene management | | ProceduralTextureSystem | Runtime procedural texture generation | | ProceduralMaterialSystem | Runtime procedural material creation | | AnimationTreeRegistry | Global named animation tree definitions | | AnimationTreeSystem | Runtime evaluation of registry-referenced animation trees | | SceneScriptSystem | Execute-once scene/prefab Lua scripts (SceneScriptComponent) and scene_loaded/prefab_loaded events | | VehicleSystem | Jolt VehicleConstraint vehicles (VehicleComponent): chassis constraint lifetime, driver input, wheel visual nodes | #### PlayerControllerSystem `PlayerControllerSystem` reads the shared `GameInputState`, drives the TPS/FPS camera and sets the locomotion animation state (`idle`/`walking`/`running` and the swim equivalents) on the controlled entity. In game mode it adds the `PlayerControlledComponent` tag to the target so AI systems know to leave it alone. When a controller's `targetCharacterName` points at an entity with `CharacterSpawnerComponent`, the system locks the spawner and forces an immediate spawn; the actual controlled entity is the spawned character instance, not the spawner. The TPS camera boom is collision-clamped via a physics raycast from the pivot to the desired camera position (instant pull-in, eased recovery), and the character geometry is hidden when the clamped camera gets too close to the body — see `src/features/editScene/AGENTS.md` for details. #### Player Character Resolution Systems that need the live player character (inventory UI, character sheet, save/load, actuators) must not resolve the controller's `targetCharacterName` against `EntityNameComponent` directly – that returns the spawner entity when the controller targets a spawner. Instead use: ```cpp flecs::entity player = editorApp->getPlayerCharacterEntity(); ``` `EditorApp::getPlayerCharacterEntity()` returns the controller's current target, spawning the character through `CharacterSpawnerSystem` if necessary. `CharacterSpawnerSystem::getSpawnerForCharacter()` can be used in save/load to keep the controller pointed at the spawner rather than the transient instance. #### Game Mode Input Game mode movement keys (`W`, `A`, `S`, `D`, left/right `Shift`) are handled inside `keyPressed`/`keyReleased` by `keysym.sym`. Repeated `KEYDOWN` events (`evt.repeat != 0`) are ignored for movement keys, because releasing `Shift` while `W`/`A`/`S`/`D` is held can generate a repeated keydown with a different symbol after the physical release, which would otherwise leave the key stuck. One-shot actions (`E`, `F`, `I`, `Space`) are also matched by `keysym.sym`, and their `*Pressed` edges ignore repeats too — otherwise holding `E` (e.g. the hold-E-to-exit a vehicle) re-fires the door actuators and re-enters. #### CharacterSpawnerComponent - `registryId` - Character registry ID to spawn. - `spawnDistanceSq` - Squared distance to camera at which the character spawns (default 100²). - `despawnDistanceSq` - Squared distance to camera at which the character despawns (default 200²). The spawner uses the entity's `TransformComponent` for spawn position/rotation. When the spawner itself moves/rotates/scales in the editor, the spawned character is updated to match; when the spawner is stationary, the character is left alone so it can move on its own. Spawned characters are created without `EditorMarkerComponent` and removed from the editor UI cache so they remain visible but are not selectable/editable in the editor. Registry changes that bump the character version trigger an immediate respawn. Scene serialization stores plain `spawnDistance`/`despawnDistance` values for readability while the component keeps squared values for comparisons. #### AnimationTreeComponent - `treeName` - Name of the animation tree in `AnimationTreeRegistry`. - `enabled` - Whether the tree is evaluated. - `useRootMotion` - Whether root motion from the animation drives the character's linear velocity. The actual tree definition (node hierarchy, state machines, animations) lives in the `AnimationTreeRegistry`, persisted to `animation_tree.json`. Trees are authored in the registry editor (**Tools -> Animation Tree Registry**), where each entry can also select a skeleton source from the `Characters` resource group (one representative mesh per skeleton) to populate animation-name dropdowns. Old scenes and prefabs that stored the tree inline or referenced an `AnimationTreeTemplate` are migrated automatically on load. #### Road Region Streaming (M5) When the terrain has `streamingEnabled`, `RoadSystem` persists the road graph per terrain page in `heightmaps//roads/_.json` (managed by `RoadRegionStore`) instead of inline in the scene JSON — `SceneSerializer::serializeTerrain` then skips `roadNodes`/`roadEdges` and keeps only `roadConfig`. Region files store absolute world-space doubles; a cross-page edge is written to the region file of each endpoint page with the foreign endpoint repeated inline. On the first sync a non-empty inline graph is migrated to region files automatically. Merges match nodes by world XZ (0.01 eps) so reloaded pages never duplicate nodes; `EditorUISystem::saveScene` calls `RoadSystem::flushRegionStore()` before writing the scene. Page mesh rebuilds are gated by a rebase-invariant FNV-1a content signature (world positions quantized to cm), so a render-origin rebase shifts node render positions without re-dirtying pages; navmesh dirtying is debounced (~15 quiet frames) while streaming. #### Terrain Streaming Architecture The terrain can span up to 40,000,000 x 40,000,000 units (`TerrainComponent::worldSizeUnits`, default; 20000 x 20000 pages at the default 2000-unit page size, clamped to 32768 per axis for TerrainGroup's signed 16-bit slot packing). Streaming is opt-in per terrain via `TerrainComponent::streamingEnabled`. **Coordinate spaces.** Three spaces coexist (see `TerrainSystem.hpp` "Coordinate spaces"): - **WORLD** space — absolute double-precision coordinates; authoritative. `TransformComponent::worldX/Y/Z`, region files, bookmarks and the Navigation panel all use it. - **RENDER** space — floats relative to the floating render origin: `render = world - renderOrigin`. Scene nodes, mouse rays and the editor camera live here. `RenderOriginSystem` (singleton, `RenderOriginSystem::getInstance()`) owns the origin and rebases when the camera moves further than `REBASE_THRESHOLD` (8192 render units) from it: the origin snaps to integer world coordinates near the camera and every render-space position shifts by the exact negated delta. Convert with `RenderOriginSystem::worldToRender(x,y,z)` / `renderToWorld(Ogre::Vector3)`. - **PHYSICS** space — Jolt `DVec3`/`RVec3` in absolute world coordinates via `physics/physics.h`; terrain colliders live here, so `TerrainSystem::raycastTerrain` converts its render-space ray to world space for the collider query. `TerrainSystem` additionally exposes `renderToWorldX/Y/Z`, `worldToRender`, and `visualToPhysicalX/Z` / `physicalToVisualX/Z` for the physical heightmap space (physical X shifted by half a page, physical Z mirrored within each page). **Page streaming window.** With `streamingEnabled`, pages are not defined up front; `TerrainSystem::updateStreamingWindow()` loads a square window of `pageLoadRadius` pages around the camera page each frame (2 loads/frame cap) and unloads pages beyond `pageHoldRadius` (4 unloads/frame cap), all synchronously to avoid WorkQueue shutdown hangs. Base heights come from procedural `TerrainComponent::baseNoise` (FastNoiseLite, double precision) instead of the legacy heightmap buffer; `setHeightAt` writes through the LRU-capped fixup chunk layer. Pages are indexed in PHYSICAL page coords `[0, N-1]`; the Ogre TerrainGroup slot for physical page `(x, y)` is `(x, -y)` because `ALIGN_X_Z` negates Z. The world is bounded — page indices and teleports clamp to `[0, N-1]`. **Region storage.** Per-page data lives under `heightmaps//`: painted blend maps, aux maps, fixup chunks, plus the streamed content stores `spawners/_.json` (prefab spawner defs, see below) and `roads/_.json` (road graph, see "Road Region Streaming (M5)" above). **Editor navigation tools (M3).** `EditorCamera` supports mouse-wheel zoom (`handleMouseWheel`), Shift boost (x10) and a configurable fly speed (`setFlySpeed`, 1..100000 units/s). **Tools -> Navigation** opens `NavigationPanel` (teleport by world X/Y/Z or by page index, clamped to world bounds; named world bookmarks stored in the scene JSON top-level `bookmarks` array, tolerated when missing on load). **Tools -> World Map** opens `WorldMapPanel` (ImGui canvas over `WorldMapData`: coarse heights, loaded pages, roads, spawners, bookmarks and camera overlays; drag pan, wheel zoom, double-click teleport). `TerrainEditor` also has a compact "Navigation" section sharing the same static teleport backend. **Streamed vs always-loaded spawners (M4).** Scene-embedded `TerrainPrefabSpawnerComponent` entities behave as always-loaded spawners for small/non-streaming scenes. When the terrain streams, spawner definitions persist per page in `heightmaps//spawners/_.json` (via `SpawnerRegionStore`); `TerrainPrefabSpawnerSystem::syncStreamedSpawners()` polls `TerrainGroup::getTerrainSlots()` and creates a region spawner entity (tagged `StreamedSpawnerTag{pageX,pageY,defId}`, excluded from scene JSON) when a page loads, destroying it and writing edits back (including page-boundary crossings) when it unloads. The editor "prefab spawn mode" click-to-place writes to the region store when streaming. ### Physics System Uses Jolt Physics with custom wrapper (legacy - `src/physics/physics.h`, current - `src/features/editScene/physics/physics.h`): ```cpp // Example: Creating a physics body JoltPhysicsWrapper *physics = new JoltPhysicsWrapper(scnMgr, cameraNode); JPH::ShapeRefC shape = physics->createBoxShape(Ogre::Vector3(1, 1, 1)); JPH::BodyID body = physics->createBody(shape, 1.0f, position, rotation, JPH::EMotionType::Dynamic, Layers::MOVING); ``` ### Rendering Pipeline 1. **Main Render**: Standard OGRE render with RTSS (Real Time Shader System) 2. **Water**: Reflection/refraction with custom shaders 3. **Sky**: Dynamic skybox with day/night cycle 4. **Shadows**: Configurable shadow techniques ### Asset Pipeline 1. **Source**: Blender `.blend` files in `assets/` 2. **Export**: Python scripts in `assets/blender/scripts/` - `export_buildings.py` - Building export to glTF - `export_characters_ogre.py` - Character export to OGRE format - `export_vehicles.py` - Vehicle export (car modeling contract: `assets/blender/vehicles/CAR_MODELING.md`) - `gen_sokoban_assets.py` - One-shot generator for the demo-sokoban `forklift`/`crate`/`pad` .blend files (blender2ogre names .mesh files after mesh *data* names — set both object and data names) - `gen_taxi_assets.py` - Generator for the demo-taxi `sedan-a` / `sedan-taxi` .blend files (body + hinge-local door/hood/trunk parts, shared wheel meshes; body colors baked as material variants) - `gen_vehicle.py` - Convention-based vehicle pipeline for hand-modeled cars (`sedan-v2.blend` is the reference): classifies parts by name (`* Tire`, `* Door`, `* hood`/`* trunk`, `* Steering`, `seat_*` empties), normalizes wheel/steering axes, unpacks texture atlases, and emits a ready-to-merge `.vehicle.json` scene entity (contract: `assets/blender/vehicles/CAR_MODELING.md`) - `import_vrm.py` - VRM character import 3. **Build**: CMake processes assets during build 4. **Runtime**: Assets loaded from `resources.cfg` paths ## Key Conventions ### Module Registration Modules register themselves with Flecs using the `FLECS_CPP_NO_AUTO_REGISTRATION` macro: ```cpp // In module header struct MyModule { MyModule(flecs::world &ecs); }; // In module implementation MyModule::MyModule(flecs::world &ecs) { // Register systems, components, etc. } ``` ### Scene Setup Scenes are configured through ECS setup functions: ```cpp // Setup exterior game scene ECS::setupExteriorScene(scnMgr, cameraNode, camera, renderWindow); // Setup interior scene ECS::setupInteriorScene(scnMgr, cameraNode, camera, renderWindow); // Setup editor ECS::setupEditor(scnMgr, cameraNode, camera, renderWindow); ``` ### Lua Scripting Story content is written in Ink format and parsed to Lua: - Source: `lua-scripts/stories/*.ink` - Compiled: `lua-scripts/stories/*.lua` - Runtime: Narrator parser loads and executes stories ## Development Workflow ### Adding Assets 1. Create/modify `.blend` file in `assets/blender/` 2. Add export logic to relevant Python script if needed 3. Add CMake custom command in `CMakeLists.txt` if new asset type 4. Rebuild to process assets ### Debugging - Use `ECS::EngineData.enableDbgDraw` for physics debug visualization - Tracy profiler integration for performance analysis - FPS and draw call stats printed to console ## Security Considerations - Lua scripts run in sandboxed environment - File system access restricted to resource directories - No network functionality currently implemented ## Additional Resources - **OGRE3D Docs**: https://ogrecave.github.io/ogre/api/latest/ - **Flecs Manual**: https://www.flecs.dev/flecs/ - **Jolt Physics**: https://jrouwe.github.io/JoltPhysics/ - **Ink Narrative**: https://www.inklestudios.com/ink/