using Microsoft.Xna.Framework;
using System;
using Terraria;
using Terraria.ID;
namespace SoulHarvest.Common;
/// <summary>
/// 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.
/// </summary>
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;
}
}
using Microsoft.Xna.Framework;
using System;
using Terraria;
using Terraria.ID;
namespace SoulHarvest.Common;
/// <summary>
/// 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.
/// </summary>
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;
}
}