feat: worn equipment visible on other players — layered anim + paperdoll (#18) #132

Merged
marco merged 1 commit from feat/worn-gear-on-others into main 2026-07-22 10:48:57 +02:00
Owner

ok
Summary

Other players now show what they're wearing — the "layered paperdoll" from #18 — built directly
on the appearance-state foundation from #112.

  • Worn gear is reconciled appearance state. PlayerAppearance now carries Equipment (layer +
    kind); PlayerJoined carries it (a player entering your AoI shows their gear immediately) and
    PlayerAppearanceChanged reconciles equip/unequip within AoI. The item domain pushes the
    worn-gear projection onto the wearer instance on equip/unequip/restore (act on the instance)
    and marks the appearance dirty; World.Equip/Unequip stay thin delegates. Protocol bumped to 8.
  • Client draws each equipped piece over the character in lockstep — same action/facing/frame,
    correct draw order — so a sword and platemail render together, consistent across all 8
    facings, and both show on the paperdoll. (Server unchanged for the render; the client keys off
    the appearance.)
  • Equip-art extraction (#16 groundwork). A worn item animates as the wearer's body-anim at the
    item's tiledata AnimID (broadsword 0x026A, platemail 0x020F), packed as
    equip/<kind>/<action>_<dir>. New extractor tooling: findart (find an art id by name from
    tiledata.mul — the authoritative way to locate an AnimID) and animdump (eyeball a body's
    frames). Documented in docs/asset-extraction.md.

Note: the armor's backpack icon is still a placeholder (no item_armor static extracted yet) —
its world equip anim and paperdoll gump are the real UO art. This PR does not close
the broader #16 (all equip art); it lays the pipeline + the first two pieces.

Closes #18.

Screenshots / recording

Captured via the debug harness (docs/debug-harness.md) from a fresh DB, login debug,
/give sword + /give armor, equipped one of each by double-clicking them in the backpack, then
goto-ing around to face each direction:

Paperdoll (both worn) World — east World — south-east
paperdoll east south-east

The world sprite shows the platemail body + the held sword together; both stay correct as the
character turns (mirrored facings included).

How it was tested

  • just test — all green (190 GameServer incl. a new Equipping_SurfacesWornGear_InTheTickAppearance
    test, 72 Client.Core, 54 Shared, 17 AssetExtractor, 12 Auth, 4 Assets).
  • just lint — build succeeds, 0 warnings.
  • Repacked assets.isoa from ~/Games/UO (classic .mul); confirmed equip/sword + equip/armor
    present.
  • Piloted the client (fresh DB) for the screenshots above.

Checklist

  • just lint passes (CSharpier + analyzers, zero warnings)
  • just test is green
  • The whole solution builds (client and tools included)
  • Multi-platform preserved (server on Win/macOS/Linux, client on Win/macOS)
  • Tests added/updated for this change (server-side appearance reconcile of equip/unequip)
  • Linked the related issue (#18) and its Definition of Done is met (equip/unequip is visible on other players' sprites — real art — across all 8 facings, and on the paperdoll)
ok Summary Other players now show what they're wearing — the "layered paperdoll" from #18 — built directly on the appearance-state foundation from #112. - **Worn gear is reconciled appearance state.** `PlayerAppearance` now carries `Equipment` (layer + kind); `PlayerJoined` carries it (a player entering your AoI shows their gear immediately) and `PlayerAppearanceChanged` reconciles equip/unequip within AoI. The **item domain** pushes the worn-gear projection onto the wearer *instance* on equip/unequip/restore (act on the instance) and marks the appearance dirty; `World.Equip/Unequip` stay thin delegates. Protocol bumped to **8**. - **Client draws each equipped piece over the character in lockstep** — same action/facing/frame, correct draw order — so a sword **and** platemail render together, consistent across all 8 facings, and both show on the paperdoll. (Server unchanged for the render; the client keys off the appearance.) - **Equip-art extraction (#16 groundwork).** A worn item animates as the wearer's body-anim at the item's tiledata `AnimID` (broadsword `0x026A`, platemail `0x020F`), packed as `equip/<kind>/<action>_<dir>`. New extractor tooling: **`findart`** (find an art id by name from `tiledata.mul` — the authoritative way to locate an AnimID) and **`animdump`** (eyeball a body's frames). Documented in `docs/asset-extraction.md`. Note: the armor's *backpack icon* is still a placeholder (no `item_armor` static extracted yet) — its **world equip anim** and **paperdoll gump** are the real UO art. This PR does **not** close the broader #16 (all equip art); it lays the pipeline + the first two pieces. Closes #18. ## Screenshots / recording Captured via the debug harness (`docs/debug-harness.md`) from a **fresh DB**, `login debug`, `/give sword` + `/give armor`, equipped one of each by double-clicking them in the backpack, then `goto`-ing around to face each direction: | Paperdoll (both worn) | World — east | World — south-east | | --- | --- | --- | | ![paperdoll](https://git.homelab.devncode.it/attachments/5540f157-3019-425c-8093-f962b1c1db3b) | ![east](https://git.homelab.devncode.it/attachments/3afd26cd-87a2-4552-a26d-dd2daa7ca49e) | ![south-east](https://git.homelab.devncode.it/attachments/954adfcf-1a17-4d28-9e81-5fac2a46e152) | The world sprite shows the platemail body + the held sword together; both stay correct as the character turns (mirrored facings included). ## How it was tested - `just test` — all green (**190 GameServer** incl. a new `Equipping_SurfacesWornGear_InTheTickAppearance` test, 72 Client.Core, 54 Shared, 17 AssetExtractor, 12 Auth, 4 Assets). - `just lint` — build succeeds, **0 warnings**. - Repacked `assets.isoa` from `~/Games/UO` (classic `.mul`); confirmed `equip/sword` + `equip/armor` present. - Piloted the client (fresh DB) for the screenshots above. ## 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 (server on Win/macOS/Linux, client on Win/macOS) - [x] Tests added/updated for this change (server-side appearance reconcile of equip/unequip) - [x] Linked the related issue (#18) and its Definition of Done is met (equip/unequip is visible on other players' sprites — real art — across all 8 facings, and on the paperdoll)
feat: worn equipment visible on other players — layered anim + paperdoll (#18, #16)
All checks were successful
ci / Lint & Test (pull_request) Successful in 1m28s
563915a82e
Worn gear an observer sees is now part of the reconciled appearance state (built on
#112): PlayerAppearance carries Equipment (layer + kind), PlayerJoined carries it,
and PlayerAppearanceChanged reconciles equip/unequip within AoI. The item domain
pushes the worn-gear projection onto the wearer instance on equip/unequip/restore
(act on the instance) and marks the appearance dirty; World stays a thin delegate.
Protocol bumped to 8.

The client draws each equipped kind's animation over the character in lockstep
(same action/facing/frame, correct draw order) — a sword and platemail render
together, consistent across all 8 facings, and both show on the paperdoll.

Extractor (#16): equip animations are the wearer's body-anim layout at the item's
tiledata AnimID (sword 0x026A, platemail 0x020F), packed as equip/<kind>/<action>_<dir>.
Adds the tiledata reader + `findart` (locate art by name — the authoritative way to
find an AnimID) and `animdump` (eyeball a body's frames). Documented in
docs/asset-extraction.md.
marco merged commit 9f63ce6155 into main 2026-07-22 10:48:57 +02:00
marco deleted branch feat/worn-gear-on-others 2026-07-22 10:48:58 +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!132
No description provided.