using System.Numerics;
using AcDream.Core.Net.Packets;
namespace AcDream.Core.Net.Messages;
///
/// Outbound GameAction(AutonomousPosition) message — opcode
/// 0xF753. Sent roughly every 200ms while the player is moving to
/// give the server a periodic ground-truth position heartbeat. Simpler than
/// : no RawMotionState, just the GameAction
/// envelope, a WorldPosition, sequence numbers, a contact byte, and 4-byte
/// alignment padding.
///
///
/// Wire layout (ported from
/// references/holtburger/crates/holtburger-protocol/src/messages/movement/actions.rs
/// AutonomousPositionActionData::pack):
///
///
/// - GameAction envelope: u32 0xF7B1, u32 sequence, u32 0xF753
/// - WorldPosition: u32 cellId, f32 x, f32 y, f32 z,
/// f32 rotW, f32 rotX, f32 rotY, f32 rotZ
/// - Sequences: u16 instance, u16 serverControl,
/// u16 teleport, u16 forcePosition
/// - Contact byte: u8 (1 = on ground, 0 = airborne)
/// - Align to 4 bytes
///
///
public static class AutonomousPosition
{
public const uint GameActionOpcode = 0xF7B1u;
public const uint AutonomousPositionAction = 0xF753u;
///
/// Build an AutonomousPosition GameAction body.
///
/// Monotonically increasing counter from
/// .
/// Landblock cell ID (u32).
/// World-space position relative to the landblock.
/// Rotation quaternion. AC wire order is W, X, Y, Z.
/// Instance sequence number from the server.
/// Server-control sequence number.
/// Teleport sequence number.
/// Force-position sequence number.
/// 1 if the character was last on the ground, 0 if airborne.
public static byte[] Build(
uint gameActionSequence,
uint cellId,
Vector3 position,
Quaternion rotation,
ushort instanceSequence,
ushort serverControlSequence,
ushort teleportSequence,
ushort forcePositionSequence,
byte lastContact = 1)
{
var w = new PacketWriter(64);
// --- GameAction envelope ---
w.WriteUInt32(GameActionOpcode);
w.WriteUInt32(gameActionSequence);
w.WriteUInt32(AutonomousPositionAction);
// --- WorldPosition (32 bytes) ---
w.WriteUInt32(cellId);
w.WriteFloat(position.X);
w.WriteFloat(position.Y);
w.WriteFloat(position.Z);
// Quaternion wire order: W, X, Y, Z
w.WriteFloat(rotation.W);
w.WriteFloat(rotation.X);
w.WriteFloat(rotation.Y);
w.WriteFloat(rotation.Z);
// --- Sequence numbers ---
w.WriteUInt16(instanceSequence);
w.WriteUInt16(serverControlSequence);
w.WriteUInt16(teleportSequence);
w.WriteUInt16(forcePositionSequence);
// --- Contact byte + 4-byte align ---
w.WriteByte(lastContact);
w.AlignTo4();
return w.ToArray();
}
}