Files
mrgameeng/CLAUDE.md
T
Leonid PershinandClaude Opus 4.8 79d406a9f4
CI / build-test (push) Successful in 1m14s
Add 2D lightmap: occlusion shadows and point lights
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>
2026-06-12 18:40:17 +03:00

7.8 KiB
Raw Blame History

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 lightmapLightmapBuilder (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.