Mirror of PublicUpdatePropertyInt (0x02CE) but with no guid field — targets the local player's own object. Burden (EncumbranceVal, PropertyInt 5) changes ride this opcode on every pick-up / drop. Layout: opcode(4) + seq(1) + property(4) + value(4) = 13 bytes. 3 tests: happy path, wrong opcode, truncated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
38 lines
1.5 KiB
C#
38 lines
1.5 KiB
C#
using System;
|
|
using System.Buffers.Binary;
|
|
|
|
namespace AcDream.Core.Net.Messages;
|
|
|
|
/// <summary>
|
|
/// Inbound <c>PrivateUpdatePropertyInt (0x02CD)</c> — the server updates one
|
|
/// <c>PropertyInt</c> on the player's OWN object. Unlike the sibling
|
|
/// <see cref="PublicUpdatePropertyInt"/> (0x02CE), this carries NO guid (it
|
|
/// implicitly targets the local player). Burden (<c>EncumbranceVal</c>, PropertyInt 5)
|
|
/// changes ride this opcode on every pick-up / drop.
|
|
///
|
|
/// <para>Wire layout (ACE <c>GameMessagePrivateUpdatePropertyInt</c>):</para>
|
|
/// <code>
|
|
/// u32 opcode = 0x02CD
|
|
/// u8 sequence // single byte (ByteSequence) — not honored, latest-wins (DR-4)
|
|
/// u32 property // PropertyInt enum
|
|
/// i32 value
|
|
/// </code>
|
|
/// </summary>
|
|
public static class PrivateUpdatePropertyInt
|
|
{
|
|
public const uint Opcode = 0x02CDu;
|
|
|
|
public readonly record struct Parsed(uint Property, int Value);
|
|
|
|
/// <summary>Parse a raw 0x02CD body. Returns null on opcode mismatch / truncation.</summary>
|
|
public static Parsed? TryParse(ReadOnlySpan<byte> body)
|
|
{
|
|
if (body.Length < 13) return null; // 4 + 1 + 4 + 4
|
|
if (BinaryPrimitives.ReadUInt32LittleEndian(body) != Opcode) return null;
|
|
int pos = 4;
|
|
pos += 1; // sequence byte (not honored)
|
|
uint prop = BinaryPrimitives.ReadUInt32LittleEndian(body[pos..]); pos += 4;
|
|
int value = BinaryPrimitives.ReadInt32LittleEndian(body[pos..]);
|
|
return new Parsed(prop, value);
|
|
}
|
|
}
|