CI / build-test (push) Successful in 1m14s
Extend the Lighting module with a per-cell lightmap. LightmapBuilder (pure, tested) fills an ambient base, shades occluder cells, and adds point lights that attenuate with distance and are blocked by occluders between source and cell (grid-traced soft shadows). Lightmap holds the grid plus a greyscale texture (Upload) and a bilinear SampleAt for the simulation; a PointLight component places lights in the world. LightmapSystem rebuilds the grid a few times a second (ambient from the day/night cycle with a night floor, occluders from a game-supplied grid, point lights from the ECS); LightmapRenderSystem multiplies the lightmap over the world after the sprite flush and under the HUD. Wired via scene.UseLighting(...), sampled through Lighting.SampleAt. Docs updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
131 lines
7.8 KiB
Markdown
131 lines
7.8 KiB
Markdown
# mrgameeng
|
||
|
||
2D game engine built on MonoGame 3.8.4 (DesktopGL), .NET 8, C#.
|
||
ECS-first: Friflo.Engine.ECS 3.6 is tightly integrated into the core — all gameplay
|
||
state lives in components, all logic in systems.
|
||
|
||
Design docs and developer documentation live in `docs/` and are written in **Russian**.
|
||
Keep them up to date when architecture or conventions change.
|
||
|
||
## Solution layout
|
||
|
||
```
|
||
src/ MrGameEng.* engine libraries (grouped by role, not one-per-feature)
|
||
tests/ xUnit test projects, one per engine library
|
||
tools/ CLI tools (atlas packer)
|
||
docs/ architecture, conventions, roadmap (Russian)
|
||
```
|
||
|
||
Libraries are grouped by architectural role rather than split per feature, to avoid a
|
||
sprawl of two-file projects. A feature lives in a subfolder of its host library and
|
||
keeps its own `MrGameEng.<Feature>` namespace (namespaces are independent of the
|
||
assembly), so `using MrGameEng.Tilemaps;` etc. still resolve after a merge.
|
||
|
||
The engine has no sample project: the **LittleSim** game
|
||
(https://gitea.hsrv.site/mrleo1nid/LittleSim, this repo as the `engine/` submodule)
|
||
is the living showcase — new engine features are demonstrated there.
|
||
|
||
Engine libraries (each feature is a namespaced subfolder of its host):
|
||
|
||
- **`Core`** — game loop, ECS world, scenes, time (`GameClock` with `TimeScale`; `GameSpeed`
|
||
for discrete pause/1×/3×/6× speed control over the clock, `context.UseGameSpeed(...)`;
|
||
`Calendar` turning scaled time into in-game days, `context.UseCalendar(secondsPerDay)`;
|
||
`Climate` — continuous seasonal/daily temperature and season over the calendar,
|
||
`context.UseClimate(settings)`),
|
||
plus **Input** (`MrGameEng.Input`: `InputManager`, `ActionMap`, `InputSystem`, in
|
||
`Core/Input/`). Depends only on MonoGame and Friflo.Engine.ECS.
|
||
- **`Graphics`** — custom batched renderer, camera, sprites, plus **Tilemaps**
|
||
(`MrGameEng.Tilemaps`: code-built tile grids rendered through the batcher,
|
||
`scene.UseTilemaps()` after `UseRenderer2D()`, in `Graphics/Tilemaps/`) and **Lighting**
|
||
(`MrGameEng.Lighting`, `Graphics/Lighting/`: day/night ambient over the `Calendar` driving
|
||
`Renderer2D.AmbientLight` on world layers, `scene.UseDayNight(renderer)`; plus a per-cell
|
||
**lightmap** — `LightmapBuilder` (ambient × occlusion + point lights with grid-traced shadows),
|
||
`PointLight` component, multiplied over the world via `scene.UseLighting(...)`, sampleable with
|
||
`Lighting.SampleAt` for the simulation). → `Core`.
|
||
- **`Audio`** — ogg playback (NVorbis); `AudioManager` with `SoundVolume`/`MasterVolume`
|
||
(one knob for effects + music). → `Core`.
|
||
- **`Content`** — the asset/content pipeline: **Assets** (`MrGameEng.Assets`: runtime
|
||
loading, no MGCB pipeline; FontStash), **Atlases** (`MrGameEng.Atlases`: texture-atlas
|
||
builder + runtime loader, CLI wrapper in `tools/MrGameEng.AtlasTool`; StbImage), and
|
||
**Mods** (`MrGameEng.Mods`: mod discovery + load order from `About/About.json`, JSON
|
||
`Defs/` with parent inheritance and later-mod override, `Languages/<code>/`
|
||
localization, merged texture content trees; the game ships its content as the `Core`
|
||
mod). → `Core`, `Graphics` (Atlases needs `Texture2DRegion`).
|
||
- **`Simulation`** — deterministic gameplay primitives that own no world data:
|
||
**Pathfinding** (`MrGameEng.Pathfinding`: grid A*/Dijkstra/BFS and flow fields over a
|
||
game-implemented `IPathGrid`), **AI** (`MrGameEng.AI`: utility-AI primitives —
|
||
`ResponseCurve`, `Consideration<TContext>`, `UtilityAction<TContext>`,
|
||
`UtilityAi<TContext>` selector, `Blackboard`; generic over a game context), and
|
||
**Collisions** (`MrGameEng.Collisions`: `Collider` component, spatial hash rebuilt per
|
||
tick, pairs/queries/raycast, `scene.UseCollisions()` after movement systems).
|
||
→ `Core`, `Graphics` (Collisions needs `Transform2D`, `RectF`).
|
||
- **`UI`** — Myra integration (`scene.UseUI()` after `UseRenderer2D()`),
|
||
**DevConsole** (`MrGameEng.DevConsole`: in-game console capturing `Core.Log`,
|
||
`scene.UseDevConsole()` last in OnLoad) and **Inspector** (`MrGameEng.Inspector`: a
|
||
Chrome-DevTools-style ECS debugger overlay — entity tree by archetype, component/field
|
||
view with simple-field editing, world-pick with selection highlight, renderer perf tab;
|
||
`scene.UseInspector(renderer)`, toggle F1). → `Core`, `Graphics` (the inspector picks
|
||
entities and reads renderer timings; Myra renders with its own SpriteBatch internally).
|
||
- **`Assets.Generator`** — Roslyn source generator for typed asset handles; standalone
|
||
netstandard2.0 analyzer.
|
||
|
||
Dependency rule: a library may depend only on `Core` and `Graphics`; `Core` depends only
|
||
on MonoGame and Friflo.Engine.ECS. Features grouped into one library share its package
|
||
set (e.g. `Content` carries both FontStash and StbImage) — keep optional/heavy deps
|
||
(Myra, NVorbis) in their own library so the rest of the engine stays free of them.
|
||
|
||
## Commands
|
||
|
||
```
|
||
dotnet build MrGameEng.sln
|
||
dotnet test MrGameEng.sln
|
||
```
|
||
|
||
Building requires the .NET 10+ SDK (Roslyn 5.3 packages used by the asset-handles
|
||
generator do not load under the SDK 8 compiler); the target framework stays net8.0.
|
||
|
||
## Architecture rules
|
||
|
||
- ECS-first: components are plain data (`struct` implementing `IComponent`),
|
||
behavior goes into Friflo systems (`QuerySystem`), wired through `SystemRoot`.
|
||
No `Update()` methods on game objects, no inheritance-based entities.
|
||
- Hot paths (per-frame systems) must be allocation-free below the renderer's parallel
|
||
threshold; above it Parallel.For scheduler overhead is the accepted trade.
|
||
A Friflo chunk holds a whole archetype — parallelize by slicing chunks into segments,
|
||
never by chunk alone. Measure in Release only, using the Renderer2D phase timings.
|
||
- Rendering: custom batcher in `Graphics` (vertex buffers, layer→depth→texture sort,
|
||
atlas support); `SpriteBatch` is not used in engine code. Draw systems write vertices
|
||
directly from Friflo chunk iteration. Orthographic camera (one active per scene),
|
||
registered render layers (World or Screen space, optional Y-sort), AABB culling
|
||
against the camera rect before vertices are written.
|
||
- No MGCB content pipeline. Assets are raw files under `Assets/`, loaded at runtime
|
||
(textures via `Texture2D.FromFile`, fonts via FontStashSharp, ogg via NVorbis,
|
||
shaders precompiled by `dotnet-mgfxc` at build time). Game code references assets
|
||
only through generated typed handles (`AssetRef<T>`), never string paths.
|
||
- New engine functionality goes into the host library for its role (a namespaced
|
||
subfolder, e.g. a new render feature under `Graphics/`), not a fresh project. Add a
|
||
new `MrGameEng.<Area>` library only when the area is a genuinely new role or needs an
|
||
isolated heavy/optional dependency — never into `Core` by default, never a
|
||
two-file project per feature.
|
||
- Every public engine feature must be covered by tests where logic is testable
|
||
without a GPU, and demonstrated in the LittleSim game (the engine's showcase).
|
||
|
||
## Code conventions
|
||
|
||
- Nullable reference types enabled, warnings as errors, file-scoped namespaces.
|
||
- Public engine API requires XML doc comments (English).
|
||
- Tests: xUnit, named `Method_Scenario_Expectation`.
|
||
- Formatting: all C# code is formatted with **CSharpier**. Match its output —
|
||
run `csharpier format .` (or let the editor's format-on-save handle it) before
|
||
committing; never hand-format against it.
|
||
|
||
## Memory (echovault MCP)
|
||
|
||
- At session start, call `memory_context` to load prior decisions for this project;
|
||
call `memory_search` before working on a topic that may have prior context
|
||
(e.g. "renderer", "transitions", "generator").
|
||
- Before ending a session where you decided, fixed or learned something, save it with
|
||
`memory_save`: decisions (X over Y + why), bug root causes, non-obvious gotchas
|
||
(e.g. Friflo/Myra API traps). Write for a future agent with zero context.
|
||
- Don't save what the repo already records (code, docs/, git history) or trivia.
|