Handle retail ObjectDelete (0xF747) using CM_Physics::DispatchSB_DeleteObject 0x006AC6A0 / SmartBox::HandleDeleteObject 0x00451EA0 and ACE GameMessageDeleteObject so dead creatures are removed when corpses spawn. Route action-class ForwardCommand values through AnimationCommandRouter/PlayAction instead of SetCycle so creature attack commands 0x51/0x52/0x53 survive the immediate Ready echo, matching CMotionTable::GetObjectSequence 0x00522860 / ACE MotionTable.GetObjectSequence. Use server-authoritative UpdatePosition velocity, or observed server position delta for non-player entities when HasVelocity is absent, to reduce monster/NPC chase lag without applying player RUM prediction to server-controlled creatures.
39 lines
1.1 KiB
C#
39 lines
1.1 KiB
C#
using System.Buffers.Binary;
|
|
using AcDream.Core.Net.Messages;
|
|
using Xunit;
|
|
|
|
namespace AcDream.Core.Net.Tests.Messages;
|
|
|
|
public sealed class DeleteObjectTests
|
|
{
|
|
[Fact]
|
|
public void RejectsWrongOpcode()
|
|
{
|
|
Span<byte> body = stackalloc byte[12];
|
|
BinaryPrimitives.WriteUInt32LittleEndian(body, 0xDEADBEEFu);
|
|
|
|
Assert.Null(DeleteObject.TryParse(body));
|
|
}
|
|
|
|
[Fact]
|
|
public void RejectsTruncated()
|
|
{
|
|
Assert.Null(DeleteObject.TryParse(ReadOnlySpan<byte>.Empty));
|
|
Assert.Null(DeleteObject.TryParse(new byte[9]));
|
|
}
|
|
|
|
[Fact]
|
|
public void ParsesGuidAndInstanceSequence()
|
|
{
|
|
Span<byte> body = stackalloc byte[12];
|
|
BinaryPrimitives.WriteUInt32LittleEndian(body, DeleteObject.Opcode);
|
|
BinaryPrimitives.WriteUInt32LittleEndian(body.Slice(4), 0x80000439u);
|
|
BinaryPrimitives.WriteUInt16LittleEndian(body.Slice(8), 0x1234);
|
|
|
|
var parsed = DeleteObject.TryParse(body);
|
|
|
|
Assert.NotNull(parsed);
|
|
Assert.Equal(0x80000439u, parsed!.Value.Guid);
|
|
Assert.Equal((ushort)0x1234, parsed.Value.InstanceSequence);
|
|
}
|
|
}
|