using System; using System.Buffers.Binary; using System.Numerics; using AcDream.Core.Net.Messages; using Xunit; namespace AcDream.Core.Net.Tests.Messages; public class AutonomousPositionTests { [Fact] public void Build_ProducesValidGameAction() { var body = AutonomousPosition.Build( gameActionSequence: 5, cellId: 0xA9B40001u, position: new Vector3(100f, 100f, 50f), rotation: Quaternion.Identity, instanceSequence: 0, serverControlSequence: 0, teleportSequence: 0, forcePositionSequence: 0); uint opcode = BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(0)); Assert.Equal(0xF7B1u, opcode); uint seq = BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(4)); Assert.Equal(5u, seq); uint actionType = BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(8)); Assert.Equal(0xF753u, actionType); } [Fact] public void Build_ContainsCellIdAfterHeader() { var body = AutonomousPosition.Build( gameActionSequence: 1, cellId: 0xDEADBEEFu, position: Vector3.Zero, rotation: Quaternion.Identity, instanceSequence: 0, serverControlSequence: 0, teleportSequence: 0, forcePositionSequence: 0); // After the 12-byte GameAction header, the WorldPosition starts // with u32 cell_id. uint cellId = BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(12)); Assert.Equal(0xDEADBEEFu, cellId); } [Fact] public void Build_ContainsPosition_AfterCellId() { var body = AutonomousPosition.Build( gameActionSequence: 2, cellId: 0xA9B40001u, position: new Vector3(12.5f, 34.0f, 56.75f), rotation: Quaternion.Identity, instanceSequence: 0, serverControlSequence: 0, teleportSequence: 0, forcePositionSequence: 0); // WorldPosition: cellId (4) + x (4) + y (4) + z (4) at offsets 12-27 float x = BinaryPrimitives.ReadSingleLittleEndian(body.AsSpan(16)); float y = BinaryPrimitives.ReadSingleLittleEndian(body.AsSpan(20)); float z = BinaryPrimitives.ReadSingleLittleEndian(body.AsSpan(24)); Assert.Equal(12.5f, x); Assert.Equal(34.0f, y); Assert.Equal(56.75f, z); } [Fact] public void Build_IsAlignedTo4Bytes() { var body = AutonomousPosition.Build( gameActionSequence: 3, cellId: 0xA9B40001u, position: Vector3.Zero, rotation: Quaternion.Identity, instanceSequence: 0, serverControlSequence: 0, teleportSequence: 0, forcePositionSequence: 0); Assert.Equal(0, body.Length % 4); } [Fact] public void Build_TotalLengthIsCorrect_NoCommandsNoExtraFields() { // 12 (envelope) + 32 (WorldPosition) + 8 (4x u16 sequences) + 1 (contact) + 3 (align) = 56 var body = AutonomousPosition.Build( gameActionSequence: 4, cellId: 0xA9B40001u, position: Vector3.Zero, rotation: Quaternion.Identity, instanceSequence: 0, serverControlSequence: 0, teleportSequence: 0, forcePositionSequence: 0); Assert.Equal(56, body.Length); } [Fact] public void Build_ContainsIdentityRotation_AfterPosition() { var body = AutonomousPosition.Build( gameActionSequence: 6, cellId: 0xA9B40001u, position: Vector3.Zero, rotation: Quaternion.Identity, // W=1, X=Y=Z=0 instanceSequence: 0, serverControlSequence: 0, teleportSequence: 0, forcePositionSequence: 0); // Rotation starts at offset 28: rotW(4), rotX(4), rotY(4), rotZ(4) float rotW = BinaryPrimitives.ReadSingleLittleEndian(body.AsSpan(28)); float rotX = BinaryPrimitives.ReadSingleLittleEndian(body.AsSpan(32)); float rotY = BinaryPrimitives.ReadSingleLittleEndian(body.AsSpan(36)); float rotZ = BinaryPrimitives.ReadSingleLittleEndian(body.AsSpan(40)); Assert.Equal(1.0f, rotW); Assert.Equal(0.0f, rotX); Assert.Equal(0.0f, rotY); Assert.Equal(0.0f, rotZ); } }