Top-level GameMessage (UIQueue), not a GameEvent. Server sends after a stack merge / split to update count + value. Layout: opcode(4) + seq(1) + guid(4) + stackSize(4) + value(4) = 17 bytes. 3 tests: happy path, wrong opcode, truncated. Client consumer: ACCWeenieObject::ServerSaysSetStackSize. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
38 lines
1.4 KiB
C#
38 lines
1.4 KiB
C#
using System;
|
|
using System.Buffers.Binary;
|
|
|
|
namespace AcDream.Core.Net.Messages;
|
|
|
|
/// <summary>
|
|
/// Inbound <c>SetStackSize (0x0197)</c> — a top-level GameMessage (UIQueue group),
|
|
/// NOT a GameEvent. The server updates a stack's count + value after a merge / split.
|
|
/// Client consumer: ACCWeenieObject::ServerSaysSetStackSize.
|
|
///
|
|
/// <para>Wire layout (ACE <c>GameMessageSetStackSize.cs</c>, size hint 17):</para>
|
|
/// <code>
|
|
/// u32 opcode = 0x0197
|
|
/// u8 sequence // ByteSequence (UpdatePropertyInt) — not honored
|
|
/// u32 guid
|
|
/// i32 stackSize
|
|
/// i32 value
|
|
/// </code>
|
|
/// </summary>
|
|
public static class SetStackSize
|
|
{
|
|
public const uint Opcode = 0x0197u;
|
|
|
|
public readonly record struct Parsed(uint Guid, int StackSize, int Value);
|
|
|
|
/// <summary>Parse a raw 0x0197 body. Returns null on opcode mismatch / truncation.</summary>
|
|
public static Parsed? TryParse(ReadOnlySpan<byte> body)
|
|
{
|
|
if (body.Length < 17) return null; // 4 + 1 + 4 + 4 + 4
|
|
if (BinaryPrimitives.ReadUInt32LittleEndian(body) != Opcode) return null;
|
|
int pos = 4;
|
|
pos += 1; // sequence byte (not honored)
|
|
uint guid = BinaryPrimitives.ReadUInt32LittleEndian(body[pos..]); pos += 4;
|
|
int stack = BinaryPrimitives.ReadInt32LittleEndian(body[pos..]); pos += 4;
|
|
int value = BinaryPrimitives.ReadInt32LittleEndian(body[pos..]);
|
|
return new Parsed(guid, stack, value);
|
|
}
|
|
}
|