process TODO.md step4

This commit is contained in:
SepComet
2026-03-28 15:50:44 +08:00
parent 4a152e765b
commit f0064e2ae5
22 changed files with 850 additions and 62 deletions
@@ -89,6 +89,140 @@ namespace Tests.EditMode.Network
Assert.That(buffer.LastAuthoritativeTick, Is.EqualTo(10));
}
[Test]
public void ClientAuthoritativePlayerState_NewerSnapshot_ReplacesOwnedStateAndPreservesFields()
{
var owner = new ClientAuthoritativePlayerState();
var accepted = owner.TryAccept(
new PlayerState
{
PlayerId = "player-1",
Tick = 14,
Position = new global::Network.Defines.Vector3 { X = 5f, Y = 0f, Z = -3f },
Velocity = new global::Network.Defines.Vector3 { X = 1.5f, Y = 0f, Z = 0.25f },
Rotation = 90f,
Hp = 73
},
out var snapshot);
Assert.That(accepted, Is.True);
Assert.That(owner.Current, Is.SameAs(snapshot));
Assert.That(snapshot.PlayerId, Is.EqualTo("player-1"));
Assert.That(snapshot.Tick, Is.EqualTo(14));
Assert.That(snapshot.Position, Is.EqualTo(new Vector3(5f, 0f, -3f)));
Assert.That(snapshot.Velocity, Is.EqualTo(new Vector3(1.5f, 0f, 0.25f)));
Assert.That(snapshot.Rotation, Is.EqualTo(90f));
Assert.That(snapshot.RotationQuaternion.eulerAngles.y, Is.EqualTo(90f).Within(0.01f));
Assert.That(snapshot.Hp, Is.EqualTo(73));
}
[Test]
public void ClientAuthoritativePlayerState_StaleSnapshot_IsRejected()
{
var owner = new ClientAuthoritativePlayerState();
owner.TryAccept(new PlayerState { PlayerId = "player-1", Tick = 10, Hp = 95 }, out var current);
var accepted = owner.TryAccept(
new PlayerState { PlayerId = "player-1", Tick = 9, Hp = 10 },
out var staleResult);
Assert.That(accepted, Is.False);
Assert.That(owner.Current, Is.SameAs(current));
Assert.That(staleResult, Is.SameAs(current));
Assert.That(owner.Current.Hp, Is.EqualTo(95));
}
[Test]
public void ClientAuthoritativePlayerStateSnapshot_ClonesSourceMessage()
{
var source = new PlayerState
{
PlayerId = "player-1",
Tick = 3,
Position = new global::Network.Defines.Vector3 { X = 1f, Y = 0f, Z = 2f },
Rotation = 45f,
Hp = 88
};
var snapshot = new ClientAuthoritativePlayerStateSnapshot(source);
source.Tick = 4;
source.Hp = 10;
source.Position.X = 99f;
Assert.That(snapshot.Tick, Is.EqualTo(3));
Assert.That(snapshot.Hp, Is.EqualTo(88));
Assert.That(snapshot.Position, Is.EqualTo(new Vector3(1f, 0f, 2f)));
Assert.That(snapshot.SourceState.Tick, Is.EqualTo(3));
Assert.That(snapshot.SourceState.Hp, Is.EqualTo(88));
}
[Test]
public void RemotePlayerSnapshotInterpolator_StaleOrDuplicateSnapshots_AreRejected()
{
var interpolator = new RemotePlayerSnapshotInterpolator();
var firstAccepted = interpolator.TryAddSnapshot(CreateSnapshot(10, new Vector3(1f, 0f, 0f)), 1f);
var duplicateAccepted = interpolator.TryAddSnapshot(CreateSnapshot(10, new Vector3(2f, 0f, 0f)), 1.1f);
var staleAccepted = interpolator.TryAddSnapshot(CreateSnapshot(9, new Vector3(3f, 0f, 0f)), 1.2f);
Assert.That(firstAccepted, Is.True);
Assert.That(duplicateAccepted, Is.False);
Assert.That(staleAccepted, Is.False);
Assert.That(interpolator.BufferedSnapshotCount, Is.EqualTo(1));
Assert.That(interpolator.LatestBufferedTick, Is.EqualTo(10));
}
[Test]
public void RemotePlayerSnapshotInterpolator_BufferOverflow_TrimsOldestSnapshots()
{
var interpolator = new RemotePlayerSnapshotInterpolator(maxBufferedSnapshots: 3);
interpolator.TryAddSnapshot(CreateSnapshot(1, new Vector3(1f, 0f, 0f)), 0f);
interpolator.TryAddSnapshot(CreateSnapshot(2, new Vector3(2f, 0f, 0f)), 0.05f);
interpolator.TryAddSnapshot(CreateSnapshot(3, new Vector3(3f, 0f, 0f)), 0.1f);
interpolator.TryAddSnapshot(CreateSnapshot(4, new Vector3(4f, 0f, 0f)), 0.15f);
Assert.That(interpolator.BufferedSnapshotCount, Is.EqualTo(3));
Assert.That(interpolator.LatestBufferedTick, Is.EqualTo(4));
var sample = interpolator.Sample(0.3f);
Assert.That(interpolator.BufferedSnapshotCount, Is.EqualTo(1));
Assert.That(sample.LatestSnapshot.Tick, Is.EqualTo(4));
Assert.That(sample.UsedInterpolation, Is.False);
}
[Test]
public void RemotePlayerSnapshotInterpolator_BracketedRenderTime_InterpolatesBetweenSnapshots()
{
var interpolator = new RemotePlayerSnapshotInterpolator();
interpolator.TryAddSnapshot(CreateSnapshot(10, new Vector3(0f, 0f, 0f), 0f), 0f);
interpolator.TryAddSnapshot(CreateSnapshot(11, new Vector3(10f, 0f, 0f), 90f), 0.05f);
var sample = interpolator.Sample(0.125f);
Assert.That(sample.HasValue, Is.True);
Assert.That(sample.UsedInterpolation, Is.True);
Assert.That(sample.Position.x, Is.EqualTo(5f).Within(0.001f));
Assert.That(sample.Alpha, Is.EqualTo(0.5f).Within(0.001f));
Assert.That(sample.Rotation.eulerAngles.y, Is.EqualTo(45f).Within(0.01f));
Assert.That(sample.LatestSnapshot.Tick, Is.EqualTo(11));
}
[Test]
public void RemotePlayerSnapshotInterpolator_WithoutUsableBracket_ClampsToLatestSnapshot()
{
var interpolator = new RemotePlayerSnapshotInterpolator();
interpolator.TryAddSnapshot(CreateSnapshot(12, new Vector3(2f, 0f, -1f), 15f), 0.2f);
var sample = interpolator.Sample(0.35f);
Assert.That(sample.HasValue, Is.True);
Assert.That(sample.UsedInterpolation, Is.False);
Assert.That(sample.Position, Is.EqualTo(new Vector3(2f, 0f, -1f)));
Assert.That(sample.Rotation.eulerAngles.y, Is.EqualTo(15f).Within(0.01f));
Assert.That(sample.LatestSnapshot.Tick, Is.EqualTo(12));
}
[Test]
public void ClockSyncState_RejectsOlderSamples()
{
@@ -161,6 +295,19 @@ namespace Tests.EditMode.Network
}.ToByteArray();
}
private static ClientAuthoritativePlayerStateSnapshot CreateSnapshot(long tick, Vector3 position, float rotation = 0f)
{
return new ClientAuthoritativePlayerStateSnapshot(new PlayerState
{
PlayerId = "player-1",
Tick = tick,
Position = new global::Network.Defines.Vector3 { X = position.x, Y = position.y, Z = position.z },
Velocity = new global::Network.Defines.Vector3 { X = 0f, Y = 0f, Z = 0f },
Rotation = rotation,
Hp = 100
});
}
private sealed class FakeTransport : ITransport
{
public event System.Action<byte[], IPEndPoint> OnReceive;