refactor(input): extract the gameplay frame
This commit is contained in:
parent
0bc9fda9de
commit
c557038353
24 changed files with 2433 additions and 559 deletions
161
src/AcDream.App/Input/MovementTruthDiagnosticController.cs
Normal file
161
src/AcDream.App/Input/MovementTruthDiagnosticController.cs
Normal 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()
|
||||
{
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue