feat(headless): complete deterministic bot command parity

This commit is contained in:
Erik 2026-07-27 08:23:36 +02:00
parent 7e8acb74dd
commit 38e83640d9
37 changed files with 2805 additions and 295 deletions

View file

@ -270,6 +270,60 @@ public sealed class RetailLocalPlayerFrameControllerTests
Assert.Equal(10, projections);
}
[Fact]
public void GraphicalWrapperAndDirectRuntimeFrameProduceIdenticalTrace()
{
List<string> Run(bool graphical)
{
PlayerMovementController controller = CreateController();
var trace = new List<string>();
var host = new TestLocalPlayerFrameRuntime(
() => true,
() => controller,
() => 7u,
() => trace.Add("target"),
() => false,
(_, movement, hidden) =>
trace.Add(
$"project:{movement.CellId:X8}:"
+ $"{movement.ForwardCommand:X8}:"
+ $"{movement.ShouldSendMovementEvent}:"
+ $"{hidden}"),
(_, movement, hidden) =>
trace.Add(
$"pre:{movement.ForwardCommand:X8}:"
+ $"{movement.ShouldSendMovementEvent}:"
+ $"{hidden}"),
(_, hidden) => trace.Add($"post:{hidden}"),
() => RetailObjectClockDisposition.Advance);
IMovementInputSource input = Input(
() => new MovementInput(
Forward: true,
Run: true));
if (graphical)
{
var frame = new RetailLocalPlayerFrameController(
host,
input);
frame.AdvanceBeforeNetwork(PhysicsBody.MaxQuantum);
frame.RunPostNetworkCommandPhase();
}
else
{
var frame = new RuntimeLocalPlayerFrameController(
host,
input);
frame.AdvanceBeforeNetwork(PhysicsBody.MaxQuantum);
frame.RunPostNetworkCommandPhase();
}
return trace;
}
Assert.Equal(Run(graphical: true), Run(graphical: false));
}
private static PlayerMovementController CreateController()
{
var engine = new PhysicsEngine();