revert old sim groundwork
This commit is contained in:
@@ -1,16 +0,0 @@
|
||||
using SideScrollerGame.Sim.Math;
|
||||
|
||||
namespace SideScrollerGame.Sim.Tests;
|
||||
|
||||
public sealed class DeterministicMathSmokeTests
|
||||
{
|
||||
[Fact]
|
||||
public void FixPointAverage_UsesSimulationMathTypes()
|
||||
{
|
||||
FixPoint16[] values = [new(1), new(2), new(3)];
|
||||
|
||||
var average = values.Average();
|
||||
|
||||
Assert.Equal(new(2), average);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<Exclude>[SideScrollerGame.Sim]SideScrollerGame.Sim.Math.*,[SideScrollerGame.Sim]SideScrollerGame.Sim.SimulationDefaults</Exclude>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||
<PackageReference Include="coverlet.msbuild" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.5.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\SideScrollerGame.Sim\SideScrollerGame.Sim.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,19 +0,0 @@
|
||||
using SideScrollerGame.Sim.Verification;
|
||||
|
||||
namespace SideScrollerGame.Sim.Tests;
|
||||
|
||||
public sealed class SimulationConfigTests
|
||||
{
|
||||
[Fact]
|
||||
public void Default_UsesRepositoryDefaults()
|
||||
{
|
||||
Assert.Equal(SimulationDefaults.DefaultTicksPerSecond, SimulationConfig.Default.TicksPerSecond);
|
||||
Assert.Equal(VerificationMode.None, SimulationConfig.Default.VerificationMode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_RejectsNonPositiveTicksPerSecond()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => new SimulationConfig(0, VerificationMode.None));
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
using System.Collections.Immutable;
|
||||
using SideScrollerGame.Sim.Input;
|
||||
using SideScrollerGame.Sim.Replay;
|
||||
using SideScrollerGame.Sim.Serialization;
|
||||
|
||||
namespace SideScrollerGame.Sim.Tests;
|
||||
|
||||
public sealed class SimulationReplayTests
|
||||
{
|
||||
[Fact]
|
||||
public void SameSeedAndActions_ProduceSameHashes()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition();
|
||||
var config = SimulationTestFactory.CreateConfig();
|
||||
TickActionBatch[] batches =
|
||||
[
|
||||
SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 1, 0)),
|
||||
SimulationTestFactory.CreateTick(2, new AimAxisChanged(new(1), 3, 4)),
|
||||
SimulationTestFactory.CreateTick(3, new ButtonChanged(new(1), InputButton.Dash, true))
|
||||
];
|
||||
|
||||
Simulation left = new(definition, config, 42);
|
||||
Simulation right = new(definition, config, 42);
|
||||
|
||||
var leftHashes = ImmutableArray.CreateBuilder<int>();
|
||||
var rightHashes = ImmutableArray.CreateBuilder<int>();
|
||||
foreach (var batch in batches)
|
||||
{
|
||||
leftHashes.Add(left.Step(batch).StateHash);
|
||||
rightHashes.Add(right.Step(batch).StateHash);
|
||||
}
|
||||
|
||||
Assert.Equal(leftHashes.ToImmutable(), rightHashes.ToImmutable());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DifferentSeeds_ProduceDifferentHashes()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition();
|
||||
var config = SimulationTestFactory.CreateConfig();
|
||||
var batch = TickActionBatch.Empty(1);
|
||||
|
||||
Simulation left = new(definition, config, 1);
|
||||
Simulation right = new(definition, config, 2);
|
||||
|
||||
Assert.NotEqual(left.Step(batch).StateHash, right.Step(batch).StateHash);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReplayRecord_RoundTripsAndReplaysExpectedHashes()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition();
|
||||
var config = SimulationTestFactory.CreateConfig();
|
||||
Simulation simulation = new(definition, config, 9);
|
||||
ReplayRecorder recorder = new();
|
||||
|
||||
TickActionBatch[] batches =
|
||||
[
|
||||
SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 2, 0), new AimAxisChanged(new(1), 5, 6)),
|
||||
SimulationTestFactory.CreateTick(2, new ButtonChanged(new(1), InputButton.FireSecondary, true)),
|
||||
SimulationTestFactory.CreateTick(3, new WeaponSlotSelected(new(1), 4))
|
||||
];
|
||||
|
||||
foreach (var batch in batches)
|
||||
{
|
||||
var result = simulation.Step(batch);
|
||||
recorder.Append(batch, result);
|
||||
}
|
||||
|
||||
var replay = recorder.Build(definition, config, 9);
|
||||
var payload = ReplayRecordSerializer.Serialize(replay);
|
||||
var loadedReplay = ReplayRecordSerializer.Deserialize(payload);
|
||||
var replayedHashes = ReplayPlayer.Play(loadedReplay, definition, config);
|
||||
|
||||
Assert.Equal(loadedReplay.Ticks.Select(static tick => tick.ExpectedStateHash).ToImmutableArray(), replayedHashes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReplayPlayer_RejectsMismatchedDefinition()
|
||||
{
|
||||
var config = SimulationTestFactory.CreateConfig();
|
||||
var definition = SimulationTestFactory.CreateGameDefinition();
|
||||
ReplayRecord replay = new(123, 9, config.TicksPerSecond, ImmutableArray<RecordedTick>.Empty);
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => ReplayPlayer.Play(replay, definition, config));
|
||||
|
||||
Assert.Contains("content hash", exception.Message.ToLowerInvariant());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReplayPlayer_RejectsMismatchedTickRate()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition();
|
||||
var replay = new ReplayRecorder().Build(definition, SimulationTestFactory.CreateConfig(), 9) with { TicksPerSecond = 30 };
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => ReplayPlayer.Play(replay, definition, SimulationTestFactory.CreateConfig()));
|
||||
|
||||
Assert.Contains("tick rate", exception.Message.ToLowerInvariant());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReplayPlayer_RejectsDivergentHashes()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition();
|
||||
var config = SimulationTestFactory.CreateConfig();
|
||||
Simulation simulation = new(definition, config, 55);
|
||||
ReplayRecorder recorder = new();
|
||||
var batch = SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 1, 0));
|
||||
var result = simulation.Step(batch);
|
||||
recorder.Append(batch, result);
|
||||
|
||||
var replay = recorder.Build(definition, config, 55);
|
||||
var divergentReplay = replay with { Ticks = ImmutableArray.Create(replay.Ticks[0] with { ExpectedStateHash = replay.Ticks[0].ExpectedStateHash + 1 }) };
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => ReplayPlayer.Play(divergentReplay, definition, config));
|
||||
|
||||
Assert.Contains("diverged", exception.Message.ToLowerInvariant());
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using System.Collections.Immutable;
|
||||
using SideScrollerGame.Sim.Definitions;
|
||||
using SideScrollerGame.Sim.Input;
|
||||
using SideScrollerGame.Sim.Math;
|
||||
|
||||
namespace SideScrollerGame.Sim.Tests;
|
||||
|
||||
public sealed class SimulationSerializationTests
|
||||
{
|
||||
[Fact]
|
||||
public void SaveStateLoadState_PreservesStateAndNextStepHash()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(50, 20)), triggers: ImmutableArray.Create(new TriggerDefinition("checkpoint_a", new(new(11, 17), new(12, 18)), "TriggerActivated")), players: ImmutableArray.Create(new PlayerDefinition(new(1), new(10, 20), 10, true, FixPoint16.One, FixPoint16.One, new(3), 1, 1)));
|
||||
var config = SimulationTestFactory.CreateConfig();
|
||||
|
||||
Simulation original = new(definition, config, 17);
|
||||
original.Step(SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 1, 1), new ButtonChanged(new(1), InputButton.Jump, true)));
|
||||
|
||||
var bytes = original.SaveState();
|
||||
var loaded = Simulation.LoadState(bytes, definition, config);
|
||||
|
||||
Assert.Equal(original.CurrentTick, loaded.CurrentTick);
|
||||
Assert.Equal(original.CurrentSnapshot.StateHash, loaded.CurrentSnapshot.StateHash);
|
||||
Assert.Equal(original.CurrentState.GetRequiredPlayer(new(1)).Health, loaded.CurrentState.GetRequiredPlayer(new(1)).Health);
|
||||
Assert.Equal(original.CurrentState.ActivatedTriggerIds, loaded.CurrentState.ActivatedTriggerIds);
|
||||
Assert.Equal(original.CurrentState.GetRequiredPlayer(new(1)).VerticalVelocity, loaded.CurrentState.GetRequiredPlayer(new(1)).VerticalVelocity);
|
||||
Assert.Equal(original.CurrentState.GetRequiredPlayer(new(1)).IsGrounded, loaded.CurrentState.GetRequiredPlayer(new(1)).IsGrounded);
|
||||
|
||||
var nextBatch = SimulationTestFactory.CreateTick(2, new MoveAxisChanged(new(1), 0, 0), new ButtonChanged(new(1), InputButton.FirePrimary, true));
|
||||
var originalHash = original.Step(nextBatch).StateHash;
|
||||
var loadedHash = loaded.Step(nextBatch).StateHash;
|
||||
|
||||
Assert.Equal(originalHash, loadedHash);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_NormalizesZeroSeed()
|
||||
{
|
||||
Simulation simulation = new(SimulationTestFactory.CreateGameDefinition(), SimulationTestFactory.CreateConfig(), 0);
|
||||
|
||||
simulation.Step(TickActionBatch.Empty(1));
|
||||
|
||||
Assert.NotEqual(0UL, simulation.CurrentState.RandomState);
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
using System.Collections.Immutable;
|
||||
using SideScrollerGame.Sim.Input;
|
||||
using SideScrollerGame.Sim.Math;
|
||||
using SideScrollerGame.Sim.Runtime;
|
||||
|
||||
namespace SideScrollerGame.Sim.Tests;
|
||||
|
||||
public sealed class SimulationStateTests
|
||||
{
|
||||
[Fact]
|
||||
public void PlayerState_CloneAndButtonReleasePreserveIndependentState()
|
||||
{
|
||||
PlayerState player = new(new(1), new(3, 4), 1, 2, 5, 6, 7, 0, 9, FixPoint16.One, true, 3, 4);
|
||||
player.SetButton(InputButton.Dash, true);
|
||||
player.ApplyDamage(4);
|
||||
player.BufferJump(6);
|
||||
|
||||
var clone = player.Clone();
|
||||
player.SetButton(InputButton.Dash, false);
|
||||
player.SetPosition(new(8, 9));
|
||||
player.SetVerticalVelocity(new(5));
|
||||
|
||||
Assert.NotEqual(player.ButtonMask, clone.ButtonMask);
|
||||
Assert.Equal(7, clone.SelectedWeaponSlot);
|
||||
Assert.Equal(3, clone.Position.m_X.ToIntRound());
|
||||
Assert.Equal(4, clone.Position.m_Y.ToIntRound());
|
||||
Assert.Equal(5, clone.Health);
|
||||
Assert.Equal(1, clone.VerticalVelocity.ToIntRound());
|
||||
Assert.True(clone.IsGrounded);
|
||||
Assert.Equal(3, clone.LastGroundedTick);
|
||||
Assert.Equal(6, clone.BufferedJumpTick);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SimulationState_CloneCreatesDeepCopy()
|
||||
{
|
||||
SimulationState original = new(4, 9, 123UL, 456UL, ImmutableArray.Create(new PlayerState(new(1), new(1, 2), 3, 4, 5, 6, 7, 8, 9, new(2), true, 4, -1)), ImmutableHashSet<string>.Empty.Add("checkpoint_a"));
|
||||
var clone = original.Clone();
|
||||
|
||||
original.GetRequiredPlayer(new(1)).SetMoveAxis(9, 9);
|
||||
original.ActivateTrigger("checkpoint_b");
|
||||
|
||||
Assert.Equal(4, clone.Tick);
|
||||
Assert.Equal(9, clone.Seed);
|
||||
Assert.Equal((ulong)123, clone.RandomState);
|
||||
Assert.Equal((ulong)456, clone.LastRandomValue);
|
||||
Assert.Equal(3, clone.GetRequiredPlayer(new(1)).MoveAxisX);
|
||||
Assert.Equal(2, clone.GetRequiredPlayer(new(1)).VerticalVelocity.ToIntRound());
|
||||
Assert.DoesNotContain("checkpoint_b", clone.ActivatedTriggerIds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SimulationState_AcceptsDefaultPlayerArray()
|
||||
{
|
||||
SimulationState state = new(0, 1, 1UL, 0UL, default, ImmutableHashSet<string>.Empty);
|
||||
|
||||
Assert.Empty(state.Players);
|
||||
Assert.Empty(state.ActivatedTriggerIds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SimulationState_AcceptsDefaultTriggerSet()
|
||||
{
|
||||
SimulationState state = new(0, 1, 1UL, 0UL, ImmutableArray<PlayerState>.Empty, default!);
|
||||
|
||||
Assert.Empty(state.ActivatedTriggerIds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ActivateTrigger_ReturnsFalseWhenRepeated()
|
||||
{
|
||||
SimulationState state = new(0, 1, 1UL, 0UL, ImmutableArray<PlayerState>.Empty, ImmutableHashSet<string>.Empty);
|
||||
|
||||
Assert.True(state.ActivateTrigger("checkpoint_a"));
|
||||
Assert.False(state.ActivateTrigger("checkpoint_a"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlayerState_BufferedJumpExpiresOutsideWindow()
|
||||
{
|
||||
PlayerState player = new(new(1), new(0, 0), 0, 0, 0, 0, 0, 0, 10, FixPoint16.Zero, false, -1, -1);
|
||||
player.BufferJump(3);
|
||||
|
||||
Assert.True(player.HasBufferedJump(4, 1));
|
||||
Assert.False(player.HasBufferedJump(5, 1));
|
||||
|
||||
player.ConsumeBufferedJump();
|
||||
|
||||
Assert.False(player.HasBufferedJump(5, 5));
|
||||
}
|
||||
}
|
||||
@@ -1,417 +0,0 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using SideScrollerGame.Sim.Definitions;
|
||||
using SideScrollerGame.Sim.Input;
|
||||
using SideScrollerGame.Sim.Math;
|
||||
|
||||
namespace SideScrollerGame.Sim.Tests;
|
||||
|
||||
public sealed class SimulationStepTests
|
||||
{
|
||||
private sealed record UnsupportedAction : SimulationAction;
|
||||
|
||||
private static byte[] CreateStatePayload(int playerId, int positionX, int positionY, bool isGrounded, int lastGroundedTick = -1)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes($$"""
|
||||
{"Version":{{SimulationDefaults.StateFormatVersion}},"Tick":0,"Seed":7,"RandomState":7,"LastRandomValue":0,"Players":[{"PlayerId":{{playerId}},"PositionX":{{positionX * 65536}},"PositionY":{{positionY * 65536}},"MoveAxisX":0,"MoveAxisY":0,"AimAxisX":0,"AimAxisY":0,"SelectedWeaponSlot":0,"ButtonMask":0,"Health":10,"VerticalVelocity":0,"IsGrounded":{{isGrounded.ToString().ToLowerInvariant()}},"LastGroundedTick":{{lastGroundedTick}},"BufferedJumpTick":-1}],"ActivatedTriggerIds":[]}
|
||||
""");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_AdvancesTickSnapshotsAndMovement()
|
||||
{
|
||||
Simulation simulation = new(SimulationTestFactory.CreateGameDefinition(), SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var result = simulation.Step(SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 2, -1), new AimAxisChanged(new(1), 30, 40), new ButtonChanged(new(1), InputButton.Jump, true), new WeaponSlotSelected(new(1), 3)));
|
||||
|
||||
Assert.Equal(1, simulation.CurrentTick);
|
||||
Assert.Equal(0, simulation.PreviousSnapshot.Tick);
|
||||
Assert.Equal(0, result.PreviousSnapshot.Tick);
|
||||
Assert.Equal(1, result.CurrentSnapshot.Tick);
|
||||
Assert.Single(result.Events);
|
||||
|
||||
var player = simulation.CurrentState.GetRequiredPlayer(new(1));
|
||||
Assert.Equal(12, player.Position.m_X.ToIntRound());
|
||||
Assert.Equal(19, player.Position.m_Y.ToIntRound());
|
||||
Assert.Equal(30, player.AimAxisX);
|
||||
Assert.Equal(40, player.AimAxisY);
|
||||
Assert.Equal(3, player.SelectedWeaponSlot);
|
||||
Assert.Equal(10, player.Health);
|
||||
Assert.NotEqual(0, player.ButtonMask);
|
||||
Assert.Equal(result.StateHash, simulation.CurrentSnapshot.StateHash);
|
||||
Assert.NotEqual(0UL, simulation.CurrentSnapshot.LastRandomValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_ClampsPlayerToWorldBounds()
|
||||
{
|
||||
Simulation simulation = new(SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(11, 20))), SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var result = simulation.Step(SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 5, 0)));
|
||||
|
||||
var player = simulation.CurrentState.GetRequiredPlayer(new(1));
|
||||
Assert.Equal(11, player.Position.m_X.ToIntRound());
|
||||
Assert.Contains(result.Events, static e => e.Kind == "PlayerClamped");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_AppliesHazardDamage()
|
||||
{
|
||||
Simulation simulation = new(SimulationTestFactory.CreateGameDefinition(hazards: ImmutableArray.Create(new HazardDefinition("lava", new(new(11, 20), new(12, 21)), 3))), SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var result = simulation.Step(SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 1, 0)));
|
||||
|
||||
var player = simulation.CurrentState.GetRequiredPlayer(new(1));
|
||||
Assert.Equal(7, player.Health);
|
||||
Assert.Contains(result.Events, static e => e.Kind == "PlayerDamaged");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_IgnoresHazardsWhenPlayerIsOutside()
|
||||
{
|
||||
Simulation simulation = new(SimulationTestFactory.CreateGameDefinition(hazards: ImmutableArray.Create(new HazardDefinition("lava", new(new(50, 50), new(60, 60)), 3))), SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var result = simulation.Step(SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 1, 0)));
|
||||
|
||||
Assert.Equal(10, simulation.CurrentState.GetRequiredPlayer(new(1)).Health);
|
||||
Assert.DoesNotContain(result.Events, static e => e.Kind == "PlayerDamaged");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_ActivatesTriggerOnlyOnce()
|
||||
{
|
||||
Simulation simulation = new(SimulationTestFactory.CreateGameDefinition(triggers: ImmutableArray.Create(new TriggerDefinition("checkpoint_a", new(new(11, 20), new(12, 21)), "TriggerActivated"))), SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var first = simulation.Step(SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 1, 0)));
|
||||
var second = simulation.Step(SimulationTestFactory.CreateTick(2, new MoveAxisChanged(new(1), 0, 0)));
|
||||
|
||||
Assert.Contains(first.Events, static e => e.Kind == "TriggerActivated");
|
||||
Assert.DoesNotContain(second.Events, static e => e.Kind == "TriggerActivated");
|
||||
Assert.Contains("checkpoint_a", simulation.CurrentState.ActivatedTriggerIds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_IgnoresTriggersWhenPlayerIsOutside()
|
||||
{
|
||||
Simulation simulation = new(SimulationTestFactory.CreateGameDefinition(triggers: ImmutableArray.Create(new TriggerDefinition("checkpoint_a", new(new(50, 50), new(60, 60)), "TriggerActivated"))), SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var result = simulation.Step(SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 1, 0)));
|
||||
|
||||
Assert.DoesNotContain(result.Events, static e => e.Kind == "TriggerActivated");
|
||||
Assert.Empty(simulation.CurrentState.ActivatedTriggerIds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_RejectsUnexpectedTickNumbers()
|
||||
{
|
||||
Simulation simulation = new(SimulationTestFactory.CreateGameDefinition(), SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => simulation.Step(TickActionBatch.Empty(2)));
|
||||
|
||||
Assert.Contains("Expected tick 1", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_RejectsUnknownPlayers()
|
||||
{
|
||||
Simulation simulation = new(SimulationTestFactory.CreateGameDefinition(), SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => simulation.Step(SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(99), 1, 0))));
|
||||
|
||||
Assert.Contains("Unknown player id 99", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_RejectsUnsupportedActions()
|
||||
{
|
||||
Simulation simulation = new(SimulationTestFactory.CreateGameDefinition(), SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var exception = Assert.Throws<NotSupportedException>(() => simulation.Step(SimulationTestFactory.CreateTick(1, new UnsupportedAction())));
|
||||
|
||||
Assert.Contains("Unsupported action type", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_RejectsDuplicatePlayers()
|
||||
{
|
||||
GameDefinition definition = new(new(new(new(0, 0), new(100, 100)), ImmutableArray<HazardDefinition>.Empty, ImmutableArray<TriggerDefinition>.Empty, ImmutableArray<SolidPlatformDefinition>.Empty), ImmutableArray.Create(new(new(1), new(0, 0), 10), new PlayerDefinition(new(1), new(2, 3), 10)));
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => new Simulation(definition, SimulationTestFactory.CreateConfig(), 11));
|
||||
|
||||
Assert.Contains("Duplicate player id 1", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_RejectsSpawnOutsideBounds()
|
||||
{
|
||||
GameDefinition definition = new(new(new(new(0, 0), new(5, 5)), ImmutableArray<HazardDefinition>.Empty, ImmutableArray<TriggerDefinition>.Empty, ImmutableArray<SolidPlatformDefinition>.Empty), ImmutableArray.Create(new PlayerDefinition(new(1), new(10, 20), 10)));
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => new Simulation(definition, SimulationTestFactory.CreateConfig(), 11));
|
||||
|
||||
Assert.Contains("spawn must start inside world bounds", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_RejectsNonPositiveHealth()
|
||||
{
|
||||
GameDefinition definition = new(new(new(new(0, 0), new(100, 100)), ImmutableArray<HazardDefinition>.Empty, ImmutableArray<TriggerDefinition>.Empty, ImmutableArray<SolidPlatformDefinition>.Empty), ImmutableArray.Create(new PlayerDefinition(new(1), new(1, 1), 0)));
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => new Simulation(definition, SimulationTestFactory.CreateConfig(), 11));
|
||||
|
||||
Assert.Contains("positive health", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_RejectsNullDefinition()
|
||||
{
|
||||
var exception = Assert.Throws<ArgumentNullException>(() => new Simulation(null!, SimulationTestFactory.CreateConfig(), 1));
|
||||
|
||||
Assert.Equal("gameDefinition", exception.ParamName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_RejectsNullConfig()
|
||||
{
|
||||
var exception = Assert.Throws<ArgumentNullException>(() => new Simulation(SimulationTestFactory.CreateGameDefinition(), null!, 1));
|
||||
|
||||
Assert.Equal("config", exception.ParamName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LoadState_RejectsNullDefinition()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition();
|
||||
var config = SimulationTestFactory.CreateConfig();
|
||||
Simulation simulation = new(definition, config, 2);
|
||||
var bytes = simulation.SaveState();
|
||||
|
||||
var exception = Assert.Throws<ArgumentNullException>(() => Simulation.LoadState(bytes, null!, config));
|
||||
|
||||
Assert.Equal("gameDefinition", exception.ParamName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_PlatformerJumpUsesBufferedInputAndProducesVerticalVelocity()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(50, 20)), players: ImmutableArray.Create(SimulationTestFactory.CreatePlatformerPlayerDefinition(new(1), 10, 20)));
|
||||
Simulation simulation = new(definition, SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var result = simulation.Step(SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 1, 1), new ButtonChanged(new(1), InputButton.Jump, true)));
|
||||
|
||||
var player = simulation.CurrentState.GetRequiredPlayer(new(1));
|
||||
Assert.False(player.IsGrounded);
|
||||
Assert.Equal(12, player.Position.m_X.ToIntRound());
|
||||
Assert.Equal(18, player.Position.m_Y.ToIntRound());
|
||||
Assert.Equal(-2, player.VerticalVelocity.ToIntRound());
|
||||
Assert.Contains(result.Events, static e => e.Kind == "PlayerJumped");
|
||||
Assert.DoesNotContain(result.Events, static e => e.Kind == "PlayerClamped");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_PlatformerUsesCoyoteTimeAfterLeavingPlatform()
|
||||
{
|
||||
var platforms = ImmutableArray.Create(new SolidPlatformDefinition("ledge", new(new(10, 20), new(12, 22))));
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(50, 40)), platforms: platforms, players: ImmutableArray.Create(SimulationTestFactory.CreatePlatformerPlayerDefinition(new(1), 10, 20)));
|
||||
Simulation simulation = new(definition, SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var first = simulation.Step(SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 2, 0)));
|
||||
var second = simulation.Step(SimulationTestFactory.CreateTick(2, new MoveAxisChanged(new(1), 0, 0), new ButtonChanged(new(1), InputButton.Jump, true)));
|
||||
|
||||
var player = simulation.CurrentState.GetRequiredPlayer(new(1));
|
||||
Assert.DoesNotContain(first.Events, static e => e.Kind == "PlayerJumped");
|
||||
Assert.Contains(second.Events, static e => e.Kind == "PlayerJumped");
|
||||
Assert.False(player.IsGrounded);
|
||||
Assert.Equal(14, player.Position.m_X.ToIntRound());
|
||||
Assert.Equal(18, player.Position.m_Y.ToIntRound());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_PlatformerConsumesJumpBufferOnLanding()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(50, 20)), players: ImmutableArray.Create(new PlayerDefinition(new(1), new(10, 18), 10, true, FixPoint16.One, new(2), new(3), 0, 1)));
|
||||
Simulation simulation = new(definition, SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var result = simulation.Step(SimulationTestFactory.CreateTick(1, new ButtonChanged(new(1), InputButton.Jump, true)));
|
||||
|
||||
var player = simulation.CurrentState.GetRequiredPlayer(new(1));
|
||||
Assert.False(player.IsGrounded);
|
||||
Assert.Equal(17, player.Position.m_Y.ToIntRound());
|
||||
Assert.Equal(-3, player.VerticalVelocity.ToIntRound());
|
||||
Assert.Contains(result.Events, static e => e.Kind == "PlayerLanded");
|
||||
Assert.Contains(result.Events, static e => e.Kind == "PlayerJumped");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_PlatformerClampsHorizontalMovementAtWorldEdge()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(11, 20)), players: ImmutableArray.Create(SimulationTestFactory.CreatePlatformerPlayerDefinition(new(1), 10, 20)));
|
||||
Simulation simulation = new(definition, SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var result = simulation.Step(SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 1, 0)));
|
||||
|
||||
Assert.Equal(11, simulation.CurrentState.GetRequiredPlayer(new(1)).Position.m_X.ToIntRound());
|
||||
Assert.Contains(result.Events, static e => e.Kind == "PlayerClamped");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_PlatformerClampsJumpAtWorldCeiling()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(20, 2)), players: ImmutableArray.Create(new PlayerDefinition(new(1), new(10, 2), 10, true, FixPoint16.Zero, FixPoint16.Zero, new(4), 0, 1)));
|
||||
Simulation simulation = new(definition, SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var result = simulation.Step(SimulationTestFactory.CreateTick(1, new ButtonChanged(new(1), InputButton.Jump, true)));
|
||||
|
||||
var player = simulation.CurrentState.GetRequiredPlayer(new(1));
|
||||
Assert.Equal(0, player.Position.m_Y.ToIntRound());
|
||||
Assert.Equal(0, player.VerticalVelocity.ToIntRound());
|
||||
Assert.Contains(result.Events, static e => e.Kind == "PlayerClamped");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_PlatformerLandsOnHighestCrossedPlatform()
|
||||
{
|
||||
var platforms = ImmutableArray.Create(new("lower", new(new(8, 20), new(12, 22))), new SolidPlatformDefinition("upper", new(new(8, 15), new(12, 17))));
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(50, 40)), platforms: platforms, players: ImmutableArray.Create(new PlayerDefinition(new(1), new(10, 10), 10, true, FixPoint16.Zero, new(12), new(3), 1, 1)));
|
||||
Simulation simulation = new(definition, SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
var result = simulation.Step(SimulationTestFactory.CreateTick(1));
|
||||
|
||||
var player = simulation.CurrentState.GetRequiredPlayer(new(1));
|
||||
Assert.Equal(15, player.Position.m_Y.ToIntRound());
|
||||
Assert.True(player.IsGrounded);
|
||||
Assert.Contains(result.Events, static e => e.Kind == "PlayerLanded");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_PlatformerIgnoresPlatformWhenStillAboveTop()
|
||||
{
|
||||
var platforms = ImmutableArray.Create(new SolidPlatformDefinition("ledge", new(new(8, 15), new(12, 17))));
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(50, 40)), platforms: platforms, players: ImmutableArray.Create(new PlayerDefinition(new(1), new(10, 10), 10, true, FixPoint16.Zero, FixPoint16.Zero, new(3), 1, 1)));
|
||||
Simulation simulation = new(definition, SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
simulation.Step(SimulationTestFactory.CreateTick(1));
|
||||
|
||||
Assert.Equal(10, simulation.CurrentState.GetRequiredPlayer(new(1)).Position.m_Y.ToIntRound());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_PlatformerIgnoresPlatformWhenAlreadyBelowTop()
|
||||
{
|
||||
var platforms = ImmutableArray.Create(new SolidPlatformDefinition("ledge", new(new(8, 15), new(12, 17))));
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(50, 40)), platforms: platforms, players: ImmutableArray.Create(new PlayerDefinition(new(1), new(10, 20), 10, true, FixPoint16.Zero, FixPoint16.Zero, new(3), 1, 1)));
|
||||
Simulation simulation = new(definition, SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
simulation.Step(SimulationTestFactory.CreateTick(1));
|
||||
|
||||
Assert.Equal(20, simulation.CurrentState.GetRequiredPlayer(new(1)).Position.m_Y.ToIntRound());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_PlatformerIgnoresPlatformWhenFallingOutsideRightEdge()
|
||||
{
|
||||
var platforms = ImmutableArray.Create(new SolidPlatformDefinition("ledge", new(new(8, 15), new(12, 17))));
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(50, 40)), platforms: platforms, players: ImmutableArray.Create(new PlayerDefinition(new(1), new(14, 10), 10, true, FixPoint16.Zero, new(12), new(3), 1, 1)));
|
||||
Simulation simulation = new(definition, SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
simulation.Step(SimulationTestFactory.CreateTick(1));
|
||||
|
||||
Assert.Equal(22, simulation.CurrentState.GetRequiredPlayer(new(1)).Position.m_Y.ToIntRound());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_PlatformerIgnoresPlatformWhenFallingOutsideLeftEdge()
|
||||
{
|
||||
var platforms = ImmutableArray.Create(new SolidPlatformDefinition("ledge", new(new(8, 15), new(12, 17))));
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(50, 40)), platforms: platforms, players: ImmutableArray.Create(new PlayerDefinition(new(1), new(6, 10), 10, true, FixPoint16.Zero, new(12), new(3), 1, 1)));
|
||||
Simulation simulation = new(definition, SimulationTestFactory.CreateConfig(), 7);
|
||||
|
||||
simulation.Step(SimulationTestFactory.CreateTick(1));
|
||||
|
||||
Assert.Equal(22, simulation.CurrentState.GetRequiredPlayer(new(1)).Position.m_Y.ToIntRound());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_LoadedPlatformerStateCanRegainGroundedFlagFromSupport()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(20, 20)), players: ImmutableArray.Create(SimulationTestFactory.CreatePlatformerPlayerDefinition(new(1), 10, 20)));
|
||||
var simulation = Simulation.LoadState(CreateStatePayload(1, 10, 20, false), definition, SimulationTestFactory.CreateConfig());
|
||||
|
||||
simulation.Step(SimulationTestFactory.CreateTick(1));
|
||||
|
||||
Assert.True(simulation.CurrentState.GetRequiredPlayer(new(1)).IsGrounded);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_LoadedStateBelowFloorClampsBackIntoSupport()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(new(new(0, 0), new(20, 20)), players: ImmutableArray.Create(SimulationTestFactory.CreatePlatformerPlayerDefinition(new(1), 10, 20)));
|
||||
var simulation = Simulation.LoadState(CreateStatePayload(1, 10, 25, false), definition, SimulationTestFactory.CreateConfig());
|
||||
|
||||
simulation.Step(SimulationTestFactory.CreateTick(1));
|
||||
|
||||
var player = simulation.CurrentState.GetRequiredPlayer(new(1));
|
||||
Assert.Equal(20, player.Position.m_Y.ToIntRound());
|
||||
Assert.False(player.IsGrounded);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Step_LoadedStateRejectsPlayersMissingFromDefinition()
|
||||
{
|
||||
var definition = SimulationTestFactory.CreateGameDefinition(players: ImmutableArray.Create(SimulationTestFactory.CreatePlatformerPlayerDefinition(new(1), 10, 20)));
|
||||
var simulation = Simulation.LoadState(CreateStatePayload(99, 10, 20, true, 0), definition, SimulationTestFactory.CreateConfig());
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => simulation.Step(SimulationTestFactory.CreateTick(1)));
|
||||
|
||||
Assert.Contains("Unknown player id 99", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_RejectsNegativeJumpBufferTicks()
|
||||
{
|
||||
GameDefinition definition = new(new(new(new(0, 0), new(100, 100)), ImmutableArray<HazardDefinition>.Empty, ImmutableArray<TriggerDefinition>.Empty, ImmutableArray<SolidPlatformDefinition>.Empty), ImmutableArray.Create(new PlayerDefinition(new(1), new(1, 1), 10, true, FixPoint16.One, FixPoint16.One, new(3), 1, -1)));
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => new Simulation(definition, SimulationTestFactory.CreateConfig(), 11));
|
||||
|
||||
Assert.Contains("jump buffer ticks", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_RejectsNegativeMoveSpeed()
|
||||
{
|
||||
GameDefinition definition = new(new(new(new(0, 0), new(100, 100)), ImmutableArray<HazardDefinition>.Empty, ImmutableArray<TriggerDefinition>.Empty, ImmutableArray<SolidPlatformDefinition>.Empty), ImmutableArray.Create(new PlayerDefinition(new(1), new(1, 1), 10, true, -FixPoint16.One, FixPoint16.One, new(3), 1, 1)));
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => new Simulation(definition, SimulationTestFactory.CreateConfig(), 11));
|
||||
|
||||
Assert.Contains("move speed", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_RejectsNegativeGravity()
|
||||
{
|
||||
GameDefinition definition = new(new(new(new(0, 0), new(100, 100)), ImmutableArray<HazardDefinition>.Empty, ImmutableArray<TriggerDefinition>.Empty, ImmutableArray<SolidPlatformDefinition>.Empty), ImmutableArray.Create(new PlayerDefinition(new(1), new(1, 1), 10, true, FixPoint16.One, -FixPoint16.One, new(3), 1, 1)));
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => new Simulation(definition, SimulationTestFactory.CreateConfig(), 11));
|
||||
|
||||
Assert.Contains("gravity", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_RejectsNegativeJumpVelocity()
|
||||
{
|
||||
GameDefinition definition = new(new(new(new(0, 0), new(100, 100)), ImmutableArray<HazardDefinition>.Empty, ImmutableArray<TriggerDefinition>.Empty, ImmutableArray<SolidPlatformDefinition>.Empty), ImmutableArray.Create(new PlayerDefinition(new(1), new(1, 1), 10, true, FixPoint16.One, FixPoint16.One, -FixPoint16.One, 1, 1)));
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => new Simulation(definition, SimulationTestFactory.CreateConfig(), 11));
|
||||
|
||||
Assert.Contains("jump velocity", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_RejectsNegativeCoyoteTicks()
|
||||
{
|
||||
GameDefinition definition = new(new(new(new(0, 0), new(100, 100)), ImmutableArray<HazardDefinition>.Empty, ImmutableArray<TriggerDefinition>.Empty, ImmutableArray<SolidPlatformDefinition>.Empty), ImmutableArray.Create(new PlayerDefinition(new(1), new(1, 1), 10, true, FixPoint16.One, FixPoint16.One, new(3), -1, 1)));
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => new Simulation(definition, SimulationTestFactory.CreateConfig(), 11));
|
||||
|
||||
Assert.Contains("coyote ticks", exception.Message);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System.Collections.Immutable;
|
||||
using SideScrollerGame.Sim.Definitions;
|
||||
using SideScrollerGame.Sim.Input;
|
||||
using SideScrollerGame.Sim.Math;
|
||||
using SideScrollerGame.Sim.Verification;
|
||||
|
||||
namespace SideScrollerGame.Sim.Tests;
|
||||
|
||||
internal static class SimulationTestFactory
|
||||
{
|
||||
public static GameDefinition CreateGameDefinition(AxisAlignedBounds? worldBounds = null, ImmutableArray<HazardDefinition> hazards = default, ImmutableArray<TriggerDefinition> triggers = default, ImmutableArray<SolidPlatformDefinition> platforms = default, ImmutableArray<PlayerDefinition> players = default)
|
||||
{
|
||||
return new(new(worldBounds ?? new(new(0, 0), new(100, 100)), hazards, triggers, platforms), players.IsDefault ? ImmutableArray.Create(new PlayerDefinition(new(1), new(10, 20), 10)) : players);
|
||||
}
|
||||
|
||||
public static PlayerDefinition CreatePlatformerPlayerDefinition(PlayerId playerId, int spawnX, int spawnY)
|
||||
{
|
||||
return new(playerId, new(spawnX, spawnY), 10, true, new(2), FixPoint16.One, new(3), 1, 1);
|
||||
}
|
||||
|
||||
public static SimulationConfig CreateConfig(VerificationMode verificationMode = VerificationMode.None)
|
||||
{
|
||||
return new(SimulationDefaults.DefaultTicksPerSecond, verificationMode);
|
||||
}
|
||||
|
||||
public static TickActionBatch CreateTick(int tick, params SimulationAction[] actions)
|
||||
{
|
||||
return new(tick, ImmutableArray.Create(actions));
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using SideScrollerGame.Sim.Input;
|
||||
using SideScrollerGame.Sim.Verification;
|
||||
|
||||
namespace SideScrollerGame.Sim.Tests;
|
||||
|
||||
public sealed class SimulationVerificationTests
|
||||
{
|
||||
[Fact]
|
||||
public void RoundTripStateMode_AllowsStepping()
|
||||
{
|
||||
Simulation simulation = new(SimulationTestFactory.CreateGameDefinition(), SimulationTestFactory.CreateConfig(VerificationMode.RoundTripState), 22);
|
||||
|
||||
var result = simulation.Step(SimulationTestFactory.CreateTick(1, new MoveAxisChanged(new(1), 1, 0)));
|
||||
|
||||
Assert.Equal(1, result.CurrentSnapshot.Tick);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RoundTripAndStepCloneMode_AllowsStepping()
|
||||
{
|
||||
Simulation simulation = new(SimulationTestFactory.CreateGameDefinition(), SimulationTestFactory.CreateConfig(VerificationMode.RoundTripAndStepClone), 23);
|
||||
|
||||
var result = simulation.Step(SimulationTestFactory.CreateTick(1, new ButtonChanged(new(1), InputButton.Jump, true)));
|
||||
|
||||
Assert.Equal(1, result.CurrentSnapshot.Tick);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user