feat: map editor — paint terrain + statics on the iso grid (#113) #147

Merged
marco merged 4 commits from feat/map-editor into main 2026-07-22 16:18:32 +02:00
Owner

Summary

A minimal, cross-platform map editor (#113) — paint terrain + statics on the iso grid instead of hand-editing text — built on the #89 static layer and the #143 tiledata/IMapFormat seam.

  • Engine-agnostic core (tools/IsoMmo.MapEditor.Core, refs Shared only, unit-tested): MapModel (mutable grid + statics + spawn, edits validated against TileData, ToTileMap/FromTileMap) + Brush (N×N square, rectangle, flood-fill). 14 tests.
  • The exe (tools/IsoMmo.MapEditor, MonoGame DesktopGL + MonoGame.ImGuiNet): reuses the game's GridRenderer/Camera2D/IsoProjection so the canvas is WYSIWYG with the client. All UI is off-the-shelf ImGui (owner's call: internal tool, zero bespoke UI). Pan (right-drag / WASD / arrows), zoom (wheel), tool = Terrain/Static/Erase/Spawn, brush = Single (+size) / Rect / Fill, palette auto-populated from TileData, red blocking indicator, yellow spawn marker, path + Open/Save.
  • Load/save go solely through IMapFormat (WriteMap/ReadMap, round-trip tested in #143) — the editor never parses the format itself. The palette is data-driven for free: it lists the terrains/statics from tiledata.txt, so anything paintable is loadable, and a new kind is one tiledata row + art (no code).
  • Adds a default-1.0 Camera2D.Zoom (backward-compatible; the game never sets it) and an internal TileMap.Create factory (editor builds a renderable/saveable map from its model without exposing the grid or duplicating format logic — InternalsVisibleTo the editor core).
  • just map-editor, docs/map-editor.md, and a small tools/IsoMmo.MapEditor/CLAUDE.md with the editor's agent guardrails.

Notes / decisions

  • Resurrection markers are out of scope — they shipped (#129) as GM-placed Ankh world items (world.sav), not map content; set in-game via /place ankh.
  • Map size = the grid's shape (no size field); expanding a map = a bigger grid, no code (runtime is size-agnostic).
  • MonoGame.ImGuiNet 1.0.5 ships its dll at the package root (no lib/); referenced portably via GeneratePathProperty + the generated package-path property, so it restores on any machine/OS.
  • Follow-up #146 (publish the editor as a release artifact) filed separately.

Screenshots / recording

Captured headlessly via the editor's --screenshot hook (loads world.map, renders, writes the PNG, exits). The Tools window (tool/brush/palette/path), the File menu, the iso canvas rendering the world map with biome bands + trees from the static layer, red blocking indicators on solid statics, and the yellow spawn marker (24,18):

map editor

Command: dotnet run --project tools/IsoMmo.MapEditor -- --screenshot mapeditor.png.

How it was tested

  • New unit tests (IsoMmo.MapEditor.Core.Tests, 14): MapModel (fill, set terrain/static, clear, spawn bounds, unknown-id rejection, snapshot isolation, FromTileMap round-trip) + Brush (square size 1/3, rectangle any-order inclusive, flood-fill stops at different terrain / out-of-bounds empty).
  • just lint (CSharpier + analyzers, zero warnings) and just test (421 tests) green; whole solution builds incl. client + tools.
  • Ran the editor from a fresh build (screenshot above): it renders the map WYSIWYG, the ImGui chrome works, blocking/spawn overlays draw; save/load is exercised by the round-trip tests + MapModel/IMapFormat coverage.

Checklist

  • just lint passes (CSharpier + analyzers, zero warnings)
  • just test is green
  • The whole solution builds (client and tools included)
  • Multi-platform preserved (MonoGame DesktopGL Win/macOS/Linux; portable package reference)
  • Tests added/updated for this change
  • Linked the related issue (#113) and its Definition of Done is met

Release artifact (now included)

.forgejo/workflows/release.yaml now publishes the map editor as a self-contained artifact (isommo-map-editor-<tag>-{win-x64,osx-arm64}.zip) alongside the client/servers/asset-editor, with the pack + tiledata + maps bundled so it runs standalone. Verified locally: dotnet publish --self-contained bundles the ImGuiNet dll + native libcimgui, and the published build runs and screenshots headlessly. Closes #146.

Closes #113.

## Summary A minimal, cross-platform **map editor** (#113) — paint terrain + statics on the iso grid instead of hand-editing text — built on the #89 static layer and the #143 `tiledata`/`IMapFormat` seam. - **Engine-agnostic core** (`tools/IsoMmo.MapEditor.Core`, refs Shared only, unit-tested): `MapModel` (mutable grid + statics + spawn, edits validated against `TileData`, `ToTileMap`/`FromTileMap`) + `Brush` (N×N square, rectangle, flood-fill). **14 tests.** - **The exe** (`tools/IsoMmo.MapEditor`, MonoGame DesktopGL + `MonoGame.ImGuiNet`): reuses the game's `GridRenderer`/`Camera2D`/`IsoProjection` so the canvas is **WYSIWYG with the client**. All UI is off-the-shelf ImGui (owner's call: internal tool, zero bespoke UI). Pan (right-drag / **WASD** / arrows), zoom (wheel), tool = Terrain/Static/Erase/Spawn, brush = Single (+size) / Rect / Fill, palette **auto-populated from `TileData`**, red **blocking indicator**, yellow **spawn** marker, path + Open/Save. - **Load/save go solely through `IMapFormat`** (`WriteMap`/`ReadMap`, round-trip tested in #143) — the editor never parses the format itself. The palette is **data-driven for free**: it lists the terrains/statics from `tiledata.txt`, so anything paintable is loadable, and a new kind is one tiledata row + art (no code). - Adds a default-`1.0` `Camera2D.Zoom` (backward-compatible; the game never sets it) and an internal `TileMap.Create` factory (editor builds a renderable/saveable map from its model without exposing the grid or duplicating format logic — `InternalsVisibleTo` the editor core). - `just map-editor`, `docs/map-editor.md`, and a small `tools/IsoMmo.MapEditor/CLAUDE.md` with the editor's agent guardrails. ### Notes / decisions - **Resurrection markers are out of scope** — they shipped (#129) as GM-placed `Ankh` world items (`world.sav`), not map content; set in-game via `/place ankh`. - **Map size = the grid's shape** (no size field); expanding a map = a bigger grid, no code (runtime is size-agnostic). - `MonoGame.ImGuiNet` 1.0.5 ships its dll at the package root (no `lib/`); referenced portably via `GeneratePathProperty` + the generated package-path property, so it restores on any machine/OS. - Follow-up **#146** (publish the editor as a release artifact) filed separately. ## Screenshots / recording Captured headlessly via the editor's `--screenshot` hook (loads `world.map`, renders, writes the PNG, exits). The Tools window (tool/brush/palette/path), the File menu, the iso canvas rendering the world map with biome bands + trees from the static layer, **red blocking indicators** on solid statics, and the **yellow spawn marker** (24,18): ![map editor](https://git.homelab.devncode.it/attachments/7ffaa25a-c18c-4d39-9387-b0f025fac7dd) Command: `dotnet run --project tools/IsoMmo.MapEditor -- --screenshot mapeditor.png`. ## How it was tested - **New unit tests** (`IsoMmo.MapEditor.Core.Tests`, 14): `MapModel` (fill, set terrain/static, clear, spawn bounds, unknown-id rejection, snapshot isolation, `FromTileMap` round-trip) + `Brush` (square size 1/3, rectangle any-order inclusive, flood-fill stops at different terrain / out-of-bounds empty). - `just lint` (CSharpier + analyzers, **zero warnings**) and `just test` (**421 tests**) green; whole solution builds incl. client + tools. - Ran the editor from a fresh build (screenshot above): it renders the map WYSIWYG, the ImGui chrome works, blocking/spawn overlays draw; save/load is exercised by the round-trip tests + `MapModel`/`IMapFormat` coverage. ## Checklist - [x] `just lint` passes (CSharpier + analyzers, zero warnings) - [x] `just test` is green - [x] The whole solution builds (client and tools included) - [x] Multi-platform preserved (MonoGame DesktopGL Win/macOS/Linux; portable package reference) - [x] Tests added/updated for this change - [x] Linked the related issue (#113) and its Definition of Done is met ### Release artifact (now included) `.forgejo/workflows/release.yaml` now publishes the map editor as a self-contained artifact (`isommo-map-editor-<tag>-{win-x64,osx-arm64}.zip`) alongside the client/servers/asset-editor, with the pack + tiledata + maps bundled so it runs standalone. Verified locally: `dotnet publish --self-contained` bundles the ImGuiNet dll + native `libcimgui`, and the published build runs and screenshots headlessly. **Closes #146.** Closes #113.
ci(release): publish the map editor as a release artifact (win + macOS)
All checks were successful
ci / Lint & Test (pull_request) Successful in 2m12s
0b5ce9996e
marco merged commit 552b97e9b6 into main 2026-07-22 16:18:32 +02:00
marco deleted branch feat/map-editor 2026-07-22 16:18:32 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
marco/IsoMmo!147
No description provided.