refactor(input): extract the gameplay frame

This commit is contained in:
Erik 2026-07-22 01:38:40 +02:00
parent 0bc9fda9de
commit c557038353
24 changed files with 2433 additions and 559 deletions

View file

@ -0,0 +1,161 @@
using System.Numerics;
using AcDream.Core.Net;
namespace AcDream.App.Input;
internal interface IMovementTruthDiagnosticSink
{
void OnOutbound(
string kind,
uint sequence,
MovementResult result,
Vector3 wirePosition,
uint wireCellId,
byte contactByte);
void OnServerEcho(
WorldSession.EntityPositionUpdate update,
Vector3 serverWorldPosition);
void ResetSession();
}
internal sealed class MovementTruthDiagnosticController
: IMovementTruthDiagnosticSink
{
private readonly bool _enabled;
private readonly ILocalPlayerControllerSource _player;
private readonly ILocalPlayerIdentitySource _identity;
private MovementTruthOutbound? _lastOutbound;
private readonly record struct MovementTruthOutbound(
string Kind,
uint Sequence,
DateTime TimeUtc,
Vector3 LocalWorldPosition,
Vector3 WirePosition,
uint WireCellId,
bool IsOnGround,
byte ContactByte,
Vector3 Velocity);
public MovementTruthDiagnosticController(
bool enabled,
ILocalPlayerControllerSource player,
ILocalPlayerIdentitySource identity)
{
_enabled = enabled;
_player = player ?? throw new ArgumentNullException(nameof(player));
_identity = identity ?? throw new ArgumentNullException(nameof(identity));
}
public void OnOutbound(
string kind,
uint sequence,
MovementResult result,
Vector3 wirePosition,
uint wireCellId,
byte contactByte)
{
if (!_enabled)
return;
Vector3 velocity = _player.Controller?.BodyVelocity ?? Vector3.Zero;
_lastOutbound = new MovementTruthOutbound(
kind,
sequence,
DateTime.UtcNow,
result.Position,
wirePosition,
wireCellId,
result.IsOnGround,
contactByte,
velocity);
Console.WriteLine(FormattableString.Invariant(
$"move-truth OUT kind={kind} seq={sequence} local={Fmt(result.Position)} localCell=0x{result.CellId:X8} wire={Fmt(wirePosition)} wireCell=0x{wireCellId:X8} grounded={result.IsOnGround} contact={contactByte} vel={Fmt(velocity)} f={FmtCmd(result.ForwardCommand)} s={FmtCmd(result.SidestepCommand)} t={FmtCmd(result.TurnCommand)}"));
}
public void OnServerEcho(
WorldSession.EntityPositionUpdate update,
Vector3 serverWorldPosition)
{
if (!_enabled || update.Guid != _identity.ServerGuid)
return;
DateTime now = DateTime.UtcNow;
PlayerMovementController? controller = _player.Controller;
Vector3? localPosition = controller?.Position;
uint? localCellId = controller?.CellId;
Vector3? deltaLocal = localPosition.HasValue
? serverWorldPosition - localPosition.Value
: null;
string localText = localPosition.HasValue ? Fmt(localPosition.Value) : "-";
string localCellText = localCellId.HasValue
? FormattableString.Invariant($"0x{localCellId.Value:X8}")
: "-";
string deltaLocalText = deltaLocal.HasValue ? Fmt(deltaLocal.Value) : "-";
string deltaLocalLength = deltaLocal.HasValue
? FormattableString.Invariant($"{deltaLocal.Value.Length():F3}")
: "-";
string lastText = "-";
if (_lastOutbound is { } last)
{
Vector3 deltaOut = serverWorldPosition - last.LocalWorldPosition;
double ageMs = (now - last.TimeUtc).TotalMilliseconds;
lastText = FormattableString.Invariant(
$"{last.Kind}:{last.Sequence} ageMs={ageMs:F0} outGrounded={last.IsOnGround} outContact={last.ContactByte} outCell=0x{last.WireCellId:X8} deltaOut={Fmt(deltaOut)} distOut={deltaOut.Length():F3}");
}
string state = controller?.State.ToString() ?? "-";
string velocityText = update.Velocity.HasValue
? Fmt(update.Velocity.Value)
: "-";
Console.WriteLine(FormattableString.Invariant(
$"move-truth ECHO guid=0x{update.Guid:X8} server={Fmt(serverWorldPosition)} serverCell=0x{update.Position.LandblockId:X8} local={localText} localCell={localCellText} deltaLocal={deltaLocalText} distLocal={deltaLocalLength} serverVel={velocityText} state={state} lastOut={lastText}"));
}
public void ResetSession() => _lastOutbound = null;
private static string Fmt(Vector3 value) =>
FormattableString.Invariant(
$"({value.X:F3},{value.Y:F3},{value.Z:F3})");
private static string FmtCmd(uint? command) =>
command.HasValue
? FormattableString.Invariant($"0x{command.Value:X8}")
: "-";
}
internal sealed class DelegateMovementTruthDiagnosticSink
: IMovementTruthDiagnosticSink
{
private readonly Action<string, uint, MovementResult, Vector3, uint, byte>
_outbound;
public DelegateMovementTruthDiagnosticSink(
Action<string, uint, MovementResult, Vector3, uint, byte> outbound) =>
_outbound = outbound ?? throw new ArgumentNullException(nameof(outbound));
public void OnOutbound(
string kind,
uint sequence,
MovementResult result,
Vector3 wirePosition,
uint wireCellId,
byte contactByte) =>
_outbound(kind, sequence, result, wirePosition, wireCellId, contactByte);
public void OnServerEcho(
WorldSession.EntityPositionUpdate update,
Vector3 serverWorldPosition)
{
}
public void ResetSession()
{
}
}