663 lines
23 KiB
C#
663 lines
23 KiB
C#
using System.Numerics;
|
|
using AcDream.Core.Physics;
|
|
using AcDream.Runtime.World;
|
|
|
|
namespace AcDream.Runtime.Tests.World;
|
|
|
|
public sealed class RuntimeWorldTransitStateTests
|
|
{
|
|
private const uint OutdoorCell = 0x11340021u;
|
|
private const uint OtherCell = 0x3032001Cu;
|
|
|
|
[Fact]
|
|
public void BeginReveal_OwnsGenerationDestinationAndSimulationGate()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
|
|
long generation =
|
|
state.BeginLoginReveal(OutdoorCell);
|
|
|
|
Assert.Equal(1, generation);
|
|
Assert.Equal(generation, state.Snapshot.Generation);
|
|
Assert.Equal(RuntimePortalKind.Login, state.Snapshot.Kind);
|
|
Assert.Equal(OutdoorCell, state.Snapshot.DestinationCell);
|
|
Assert.False(state.IsWorldSimulationAvailable);
|
|
Assert.False(state.Snapshot.IsReady);
|
|
}
|
|
|
|
[Fact]
|
|
public void TypedReadiness_RejectsWrongGenerationAndDestination()
|
|
{
|
|
List<string> log = [];
|
|
var state = new RuntimeWorldTransitState(log.Add);
|
|
long generation =
|
|
BeginPortal(state, OutdoorCell);
|
|
|
|
Assert.False(state.AcknowledgeDestinationReadiness(
|
|
Ready(generation + 1, OutdoorCell)));
|
|
Assert.False(state.AcknowledgeDestinationReadiness(
|
|
Ready(generation, OtherCell)));
|
|
|
|
Assert.Equal(OutdoorCell, state.Snapshot.DestinationCell);
|
|
Assert.False(state.Snapshot.IsReady);
|
|
Assert.Equal(1, state.Snapshot.InvariantFailureCount);
|
|
Assert.Equal(
|
|
1,
|
|
log.Count(value => value.Contains(
|
|
"event=invariant-failure",
|
|
StringComparison.Ordinal)));
|
|
Assert.Single(
|
|
log,
|
|
value => value.Contains(
|
|
"event=rejected",
|
|
StringComparison.Ordinal));
|
|
}
|
|
|
|
[Fact]
|
|
public void Materialization_ReleasesSimulationBeforeViewportAndCompletion()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long generation =
|
|
BeginPortal(state, OutdoorCell);
|
|
Assert.True(state.AcknowledgeDestinationReadiness(
|
|
Ready(generation, OutdoorCell)));
|
|
|
|
Assert.True(state.AcknowledgePortalMaterialized(
|
|
generation,
|
|
1,
|
|
OutdoorCell));
|
|
|
|
Assert.True(state.IsWorldSimulationAvailable);
|
|
Assert.True(state.Snapshot.Materialized);
|
|
Assert.False(state.Snapshot.WorldViewportObserved);
|
|
Assert.False(state.Snapshot.Completed);
|
|
Assert.Equal(1, state.Snapshot.PortalMaterializationCount);
|
|
Assert.False(state.AcknowledgePortalMaterialized(
|
|
generation,
|
|
1,
|
|
OutdoorCell));
|
|
|
|
Assert.True(state.AcknowledgeWorldViewportVisible(generation));
|
|
Assert.True(state.Complete(generation));
|
|
Assert.True(state.Snapshot.WorldViewportObserved);
|
|
Assert.True(state.Snapshot.Completed);
|
|
Assert.Equal(1, state.Snapshot.PortalMaterializationCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void MaterializationBeforeReadiness_IsRejectedWithoutOpeningWorld()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long generation =
|
|
BeginPortal(state, OutdoorCell);
|
|
|
|
Assert.False(state.AcknowledgePortalMaterialized(
|
|
generation,
|
|
1,
|
|
OutdoorCell));
|
|
|
|
Assert.False(state.IsWorldSimulationAvailable);
|
|
Assert.False(state.Snapshot.Materialized);
|
|
Assert.Equal(1, state.Snapshot.InvariantFailureCount);
|
|
Assert.Equal(0, state.Snapshot.PortalMaterializationCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void LoginCompletion_ReleasesSimulationBeforeFirstVisibleFrame()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long generation =
|
|
state.BeginLoginReveal(OutdoorCell);
|
|
state.AcknowledgeDestinationReadiness(
|
|
Ready(generation, OutdoorCell));
|
|
|
|
Assert.True(state.Complete(generation));
|
|
Assert.True(state.IsWorldSimulationAvailable);
|
|
Assert.False(state.Snapshot.WorldViewportObserved);
|
|
|
|
Assert.True(state.AcknowledgeWorldViewportVisible(generation));
|
|
Assert.True(state.Snapshot.WorldViewportObserved);
|
|
Assert.Equal(0, state.Snapshot.InvariantFailureCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void EarlyViewport_IsRejectedWithoutFabricatingVisibility()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long generation =
|
|
state.BeginLoginReveal(OutdoorCell);
|
|
|
|
Assert.False(state.AcknowledgeWorldViewportVisible(generation));
|
|
|
|
Assert.False(state.Snapshot.IsReady);
|
|
Assert.False(state.Snapshot.WorldViewportObserved);
|
|
Assert.Equal(1, state.Snapshot.InvariantFailureCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void ReadinessShape_MustMatchDestinationCell()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long generation =
|
|
state.BeginLoginReveal(OutdoorCell);
|
|
RuntimeDestinationReadiness invalid =
|
|
Ready(generation, OutdoorCell) with
|
|
{
|
|
IsIndoor = true,
|
|
RequiredRenderRadius = 0,
|
|
};
|
|
|
|
Assert.False(state.AcknowledgeDestinationReadiness(invalid));
|
|
|
|
Assert.False(state.Snapshot.IsReady);
|
|
Assert.Equal(1, state.Snapshot.InvariantFailureCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void AcceptedReadiness_IsGenerationSticky()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long generation =
|
|
BeginPortal(state, OutdoorCell);
|
|
RuntimeDestinationReadiness accepted =
|
|
Ready(generation, OutdoorCell);
|
|
Assert.True(state.AcknowledgeDestinationReadiness(accepted));
|
|
|
|
RuntimeDestinationReadiness regressed = accepted with
|
|
{
|
|
IsCollisionReady = false,
|
|
};
|
|
Assert.False(state.AcknowledgeDestinationReadiness(regressed));
|
|
|
|
Assert.Equal(accepted, state.Snapshot.Readiness);
|
|
Assert.True(state.Snapshot.IsReady);
|
|
Assert.Equal(0, state.Snapshot.InvariantFailureCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void Completion_RejectsReorderedLoginAndPortalEdges()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long login =
|
|
state.BeginLoginReveal(OutdoorCell);
|
|
|
|
Assert.False(state.Complete(login));
|
|
Assert.False(state.Snapshot.Completed);
|
|
|
|
long portal =
|
|
BeginPortal(state, OtherCell, sequence: 2);
|
|
Assert.True(state.AcknowledgeDestinationReadiness(
|
|
Ready(portal, OtherCell)));
|
|
Assert.False(state.Complete(portal));
|
|
Assert.False(state.Snapshot.Completed);
|
|
Assert.Equal(2, state.Snapshot.InvariantFailureCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void Supersession_RejectsOldAcknowledgementsAndKeepsLatestDestination()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long first =
|
|
state.BeginLoginReveal(OutdoorCell);
|
|
long second =
|
|
BeginPortal(state, OtherCell);
|
|
|
|
Assert.True(second > first);
|
|
Assert.False(state.AcknowledgeDestinationReadiness(
|
|
Ready(first, OutdoorCell)));
|
|
Assert.False(state.AcknowledgePortalMaterialized(
|
|
first,
|
|
1,
|
|
OutdoorCell));
|
|
|
|
Assert.Equal(second, state.Snapshot.Generation);
|
|
Assert.Equal(OtherCell, state.Snapshot.DestinationCell);
|
|
Assert.False(state.Snapshot.IsReady);
|
|
Assert.False(state.IsWorldSimulationAvailable);
|
|
Assert.Equal(0, state.Snapshot.InvariantFailureCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void Cancel_ReleasesSimulationAndRejectsLateHostWork()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long generation =
|
|
BeginPortal(state, OutdoorCell);
|
|
|
|
Assert.True(state.Cancel(generation));
|
|
Assert.True(state.IsWorldSimulationAvailable);
|
|
Assert.True(state.Snapshot.Cancelled);
|
|
|
|
Assert.False(state.AcknowledgeDestinationReadiness(
|
|
Ready(generation, OutdoorCell)));
|
|
Assert.False(state.AcknowledgePortalMaterialized(
|
|
generation,
|
|
1,
|
|
OutdoorCell));
|
|
Assert.False(state.Complete(generation));
|
|
Assert.False(state.Snapshot.Materialized);
|
|
Assert.False(state.Snapshot.Completed);
|
|
}
|
|
|
|
[Fact]
|
|
public void MaterializedThenCancelled_RemainsAvailableAndCannotComplete()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long generation =
|
|
BeginPortal(state, OutdoorCell);
|
|
state.AcknowledgeDestinationReadiness(
|
|
Ready(generation, OutdoorCell));
|
|
state.AcknowledgePortalMaterialized(
|
|
generation,
|
|
1,
|
|
OutdoorCell);
|
|
|
|
Assert.True(state.Cancel(generation));
|
|
Assert.True(state.IsWorldSimulationAvailable);
|
|
Assert.True(state.Snapshot.Materialized);
|
|
Assert.True(state.Snapshot.Cancelled);
|
|
Assert.False(state.Complete(generation));
|
|
Assert.False(state.Snapshot.Completed);
|
|
Assert.Equal(1, state.Snapshot.PortalMaterializationCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void WaitCue_UsesRetailFiveSecondEdgeWithoutCompletingReveal()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long generation =
|
|
BeginPortal(state, OutdoorCell);
|
|
|
|
Assert.False(state.ObserveWait(
|
|
generation,
|
|
RuntimeWorldTransitState.RetailWaitCueDelay
|
|
- TimeSpan.FromMilliseconds(1)));
|
|
Assert.True(state.ObserveWait(
|
|
generation,
|
|
RuntimeWorldTransitState.RetailWaitCueDelay));
|
|
Assert.True(state.ObserveWait(
|
|
generation,
|
|
RuntimeWorldTransitState.RetailWaitCueDelay
|
|
+ TimeSpan.FromSeconds(20)));
|
|
|
|
Assert.True(state.Snapshot.WaitCueShown);
|
|
Assert.False(state.Snapshot.Completed);
|
|
Assert.False(state.IsWorldSimulationAvailable);
|
|
}
|
|
|
|
[Fact]
|
|
public void UnhydratableDestination_IsAnExplicitReadyAcknowledgement()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long generation =
|
|
BeginPortal(state, OutdoorCell);
|
|
var acknowledgement = new RuntimeDestinationReadiness(
|
|
generation,
|
|
OutdoorCell,
|
|
IsIndoor: false,
|
|
IsUnhydratable: true,
|
|
RequiredRenderRadius: 1,
|
|
IsRenderNeighborhoodReady: false,
|
|
AreCompositeTexturesReady: false,
|
|
IsCollisionReady: false);
|
|
|
|
Assert.True(state.AcknowledgeDestinationReadiness(acknowledgement));
|
|
Assert.True(state.Snapshot.IsReady);
|
|
Assert.True(state.AcknowledgePortalMaterialized(
|
|
generation,
|
|
1,
|
|
OutdoorCell));
|
|
}
|
|
|
|
[Fact]
|
|
public void ResetSession_ClearsVisibleStateButNeverReusesGeneration()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long first =
|
|
BeginPortal(state, OutdoorCell);
|
|
state.ResetSession();
|
|
|
|
Assert.Equal(RuntimePortalSnapshot.Idle, state.Snapshot);
|
|
Assert.True(state.IsWorldSimulationAvailable);
|
|
|
|
long second =
|
|
state.BeginLoginReveal(OtherCell);
|
|
Assert.True(second > first);
|
|
Assert.False(state.AcknowledgeDestinationReadiness(
|
|
Ready(first, OutdoorCell)));
|
|
Assert.Equal(second, state.Snapshot.Generation);
|
|
Assert.Equal(OtherCell, state.Snapshot.DestinationCell);
|
|
}
|
|
|
|
[Fact]
|
|
public void Instances_IsolateGenerationReadinessAndMaterializationCounts()
|
|
{
|
|
var first = new RuntimeWorldTransitState();
|
|
var second = new RuntimeWorldTransitState();
|
|
long firstGeneration =
|
|
BeginPortal(first, OutdoorCell);
|
|
long secondGeneration =
|
|
second.BeginLoginReveal(OtherCell);
|
|
first.AcknowledgeDestinationReadiness(
|
|
Ready(firstGeneration, OutdoorCell));
|
|
first.AcknowledgePortalMaterialized(
|
|
firstGeneration,
|
|
1,
|
|
OutdoorCell);
|
|
|
|
Assert.Equal(1, first.Snapshot.PortalMaterializationCount);
|
|
Assert.Equal(0, second.Snapshot.PortalMaterializationCount);
|
|
Assert.True(first.IsWorldSimulationAvailable);
|
|
Assert.False(second.IsWorldSimulationAvailable);
|
|
Assert.Equal(OtherCell, second.Snapshot.DestinationCell);
|
|
Assert.Equal(1, secondGeneration);
|
|
}
|
|
|
|
[Fact]
|
|
public void DiagnosticCallbackFailure_CannotInterruptCanonicalTransition()
|
|
{
|
|
var state = new RuntimeWorldTransitState(
|
|
_ => throw new InvalidOperationException("diagnostic failed"));
|
|
|
|
long generation =
|
|
BeginPortal(state, OutdoorCell);
|
|
Assert.True(state.AcknowledgeDestinationReadiness(
|
|
Ready(generation, OutdoorCell)));
|
|
Assert.True(state.AcknowledgePortalMaterialized(
|
|
generation,
|
|
1,
|
|
OutdoorCell));
|
|
Assert.True(state.Complete(generation));
|
|
|
|
Assert.True(state.Snapshot.Completed);
|
|
Assert.True(state.IsWorldSimulationAvailable);
|
|
Assert.True(state.DiagnosticFailureCount >= 4);
|
|
Assert.IsType<InvalidOperationException>(
|
|
state.LastDiagnosticFailure);
|
|
}
|
|
|
|
[Fact]
|
|
public void ReplacementRejectsDelayedPriorDestinationAndAcceptsCurrentAdvance()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
Assert.True(state.TryQueueTeleportStart(10));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
state.EndTeleport();
|
|
Assert.True(state.TryQueueTeleportStart(11));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
|
|
Assert.False(state.OfferTeleportDestination(
|
|
Destination(OutdoorCell, 10, x: 10f),
|
|
teleportTimestampAdvanced: true));
|
|
Assert.True(state.OfferTeleportDestination(
|
|
Destination(OtherCell, 11, x: 11f),
|
|
teleportTimestampAdvanced: true));
|
|
Assert.True(state.TryGetAcceptedTeleportDestination(
|
|
out RuntimeTeleportDestination accepted));
|
|
Assert.Equal(11f, accepted.Position.Frame.Origin.X);
|
|
Assert.Equal(OtherCell, accepted.CellId);
|
|
}
|
|
|
|
[Fact]
|
|
public void PositionBeforeF751IsBufferedAndEqualFollowupCannotReplaceIt()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
|
|
Assert.False(state.OfferTeleportDestination(
|
|
Destination(OutdoorCell, 11, x: 110f),
|
|
teleportTimestampAdvanced: true));
|
|
Assert.Equal(1, state.BufferedTeleportDestinationCount);
|
|
Assert.True(state.TryQueueTeleportStart(11));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
Assert.True(state.TryGetAcceptedTeleportDestination(
|
|
out RuntimeTeleportDestination buffered));
|
|
Assert.Equal(110f, buffered.Position.Frame.Origin.X);
|
|
|
|
Assert.False(state.OfferTeleportDestination(
|
|
Destination(OtherCell, 11, x: 111f),
|
|
teleportTimestampAdvanced: false));
|
|
Assert.True(state.TryGetAcceptedTeleportDestination(out buffered));
|
|
Assert.Equal(OutdoorCell, buffered.CellId);
|
|
}
|
|
|
|
[Fact]
|
|
public void InactiveOrdinaryPositionIsNeverBuffered()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
|
|
Assert.False(state.OfferTeleportDestination(
|
|
Destination(OutdoorCell, 11),
|
|
teleportTimestampAdvanced: false));
|
|
Assert.Equal(0, state.BufferedTeleportDestinationCount);
|
|
Assert.True(state.TryQueueTeleportStart(11));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
Assert.False(state.HasAcceptedTeleportDestination);
|
|
}
|
|
|
|
[Fact]
|
|
public void DuplicateStartIsRejectedButSequenceWrapIsFresh()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
Assert.True(state.TryQueueTeleportStart(ushort.MaxValue));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
state.EndTeleport();
|
|
|
|
Assert.False(state.CanQueueTeleportStart(ushort.MaxValue));
|
|
Assert.False(state.TryQueueTeleportStart(ushort.MaxValue));
|
|
Assert.True(state.CanQueueTeleportStart(0));
|
|
Assert.True(state.TryQueueTeleportStart(0));
|
|
Assert.True(state.HasPendingTeleportStart);
|
|
}
|
|
|
|
[Fact]
|
|
public void ExactHalfRangeUsesRetailLowerStampTieBreak()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
Assert.True(state.TryQueueTeleportStart(0x8000));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
state.EndTeleport();
|
|
|
|
Assert.True(state.CanQueueTeleportStart(0x0000));
|
|
Assert.True(state.TryQueueTeleportStart(0x0000));
|
|
}
|
|
|
|
[Fact]
|
|
public void PendingStartAcceptsEqualPositionUntilHostCanActivate()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
Assert.True(state.TryQueueTeleportStart(11));
|
|
|
|
Assert.False(state.OfferTeleportDestination(
|
|
Destination(OutdoorCell, 11, x: 110f),
|
|
teleportTimestampAdvanced: false));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
Assert.True(state.TryGetAcceptedTeleportDestination(
|
|
out RuntimeTeleportDestination buffered));
|
|
|
|
Assert.Equal(110f, buffered.Position.Frame.Origin.X);
|
|
Assert.True(state.IsTeleportActive);
|
|
}
|
|
|
|
[Fact]
|
|
public void AdvancingPositionPrunesSkippedDestination()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
|
|
Assert.False(state.OfferTeleportDestination(
|
|
Destination(OutdoorCell, 11),
|
|
teleportTimestampAdvanced: true));
|
|
Assert.False(state.OfferTeleportDestination(
|
|
Destination(OtherCell, 12),
|
|
teleportTimestampAdvanced: true));
|
|
Assert.Equal(1, state.BufferedTeleportDestinationCount);
|
|
Assert.True(state.TryQueueTeleportStart(12));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
Assert.True(state.TryGetAcceptedTeleportDestination(
|
|
out RuntimeTeleportDestination buffered));
|
|
|
|
Assert.Equal(OtherCell, buffered.CellId);
|
|
}
|
|
|
|
[Fact]
|
|
public void ObsoleteDestinationCannotSurviveSequenceWrap()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
|
|
Assert.False(state.OfferTeleportDestination(
|
|
Destination(OutdoorCell, ushort.MaxValue),
|
|
teleportTimestampAdvanced: true));
|
|
Assert.False(state.OfferTeleportDestination(
|
|
Destination(OtherCell, 0),
|
|
teleportTimestampAdvanced: true));
|
|
Assert.True(state.TryQueueTeleportStart(0));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
Assert.True(state.TryGetAcceptedTeleportDestination(
|
|
out RuntimeTeleportDestination wrapped));
|
|
Assert.Equal(OtherCell, wrapped.CellId);
|
|
state.EndTeleport();
|
|
|
|
Assert.True(state.TryQueueTeleportStart(0x7FFF));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
state.EndTeleport();
|
|
Assert.True(state.TryQueueTeleportStart(0xFFFE));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
state.EndTeleport();
|
|
Assert.True(state.TryQueueTeleportStart(ushort.MaxValue));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
|
|
Assert.False(state.HasAcceptedTeleportDestination);
|
|
}
|
|
|
|
[Fact]
|
|
public void PortalRevealClaimsOnlyExactAcceptedSequenceAndCell()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
Assert.True(state.TryQueueTeleportStart(7));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
Assert.True(state.OfferTeleportDestination(
|
|
Destination(OutdoorCell, 7),
|
|
teleportTimestampAdvanced: true));
|
|
|
|
Assert.False(state.TryBeginPortalReveal(
|
|
8,
|
|
OutdoorCell,
|
|
out _));
|
|
Assert.False(state.TryBeginPortalReveal(
|
|
7,
|
|
OtherCell,
|
|
out _));
|
|
Assert.Equal(RuntimePortalSnapshot.Idle.Generation, state.Snapshot.Generation);
|
|
Assert.True(state.HasAcceptedTeleportDestination);
|
|
|
|
Assert.True(state.TryBeginPortalReveal(
|
|
7,
|
|
OutdoorCell,
|
|
out long generation));
|
|
Assert.True(generation > 0);
|
|
Assert.False(state.HasAcceptedTeleportDestination);
|
|
Assert.True(state.CanPlacePortalDestination(
|
|
generation,
|
|
7,
|
|
OutdoorCell));
|
|
Assert.False(state.CanPlacePortalDestination(
|
|
generation,
|
|
8,
|
|
OutdoorCell));
|
|
Assert.False(state.CanPlacePortalDestination(
|
|
generation,
|
|
7,
|
|
OtherCell));
|
|
}
|
|
|
|
[Fact]
|
|
public void MaterializationRequiresExactGenerationSequenceAndCell()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
long generation = BeginPortal(state, OutdoorCell, sequence: 17);
|
|
Assert.True(state.AcknowledgeDestinationReadiness(
|
|
Ready(generation, OutdoorCell)));
|
|
|
|
Assert.False(state.AcknowledgePortalMaterialized(
|
|
generation + 1,
|
|
17,
|
|
OutdoorCell));
|
|
Assert.False(state.AcknowledgePortalMaterialized(
|
|
generation,
|
|
18,
|
|
OutdoorCell));
|
|
Assert.False(state.AcknowledgePortalMaterialized(
|
|
generation,
|
|
17,
|
|
OtherCell));
|
|
Assert.False(state.Snapshot.Materialized);
|
|
|
|
Assert.True(state.AcknowledgePortalMaterialized(
|
|
generation,
|
|
17,
|
|
OutdoorCell));
|
|
Assert.True(state.Snapshot.Materialized);
|
|
}
|
|
|
|
[Fact]
|
|
public void ResetSessionClearsCorrelationHistoryAndBufferedDestinations()
|
|
{
|
|
var state = new RuntimeWorldTransitState();
|
|
Assert.False(state.OfferTeleportDestination(
|
|
Destination(OutdoorCell, 7),
|
|
teleportTimestampAdvanced: true));
|
|
Assert.True(state.TryQueueTeleportStart(8));
|
|
|
|
state.ResetSession();
|
|
|
|
Assert.False(state.IsTeleportActive);
|
|
Assert.False(state.HasPendingTeleportStart);
|
|
Assert.False(state.HasAcceptedTeleportDestination);
|
|
Assert.Equal(0, state.BufferedTeleportDestinationCount);
|
|
Assert.True(state.TryQueueTeleportStart(8));
|
|
}
|
|
|
|
private static long BeginPortal(
|
|
RuntimeWorldTransitState state,
|
|
uint cell,
|
|
ushort sequence = 1)
|
|
{
|
|
Assert.True(state.TryQueueTeleportStart(sequence));
|
|
Assert.True(state.ActivateQueuedTeleport());
|
|
Assert.True(state.OfferTeleportDestination(
|
|
Destination(cell, sequence),
|
|
teleportTimestampAdvanced: true));
|
|
Assert.True(state.TryBeginPortalReveal(
|
|
sequence,
|
|
cell,
|
|
out long generation));
|
|
return generation;
|
|
}
|
|
|
|
private static RuntimeTeleportDestination Destination(
|
|
uint cell,
|
|
ushort sequence,
|
|
float x = 1f) =>
|
|
new(
|
|
EntityGuid: 0x50000001u,
|
|
InstanceSequence: 1,
|
|
PositionSequence: 1,
|
|
TeleportSequence: sequence,
|
|
ForcePositionSequence: 1,
|
|
Position: new Position(
|
|
cell,
|
|
new Vector3(x, 2f, 3f),
|
|
Quaternion.Identity));
|
|
|
|
private static RuntimeDestinationReadiness Ready(
|
|
long generation,
|
|
uint cell) =>
|
|
new(
|
|
generation,
|
|
cell,
|
|
IsIndoor: (cell & 0xFFFFu) >= 0x0100u,
|
|
IsUnhydratable: false,
|
|
RequiredRenderRadius: (cell & 0xFFFFu) >= 0x0100u ? 0 : 1,
|
|
IsRenderNeighborhoodReady: true,
|
|
AreCompositeTexturesReady: true,
|
|
IsCollisionReady: true);
|
|
}
|