using Microsoft.Xna.Framework; using System; using Terraria; using Terraria.ID; namespace SoulHarvest.Common; /// /// Holds a server movement destination until the owning client confirms the /// sequenced correction. TCP ordering guarantees every pre-dash vanilla controls /// packet is processed before that acknowledgement; confirmation reapplies the /// destination once, then releases normal owner movement immediately. /// internal sealed class ReaperMovementAuthorityPlayer : Terraria.ModLoader.ModPlayer { private uint nextSequence; private uint activeSequence; private Vector2 authoritativePosition; private Vector2 authoritativeVelocity; private int lockFrames; public override void Initialize() { nextSequence = 0; ClearMovementLock(); } internal void BeginAuthoritativeMovement(Vector2 position, Vector2 velocity) { if (Main.netMode != NetmodeID.Server) return; nextSequence++; if (nextSequence == 0) nextSequence++; activeSequence = nextSequence; authoritativePosition = position; authoritativeVelocity = velocity; lockFrames = 60; ApplyDestination(); SoulHarvest.BroadcastReaperMovement(Player, activeSequence); } internal void ConfirmAuthoritativeMovement(uint sequence) { if (Main.netMode != NetmodeID.Server || lockFrames <= 0 || sequence != activeSequence) return; // Reapply after all older owner packets, then send an acknowledgement-free // final correction so every observer converges on the same landing point. ApplyDestination(); ClearMovementLock(); SoulHarvest.BroadcastReaperMovement(Player, sequence: 0); } public override void PostUpdate() { if (Main.netMode != NetmodeID.Server || lockFrames <= 0) return; if (!Player.active || Player.dead) { ClearMovementLock(); return; } ApplyDestination(); lockFrames--; if (lockFrames <= 0) SoulHarvest.BroadcastReaperMovement(Player, sequence: 0); } private void ApplyDestination() { Player.position = authoritativePosition; Player.velocity = authoritativeVelocity; } private void ClearMovementLock() { activeSequence = 0; authoritativePosition = Vector2.Zero; authoritativeVelocity = Vector2.Zero; lockFrames = 0; } }