acdream/tests/AcDream.Core.Net.Tests/Messages
Erik e471527924 feat(net): wire 0xF625 ObjDescEvent for live appearance updates
Retail-driven players observed from acdream rendered with stale
appearance — wrong skin/hair palettes, missing clothing — because
ACE's mid-session appearance broadcasts (equip/unequip/tailoring/
recipe/option-toggle) ride opcode 0xF625 ObjDescEvent and acdream
silently dropped them. Initial CreateObject carries the appearance
at spawn time, but every later equip change only updates via 0xF625
(per Skunkwors protocol docs in ACE/.../GameMessageObjDescEvent.cs).
Retail handles via SmartBox::HandleObjDescEvent (named-retail 0x453340).

Why: the retail observer sees the *server-relayed* view of remotes,
not retail's local build, so dropping ObjDescEvent freezes appearance
at the partial state in the first CreateObject.

How:
- Extract CreateObject's ModelData parsing into reusable
  CreateObject.ReadModelData(span, ref pos) returning
  (BasePaletteId, SubPalettes, TextureChanges, AnimPartChanges).
- Add ObjDescEvent.cs (parser for 0xF625):
  body = u32 opcode | u32 guid | ModelData | u32 instanceSeq | u32 visualDescSeq.
- WorldSession.AppearanceUpdated event + dispatcher branch.
- GameWindow.OnLiveAppearanceUpdated splices new ModelData onto the
  cached spawn and replays via OnLiveEntitySpawned. The dedup at the
  start of OnLiveEntitySpawnedLocked tears down the old GPU/animated/
  collision state cleanly before rebuild.
- _lastSpawnByGuid cache populated at spawn-end and tracked through
  UpdatePosition so re-applies use current position (no pop-back to
  login spot on equip toggle).
- ACDREAM_DUMP_APPEARANCE=1 env var prints structured SP/TC/APC
  decode for every 0xF625 — replaces the earlier raw-hex preview.
- ACDREAM_DUMP_CLOTHING extended with setup.Parts.Count, flatten.Count,
  and per-part triangle counts for offline polygon-budget audit.

Tests: 4 new ObjDescEvent tests (round-trip + parser drift guard);
269 net tests green. User-verified live: skin/hair colors match
retail's character data; equip/unequip no longer pops position.

Note: a separate "puffy arms / bulky body" geometry issue remains
where base body parts visibly overlap clothing meshes — different
root cause, tracked separately.
2026-05-06 10:46:14 +02:00
..
AllegianceRequestsTests.cs feat(allegiance): Phase H.2 AllegianceRequests + AllegianceTree model 2026-04-18 17:17:45 +02:00
AppraiseInfoParserTests.cs feat(net): AppraiseInfoParser — ArmorProfile/CreatureProfile/WeaponProfile + enchantment bitfields 2026-04-19 10:24:35 +02:00
AppraiseTests.cs feat(items): Phase F.2 ItemRepository + AppraiseRequest round-trip 2026-04-18 16:55:36 +02:00
AutonomousPositionTests.cs fix(physics): #30 #34 L.2a movement truth diagnostics 2026-04-29 21:52:53 +02:00
CastSpellTests.cs feat(spells): Phase E.5 CastSpellRequest + Spellbook/enchantment state 2026-04-18 17:00:32 +02:00
CharacterActionsTests.cs fix(net): Phase L.1c conform combat wire events 2026-04-28 10:54:50 +02:00
CharacterEnterWorldTests.cs feat(net): acdream enters the world — CharacterList parsed + CharacterEnterWorld sent + 68 CreateObject received (Phase 4.7) 2026-04-11 15:14:31 +02:00
CharacterListTests.cs feat(net): acdream enters the world — CharacterList parsed + CharacterEnterWorld sent + 68 CreateObject received (Phase 4.7) 2026-04-11 15:14:31 +02:00
ChatTests.cs fix(chat): BuildTell wire field order + retail-style FormatEntry + suppress duplicate Channel echo 2026-04-25 20:49:02 +02:00
CombatEventTests.cs fix(net): Phase L.1c conform combat wire events 2026-04-28 10:54:50 +02:00
CreateObjectTests.cs feat(physics): live-entity collision plumbing (Commit A) 2026-04-29 13:12:56 +02:00
DeleteObjectTests.cs fix(anim): Phase L.1c route creature actions and despawns 2026-04-28 19:21:02 +02:00
EmoteTextTests.cs feat(net): #18 holtburger inbound chat parity - EmoteText, SoulEmote, ServerMessage, PlayerKilled, WeenieError + Windows-1252 codec 2026-04-25 19:06:01 +02:00
GameActionLoginCompleteTests.cs feat(net): Phase 4.8 — send GameAction.LoginComplete after EnterWorld 2026-04-11 23:36:19 +02:00
GameEventDispatcherTests.cs feat(net): Phase F.1 GameEvent (0xF7B0) envelope dispatcher 2026-04-18 16:52:46 +02:00
InteractRequestsTests.cs feat(interact): Phase B.4 Use / UseWithTarget / TeleToLifestone outbound 2026-04-18 17:18:36 +02:00
InventoryActionsTests.cs feat(net): InventoryActions — stack merge/split + give + shortcut + poi recall 2026-04-19 10:28:35 +02:00
MoveToStateTests.cs fix(physics): #30 #34 L.2a movement truth diagnostics 2026-04-29 21:52:53 +02:00
ObjDescEventTests.cs feat(net): wire 0xF625 ObjDescEvent for live appearance updates 2026-05-06 10:46:14 +02:00
PlayerKilledTests.cs feat(net): #18 holtburger inbound chat parity - EmoteText, SoulEmote, ServerMessage, PlayerKilled, WeenieError + Windows-1252 codec 2026-04-25 19:06:01 +02:00
ServerMessageTests.cs feat(net): #18 holtburger inbound chat parity - EmoteText, SoulEmote, ServerMessage, PlayerKilled, WeenieError + Windows-1252 codec 2026-04-25 19:06:01 +02:00
SetTurbineChatChannelsTests.cs feat(net+chat): #19 TurbineChat (0xF7DE) codec + ChatChannelInfo + SetTurbineChatChannels parser 2026-04-25 19:44:56 +02:00
SocialActionsTests.cs feat(net): SocialActions — query / fellowship / channel / options outbound 2026-04-19 10:26:58 +02:00
SoulEmoteTests.cs feat(net): #18 holtburger inbound chat parity - EmoteText, SoulEmote, ServerMessage, PlayerKilled, WeenieError + Windows-1252 codec 2026-04-25 19:06:01 +02:00
TurbineChatTests.cs feat(net+chat): #19 TurbineChat (0xF7DE) codec + ChatChannelInfo + SetTurbineChatChannels parser 2026-04-25 19:44:56 +02:00
UpdateMotionTests.cs fix(anim): Phase L.1c clear MoveTo state + bulk-copy ForwardCommand on overlay UMs 2026-04-29 10:02:53 +02:00
UpdatePositionTests.cs feat(net): Phase 6.7 — parse UpdatePosition (0xF748) into PositionUpdated event 2026-04-11 20:37:32 +02:00