acdream/src/AcDream.Core.Net/Messages/DeleteObject.cs
Erik 8a5d77f7f4 feat(net): port retail physics spawn and event timestamps
Parse the complete PhysicsDesc plus F754/F755 packets, correct every PhysicsState bit, and gate all nine retail update channels with generation-safe immutable snapshots. Preserve ForcePosition, teleport, placement, velocity, parent, pickup, delete, and same-generation CreateObject ordering from the named client.

Separate accepted logical lifecycle notifications from retained UI qualities, make GUID replacement and session reset clear every projection exactly once, and add packet, wraparound, malformed-input, parent FIFO, canonical-position, reconnect, and GUID-reuse conformance coverage.

Co-Authored-By: Codex <noreply@openai.com>
2026-07-14 00:22:17 +02:00

42 lines
1.5 KiB
C#

using System.Buffers.Binary;
namespace AcDream.Core.Net.Messages;
/// <summary>
/// Inbound <c>ObjectDelete</c> GameMessage (opcode <c>0xF747</c>).
///
/// <para>
/// Retail dispatch path:
/// <c>CM_Physics::DispatchSB_DeleteObject</c> 0x006AC6A0 reads guid from
/// <c>buf+4</c> and instance sequence from <c>buf+8</c>, then calls
/// <c>SmartBox::HandleDeleteObject</c> 0x00451EA0. ACE emits the same
/// layout from <c>GameMessageDeleteObject</c>.
/// </para>
/// </summary>
public static class DeleteObject
{
public const uint Opcode = 0xF747u;
/// <summary>A true object-destruction event for one exact incarnation.</summary>
public readonly record struct Parsed(uint Guid, ushort InstanceSequence);
/// <summary>
/// Parse a 0xF747 body. <paramref name="body"/> must start with the
/// 4-byte opcode, matching every other parser in this namespace.
/// PickupEvent has a distinct parser and runtime event because it advances
/// POSITION_TS and retains the logical object.
/// </summary>
public static Parsed? TryParse(ReadOnlySpan<byte> body)
{
if (body.Length < 10)
return null;
uint opcode = BinaryPrimitives.ReadUInt32LittleEndian(body.Slice(0, 4));
if (opcode != Opcode)
return null;
uint guid = BinaryPrimitives.ReadUInt32LittleEndian(body.Slice(4, 4));
ushort instanceSequence = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(8, 2));
return new Parsed(guid, instanceSequence);
}
}