using System; using System.Buffers.Binary; using System.Numerics; using AcDream.Core.Net.Messages; using Xunit; namespace AcDream.Core.Net.Tests.Messages; public class MoveToStateTests { [Fact] public void Build_IdleState_ProducesValidGameAction() { var body = MoveToState.Build( gameActionSequence: 1, forwardCommand: null, forwardSpeed: null, sidestepCommand: null, sidestepSpeed: null, turnCommand: null, turnSpeed: null, holdKey: null, cellId: 0xA9B40001u, position: new Vector3(96f, 96f, 50f), rotation: Quaternion.Identity, instanceSequence: 0, serverControlSequence: 0, teleportSequence: 0, forcePositionSequence: 0); // First 4 bytes: GameAction opcode 0xF7B1 uint opcode = BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(0)); Assert.Equal(0xF7B1u, opcode); // Bytes 4-7: game action sequence uint seq = BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(4)); Assert.Equal(1u, seq); // Bytes 8-11: MoveToState action type 0xF61C uint actionType = BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(8)); Assert.Equal(0xF61Cu, actionType); } [Fact] public void Build_WalkForward_IncludesForwardCommandInFlags() { var body = MoveToState.Build( gameActionSequence: 2, forwardCommand: 0x45000005u, // WalkForward forwardSpeed: 1.0f, sidestepCommand: null, sidestepSpeed: null, turnCommand: null, turnSpeed: null, holdKey: null, cellId: 0xA9B40001u, position: new Vector3(96f, 96f, 50f), rotation: Quaternion.Identity, instanceSequence: 0, serverControlSequence: 0, teleportSequence: 0, forcePositionSequence: 0); // After the 12-byte GameAction header comes RawMotionState. // First u32 is the packed flags word. ForwardCommand flag = 0x4. uint flags = BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(12)); Assert.True((flags & 0x4u) != 0, "ForwardCommand flag (0x4) should be set"); // ForwardSpeed flag = 0x10 Assert.True((flags & 0x10u) != 0, "ForwardSpeed flag (0x10) should be set"); } [Fact] public void Build_IdleState_RawMotionFlagsAreZero() { var body = MoveToState.Build( gameActionSequence: 3, forwardCommand: null, forwardSpeed: null, sidestepCommand: null, sidestepSpeed: null, turnCommand: null, turnSpeed: null, holdKey: null, cellId: 0xA9B40001u, position: Vector3.Zero, rotation: Quaternion.Identity, instanceSequence: 0, serverControlSequence: 0, teleportSequence: 0, forcePositionSequence: 0); uint flags = BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(12)); Assert.Equal(0u, flags); } [Fact] public void Build_IdleState_WorldPositionFollowsMotionState() { // With no motion state, flags = 0 and no conditional fields are written. // So WorldPosition starts at offset 12 (envelope) + 4 (flags) = 16. var body = MoveToState.Build( gameActionSequence: 4, forwardCommand: null, forwardSpeed: null, sidestepCommand: null, sidestepSpeed: null, turnCommand: null, turnSpeed: null, holdKey: null, cellId: 0xDEADBEEFu, position: Vector3.Zero, rotation: Quaternion.Identity, instanceSequence: 0, serverControlSequence: 0, teleportSequence: 0, forcePositionSequence: 0); uint cellId = BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(16)); Assert.Equal(0xDEADBEEFu, cellId); } [Fact] public void Build_IsAlignedTo4Bytes() { var body = MoveToState.Build( gameActionSequence: 5, forwardCommand: null, forwardSpeed: null, sidestepCommand: null, sidestepSpeed: null, turnCommand: null, turnSpeed: null, holdKey: null, 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_WithHoldKey_IncludesHoldKeyFlag() { var body = MoveToState.Build( gameActionSequence: 6, forwardCommand: null, forwardSpeed: null, sidestepCommand: null, sidestepSpeed: null, turnCommand: null, turnSpeed: null, holdKey: 2u, // Run cellId: 0xA9B40001u, position: Vector3.Zero, rotation: Quaternion.Identity, instanceSequence: 0, serverControlSequence: 0, teleportSequence: 0, forcePositionSequence: 0); uint flags = BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(12)); Assert.True((flags & 0x1u) != 0, "CurrentHoldKey flag (0x1) should be set"); // The hold key value (u32 = 2) should immediately follow the flags uint holdKeyValue = BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(16)); Assert.Equal(2u, holdKeyValue); } }