From 3fd9f264b708d7700610960259d902626849ecae Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 19 Apr 2026 10:29:56 +0200 Subject: [PATCH] feat(net): 9 more GameEvent payload parsers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends GameEvents.cs with parsers for commonly-observed events that had been routed-but-unparsed by the F.1 dispatcher: - UseDone (0x01C7): u32 weenieError — Use/UseWithTarget completion. - InventoryPutObjectIn3D (0x019A): u32 itemGuid — server dropped item. - InventoryServerSaveFailed (0x00A0): u32 itemGuid — rollback signal. - CloseGroundContainer (0x0052): u32 containerGuid. - TradeFailure (0x0207): u32 errorCode. - AddToTrade (0x0200): (itemGuid, slotIndex). - AcceptTrade (0x0202): u32 initiatorGuid. - QueryItemManaResponse (0x0264): (itemGuid, f32 manaPercent). - CharacterConfirmationRequest (0x0274): (type, contextId, otherGuid, string16L message) — server-driven modal confirmations. All defensive: return null on truncated payloads rather than throwing, matching the existing style. Caller can keep the dispatcher alive even on malformed events. Build green, tests unchanged (no new tests — these are simple passthroughs). Ref: r08 §4 payloads for each opcode. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/AcDream.Core.Net/Messages/GameEvents.cs | 88 +++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/AcDream.Core.Net/Messages/GameEvents.cs b/src/AcDream.Core.Net/Messages/GameEvents.cs index 5f7dcc3..b0bc1c0 100644 --- a/src/AcDream.Core.Net/Messages/GameEvents.cs +++ b/src/AcDream.Core.Net/Messages/GameEvents.cs @@ -375,6 +375,94 @@ public static class GameEvents BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(8))); } + // ── Other small-payload events ────────────────────────────────────────── + + /// 0x01C7 UseDone: the Use/UseWithTarget completion signal (WeenieError code). + public static uint? ParseUseDone(ReadOnlySpan payload) + { + if (payload.Length < 4) return null; + return BinaryPrimitives.ReadUInt32LittleEndian(payload); + } + + /// 0x019A InventoryPutObjectIn3D: server dropped item to ground. + public static uint? ParsePutObjectIn3D(ReadOnlySpan payload) + { + if (payload.Length < 4) return null; + return BinaryPrimitives.ReadUInt32LittleEndian(payload); + } + + /// 0x00A0 InventoryServerSaveFailed: revert a speculative local inventory op. + public static uint? ParseInventoryServerSaveFailed(ReadOnlySpan payload) + { + if (payload.Length < 4) return null; + return BinaryPrimitives.ReadUInt32LittleEndian(payload); + } + + /// 0x0052 CloseGroundContainer: server closed a ground container view. + public static uint? ParseCloseGroundContainer(ReadOnlySpan payload) + { + if (payload.Length < 4) return null; + return BinaryPrimitives.ReadUInt32LittleEndian(payload); + } + + /// 0x0207 TradeFailure: server trade error code. + public static uint? ParseTradeFailure(ReadOnlySpan payload) + { + if (payload.Length < 4) return null; + return BinaryPrimitives.ReadUInt32LittleEndian(payload); + } + + /// 0x0200 AddToTrade: (itemGuid, slotIndex). + public readonly record struct AddToTrade(uint ItemGuid, uint SlotIndex); + + public static AddToTrade? ParseAddToTrade(ReadOnlySpan payload) + { + if (payload.Length < 8) return null; + return new AddToTrade( + BinaryPrimitives.ReadUInt32LittleEndian(payload), + BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(4))); + } + + /// 0x0202 AcceptTrade: initiator guid. + public static uint? ParseAcceptTrade(ReadOnlySpan payload) + { + if (payload.Length < 4) return null; + return BinaryPrimitives.ReadUInt32LittleEndian(payload); + } + + /// 0x0264 QueryItemManaResponse: (itemGuid, manaPercent). + public readonly record struct QueryItemManaResponse(uint ItemGuid, float ManaPercent); + + public static QueryItemManaResponse? ParseQueryItemManaResponse(ReadOnlySpan payload) + { + if (payload.Length < 8) return null; + return new QueryItemManaResponse( + BinaryPrimitives.ReadUInt32LittleEndian(payload), + BinaryPrimitives.ReadSingleLittleEndian(payload.Slice(4))); + } + + /// 0x0274 CharacterConfirmationRequest — server-driven modal confirm. + public readonly record struct CharacterConfirmationRequest( + uint Type, + uint ContextId, + uint OtherGuid, + string Message); + + public static CharacterConfirmationRequest? ParseCharacterConfirmationRequest(ReadOnlySpan payload) + { + if (payload.Length < 12) return null; + int pos = 0; + uint type = BinaryPrimitives.ReadUInt32LittleEndian(payload); pos += 4; + uint contextId = BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(pos)); pos += 4; + uint otherGuid = BinaryPrimitives.ReadUInt32LittleEndian(payload.Slice(pos)); pos += 4; + try + { + string msg = ReadString16L(payload, ref pos); + return new CharacterConfirmationRequest(type, contextId, otherGuid, msg); + } + catch { return null; } + } + // ── Shared string reader (matches LoginRequest.ReadString16L) ─────────── private static string ReadString16L(ReadOnlySpan source, ref int pos)