Client: unify Player + creatures under one Mobile base (fixes PvP player targeting) #149

Closed
opened 2026-07-22 16:45:39 +02:00 by marco · 0 comments
Owner

Discovered by the PvP-arena design review (#109): the client cannot target another player, so PvP is currently unplayable. Click-to-attack (GameInputController) scans only world.Mobiles (creatures); players live in a separate world.Players dict, so clicking a friend does nothing. The server side is fine (CombatSystem resolves against any Mobile).

Root cause

The client diverged from the server's model: server has Mobile -> PlayerMobile + creatures (uniform); the client has two unrelated sealed class types (Player, Mobile) in two Dictionary<Guid, _>. Interaction code must remember both -> a whole class of bugs (targeting, spell-target, tile-highlight).

Fix (mirror the server)

  • Introduce a client Mobile base (id, position, facing, movement interpolation, tint) and make Player : Mobile (adds name/appearance/equipment, polymorphic Draw).
  • One ClientWorld.Mobiles (Dictionary<Guid, Mobile>); Self = Mobiles[SelfId] as Player. Ids already share the Guid space, so no collision. Corpses/items stay separate (not mobiles).
  • Ingestion stays per-DTO (PlayerState -> Player, MobileState -> Mobile) writing into the one dict. No wire change (the shared DTOs are untouched; ProtocolVersion unaffected).
  • A single MobileAt(GridPosition) / Targetables lookup used by targeting (excl. SelfId) -> players + creatures targetable.
  • Fold the renderer's WorldKind.Player vs WorldKind.Mobile split into one polymorphic draw (extend-by-type, not switch).

Definition of Done

Base DoD applies.

  • Clicking another player sets the attack target and starts a swing (server already resolves it).
  • One client-side Mobile collection; Player derives from Mobile; no Players/Mobiles duality remains.
  • Targeting/render/target-hue iterate the one collection; the render WorldKind player/creature split is gone.
  • No wire/protocol change.
Discovered by the PvP-arena design review (#109): **the client cannot target another player**, so PvP is currently unplayable. Click-to-attack (`GameInputController`) scans only `world.Mobiles` (creatures); players live in a separate `world.Players` dict, so clicking a friend does nothing. The server side is fine (`CombatSystem` resolves against any `Mobile`). ## Root cause The client diverged from the server's model: server has `Mobile` -> `PlayerMobile` + creatures (uniform); the client has two **unrelated** `sealed class` types (`Player`, `Mobile`) in two `Dictionary<Guid, _>`. Interaction code must remember both -> a whole class of bugs (targeting, spell-target, tile-highlight). ## Fix (mirror the server) - Introduce a client `Mobile` **base** (id, position, facing, movement interpolation, tint) and make `Player : Mobile` (adds name/appearance/equipment, polymorphic `Draw`). - **One** `ClientWorld.Mobiles` (`Dictionary<Guid, Mobile>`); `Self = Mobiles[SelfId] as Player`. Ids already share the `Guid` space, so no collision. Corpses/items stay separate (not mobiles). - Ingestion stays per-DTO (`PlayerState -> Player`, `MobileState -> Mobile`) writing into the one dict. **No wire change** (the shared DTOs are untouched; `ProtocolVersion` unaffected). - A single `MobileAt(GridPosition)` / `Targetables` lookup used by targeting (excl. `SelfId`) -> players + creatures targetable. - Fold the renderer's `WorldKind.Player` vs `WorldKind.Mobile` split into one polymorphic draw (extend-by-type, not switch). ## Definition of Done _Base DoD applies._ - [ ] Clicking another player sets the attack target and starts a swing (server already resolves it). - [ ] One client-side `Mobile` collection; `Player` derives from `Mobile`; no `Players`/`Mobiles` duality remains. - [ ] Targeting/render/target-hue iterate the one collection; the render `WorldKind` player/creature split is gone. - [ ] No wire/protocol change.
marco closed this issue 2026-07-22 17:09:28 +02:00
Sign in to join this conversation.
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#149
No description provided.