From e7b6e83cf82043edb1afe6442200fd26b94b00ea Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 17 Jun 2026 18:33:18 +0200 Subject: [PATCH] feat(D.5.2): thread UiEffects through EntitySpawn + route 0x02CE PublicUpdatePropertyInt - EntitySpawn record: add UiEffects = 0 field (after IconUnderlayId) - EntitySpawn construction site: thread parsed.Value.UiEffects as the new tail arg - WorldSession: declare ObjectIntPropertyUpdate payload record + ObjectIntPropertyUpdated event (after StateUpdated) - Message loop: add else-if branch for PublicUpdatePropertyInt.Opcode (0x02CE), parses + fires ObjectIntPropertyUpdated Co-Authored-By: Claude Opus 4.8 (1M context) --- src/AcDream.Core.Net/WorldSession.cs | 29 ++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/AcDream.Core.Net/WorldSession.cs b/src/AcDream.Core.Net/WorldSession.cs index d263f0e7..db21014d 100644 --- a/src/AcDream.Core.Net/WorldSession.cs +++ b/src/AcDream.Core.Net/WorldSession.cs @@ -88,7 +88,10 @@ public sealed class WorldSession : IDisposable // (0x40000000) and WeenieHeaderFlag2.IconUnderlay (0x01) respectively. // Zero when the server did not send the field (common for most entities). uint IconOverlayId = 0, - uint IconUnderlayId = 0); + uint IconUnderlayId = 0, + // D.5.2 (2026-06-17): UiEffects bitfield (weenieFlags 0x80) — drives the icon's + // effect recolor. CreateObject-only; 0 = no effect. + uint UiEffects = 0); /// Fires when the session finishes parsing a CreateObject. public event Action? EntitySpawned; @@ -161,6 +164,20 @@ public sealed class WorldSession : IDisposable /// public event Action? StateUpdated; + /// + /// Payload for : a single PropertyInt change on + /// a visible object (from PublicUpdatePropertyInt 0x02CE). Subscribers map the + /// property to typed state (e.g. UiEffects → the item's icon effect). + /// + public readonly record struct ObjectIntPropertyUpdate(uint Guid, uint Property, int Value); + + /// + /// Fires when the session parses a PublicUpdatePropertyInt (0x02CE) — one + /// PropertyInt updated on a visible object. D.5.2 routes UiEffects (18) to the + /// item repository so the icon re-composites live. + /// + public event Action? ObjectIntPropertyUpdated; + /// /// Fires when the server sends a PlayerTeleport (0xF751) game message, /// signalling that the player is entering portal space. The uint payload @@ -727,7 +744,8 @@ public sealed class WorldSession : IDisposable parsed.Value.UseRadius, parsed.Value.IconId, parsed.Value.IconOverlayId, - parsed.Value.IconUnderlayId)); + parsed.Value.IconUnderlayId, + parsed.Value.UiEffects)); } } else if (op == DeleteObject.Opcode) @@ -901,6 +919,13 @@ public sealed class WorldSession : IDisposable if (parsed is not null) VitalCurrentUpdated?.Invoke(parsed.Value); } + else if (op == PublicUpdatePropertyInt.Opcode) + { + var p = PublicUpdatePropertyInt.TryParse(body); + if (p is not null) + ObjectIntPropertyUpdated?.Invoke( + new ObjectIntPropertyUpdate(p.Value.Guid, p.Value.Property, p.Value.Value)); + } else if (op == GameEventEnvelope.Opcode) { // Phase F.1: 0xF7B0 is the GameEvent envelope. Parse the