refactor(gameserver): World is a pure lock+delegate facade (HARD GATE) #49

Merged
marco merged 1 commit from chore/world-thin-facade into main 2026-07-19 00:51:33 +02:00
Owner

Closes the HARD-GATE finding from the code review: World.cs still held inlined domain logic (PlayersWithin loop, the move ruleset in Tick, the StepCreatures switch, PlayerAt). Root cause: players lived in a raw dictionary with no registry, so player-domain logic had nowhere to go.

  • PlayerRegistry — owns the players + AoI/occupancy/snapshot/persist projections.
  • MovementSystem — the pending-move ruleset (cooldown/walkability/creature-occupancy) + GM teleport.
  • CreatureSystem — creature stepping (the AI switch + move/attack validation).
  • CorpseRegistry.SpawnFor — the per-death corpse loop; ItemRegistry.EquippedWeapon — the catalog lookup ApplyEquippedWeapon used to inline.
  • GridPosition.ChebyshevDistanceTo — the shared in-range metric (also dedups other call sites in the next batch).

World.cs now only locks and delegates — every rule is in a component; it also unblocks the spell systems cast-walk (an effective-move-cooldown the movement component can own). Behaviour unchanged: whole suite green (GameServer 113), 0 warnings, csharpier clean.

Definition of Done

  • No if/loop/formula/switch remains in a World method beyond lock+delegate (players now have a registry like creatures/items/corpses).
  • Behaviour identical — the existing World/gameplay/integration tests pass unchanged.
  • The Chebyshev metric lives once on GridPosition.
Closes the HARD-GATE finding from the code review: `World.cs` still held inlined domain logic (`PlayersWithin` loop, the move ruleset in `Tick`, the `StepCreatures` switch, `PlayerAt`). Root cause: players lived in a raw dictionary with no registry, so player-domain logic had nowhere to go. - **`PlayerRegistry`** — owns the players + AoI/occupancy/snapshot/persist projections. - **`MovementSystem`** — the pending-move ruleset (cooldown/walkability/creature-occupancy) + GM teleport. - **`CreatureSystem`** — creature stepping (the AI switch + move/attack validation). - **`CorpseRegistry.SpawnFor`** — the per-death corpse loop; **`ItemRegistry.EquippedWeapon`** — the catalog lookup `ApplyEquippedWeapon` used to inline. - **`GridPosition.ChebyshevDistanceTo`** — the shared in-range metric (also dedups other call sites in the next batch). `World.cs` now only `lock`s and delegates — every rule is in a component; it also unblocks the spell systems cast-walk (an effective-move-cooldown the movement component can own). Behaviour unchanged: whole suite green (GameServer 113), 0 warnings, csharpier clean. ## Definition of Done - [x] No `if`/loop/formula/switch remains in a `World` method beyond lock+delegate (players now have a registry like creatures/items/corpses). - [x] Behaviour identical — the existing World/gameplay/integration tests pass unchanged. - [x] The Chebyshev metric lives once on `GridPosition`.
refactor(gameserver): World is a pure lock+delegate facade (HARD GATE)
All checks were successful
ci / Lint & Test (pull_request) Successful in 1m24s
7fe700a492
Extracts the last inlined domain logic out of World.cs into focused components,
per the thin-facade invariant:
- PlayerRegistry — owns the players + the AoI/occupancy/snapshot/persist projections
  (was PlayersWithin/PlayerAt/Snapshot/PersistableSnapshot/SkillsOf inline in World).
- MovementSystem — the pending-move ruleset (cooldown/walkability/occupancy) + GM
  teleport (was the move loop inline in World.Tick).
- CreatureSystem — creature stepping (was the switch/loops of StepCreatures).
- CorpseRegistry.SpawnFor — the per-death corpse loop; ItemRegistry.EquippedWeapon —
  the catalog lookup ApplyEquippedWeapon inlined.
- GridPosition.ChebyshevDistanceTo — the shared in-range metric.

World.cs now only locks and delegates; every rule lives in a component. Behaviour
unchanged (whole suite green).
marco merged commit b8c251923a into main 2026-07-19 00:51:33 +02:00
marco deleted branch chore/world-thin-facade 2026-07-19 00:51:33 +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!49
No description provided.