refactor(runtime): own teleport destination correlation
This commit is contained in:
parent
38b3773cb9
commit
6a063a27d4
23 changed files with 1209 additions and 487 deletions
|
|
@ -1,5 +1,7 @@
|
|||
using System.Numerics;
|
||||
using AcDream.App.Streaming;
|
||||
using AcDream.App.World;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Core.Selection;
|
||||
using AcDream.Runtime;
|
||||
using AcDream.Runtime.World;
|
||||
|
|
@ -10,6 +12,7 @@ public sealed class WorldRevealCoordinatorTests
|
|||
{
|
||||
private sealed class State
|
||||
{
|
||||
public RuntimeWorldTransitState Transit { get; private set; } = null!;
|
||||
public bool RenderReady { get; set; }
|
||||
public bool CollisionReady { get; set; }
|
||||
public bool CompositesReady { get; set; }
|
||||
|
|
@ -24,6 +27,7 @@ public sealed class WorldRevealCoordinatorTests
|
|||
{
|
||||
transit ??= new RuntimeWorldTransitState(
|
||||
logs is null ? null : new Action<string>(logs.Add));
|
||||
Transit = transit;
|
||||
return new WorldRevealCoordinator(
|
||||
transit,
|
||||
isRenderNeighborhoodReady: (_, _) => RenderReady,
|
||||
|
|
@ -48,7 +52,7 @@ public sealed class WorldRevealCoordinatorTests
|
|||
var state = new State { CompositesReady = true };
|
||||
WorldRevealCoordinator coordinator = state.Build();
|
||||
|
||||
long generation = coordinator.Begin(RuntimePortalKind.Login, 0x11340021u);
|
||||
long generation = coordinator.BeginLogin(0x11340021u);
|
||||
|
||||
Assert.Equal(1, generation);
|
||||
Assert.Equal(1, state.InvalidateCount);
|
||||
|
|
@ -66,7 +70,7 @@ public sealed class WorldRevealCoordinatorTests
|
|||
CollisionReady = true,
|
||||
};
|
||||
WorldRevealCoordinator coordinator = state.Build();
|
||||
coordinator.Begin(RuntimePortalKind.Login, outdoorCell);
|
||||
coordinator.BeginLogin(outdoorCell);
|
||||
|
||||
WorldRevealReadinessSnapshot first = coordinator.PrepareAndEvaluate(outdoorCell);
|
||||
state.CompositesReady = true;
|
||||
|
|
@ -91,12 +95,16 @@ public sealed class WorldRevealCoordinatorTests
|
|||
CompositesReady = true,
|
||||
};
|
||||
WorldRevealCoordinator coordinator = state.Build(logs);
|
||||
coordinator.Begin(RuntimePortalKind.Portal, outdoorCell);
|
||||
long generation = BeginPortal(
|
||||
coordinator,
|
||||
state.Transit,
|
||||
outdoorCell,
|
||||
sequence: 1);
|
||||
state.CompositesReady = true;
|
||||
|
||||
Assert.True(coordinator.Evaluate(outdoorCell).IsReady);
|
||||
coordinator.ObserveMaterialized();
|
||||
coordinator.ObserveMaterialized();
|
||||
coordinator.ObserveMaterialized(generation, 1, outdoorCell);
|
||||
coordinator.ObserveMaterialized(generation, 1, outdoorCell);
|
||||
coordinator.ObserveWorldViewportVisible();
|
||||
coordinator.Complete();
|
||||
|
||||
|
|
@ -108,6 +116,40 @@ public sealed class WorldRevealCoordinatorTests
|
|||
Assert.Single(logs, line => line.Contains("event=materialized", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PortalBegin_WrongSequenceOrCellCannotAcquireHostResources()
|
||||
{
|
||||
const uint destinationCell = 0x3032001Cu;
|
||||
var state = new State { CompositesReady = true };
|
||||
var scheduler = new RecordingDestinationScheduler();
|
||||
WorldRevealCoordinator coordinator = state.Build(streaming: scheduler);
|
||||
RuntimeWorldTransitTestDriver.AcceptPortalDestination(
|
||||
state.Transit,
|
||||
destinationCell,
|
||||
sequence: 7);
|
||||
|
||||
Assert.False(coordinator.TryBeginPortal(
|
||||
8,
|
||||
destinationCell,
|
||||
out _));
|
||||
Assert.False(coordinator.TryBeginPortal(
|
||||
7,
|
||||
0x11340021u,
|
||||
out _));
|
||||
Assert.Empty(scheduler.Begins);
|
||||
Assert.Equal(0, state.InvalidateCount);
|
||||
Assert.Equal(0, coordinator.Snapshot.Generation);
|
||||
|
||||
Assert.True(coordinator.TryBeginPortal(
|
||||
7,
|
||||
destinationCell,
|
||||
out long generation));
|
||||
Assert.Equal(
|
||||
(generation, destinationCell, 1),
|
||||
Assert.Single(scheduler.Begins));
|
||||
Assert.Equal(1, state.InvalidateCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Cancel_PreventsLateDestinationWorkFromMutatingLifecycle()
|
||||
{
|
||||
|
|
@ -118,11 +160,18 @@ public sealed class WorldRevealCoordinatorTests
|
|||
CompositesReady = true,
|
||||
};
|
||||
WorldRevealCoordinator coordinator = state.Build();
|
||||
coordinator.Begin(RuntimePortalKind.Portal, 0x11340021u);
|
||||
long generation = BeginPortal(
|
||||
coordinator,
|
||||
state.Transit,
|
||||
0x11340021u,
|
||||
sequence: 1);
|
||||
coordinator.Cancel();
|
||||
|
||||
coordinator.PrepareAndEvaluate(0x11340021u);
|
||||
coordinator.ObserveMaterialized();
|
||||
coordinator.ObserveMaterialized(
|
||||
generation,
|
||||
1,
|
||||
0x11340021u);
|
||||
coordinator.ObserveWorldViewportVisible();
|
||||
coordinator.Complete();
|
||||
|
||||
|
|
@ -155,14 +204,22 @@ public sealed class WorldRevealCoordinatorTests
|
|||
isSpawnClaimUnhydratable: _ => false,
|
||||
quiescence: quiescence);
|
||||
|
||||
Assert.Equal(1, coordinator.Begin(RuntimePortalKind.Login, 0x11340021u));
|
||||
Assert.Equal(2, coordinator.Begin(RuntimePortalKind.Portal, 0x11340021u));
|
||||
Assert.Equal(1, coordinator.BeginLogin(0x11340021u));
|
||||
long generation = BeginPortal(
|
||||
coordinator,
|
||||
transit,
|
||||
0x11340021u,
|
||||
sequence: 1);
|
||||
Assert.Equal(2, generation);
|
||||
Assert.False(availability.IsWorldAvailable);
|
||||
Assert.Equal(2, availability.QuiescedGeneration);
|
||||
Assert.Equal(1, audio.SuspendCalls);
|
||||
|
||||
Assert.True(coordinator.Evaluate(0x11340021u).IsReady);
|
||||
coordinator.ObserveMaterialized();
|
||||
coordinator.ObserveMaterialized(
|
||||
generation,
|
||||
1,
|
||||
0x11340021u);
|
||||
coordinator.Complete();
|
||||
|
||||
Assert.True(availability.IsWorldAvailable);
|
||||
|
|
@ -193,14 +250,21 @@ public sealed class WorldRevealCoordinatorTests
|
|||
isSpawnClaimUnhydratable: _ => false,
|
||||
quiescence: quiescence,
|
||||
streaming: scheduler);
|
||||
long generation = coordinator.Begin(
|
||||
RuntimePortalKind.Portal,
|
||||
0x3032001Cu);
|
||||
const uint destinationCell = 0x3032001Cu;
|
||||
const ushort teleportSequence = 1;
|
||||
long generation = BeginPortal(
|
||||
coordinator,
|
||||
transit,
|
||||
destinationCell,
|
||||
teleportSequence);
|
||||
|
||||
Assert.False(availability.IsWorldAvailable);
|
||||
Assert.True(coordinator.Evaluate(0x3032001Cu).IsReady);
|
||||
Assert.True(coordinator.Evaluate(destinationCell).IsReady);
|
||||
|
||||
coordinator.ObserveMaterialized();
|
||||
coordinator.ObserveMaterialized(
|
||||
generation,
|
||||
teleportSequence,
|
||||
destinationCell);
|
||||
|
||||
Assert.True(availability.IsWorldAvailable);
|
||||
Assert.False(coordinator.Snapshot.WorldViewportObserved);
|
||||
|
|
@ -259,13 +323,21 @@ public sealed class WorldRevealCoordinatorTests
|
|||
() => calls.Add("spatial")),
|
||||
availability);
|
||||
|
||||
coordinator.Begin(RuntimePortalKind.Portal, 0x3032001Cu);
|
||||
const uint destinationCell = 0x3032001Cu;
|
||||
long generation = BeginPortal(
|
||||
coordinator,
|
||||
transit,
|
||||
destinationCell,
|
||||
sequence: 1);
|
||||
frame.Tick(1f / 60f);
|
||||
Assert.Equal(["network", "commands"], calls);
|
||||
|
||||
calls.Clear();
|
||||
Assert.True(coordinator.Evaluate(0x3032001Cu).IsReady);
|
||||
coordinator.ObserveMaterialized();
|
||||
Assert.True(coordinator.Evaluate(destinationCell).IsReady);
|
||||
coordinator.ObserveMaterialized(
|
||||
generation,
|
||||
1,
|
||||
destinationCell);
|
||||
frame.Tick(1f / 60f);
|
||||
|
||||
Assert.Equal(["objects", "network", "commands", "spatial"], calls);
|
||||
|
|
@ -297,9 +369,11 @@ public sealed class WorldRevealCoordinatorTests
|
|||
isSpawnClaimUnhydratable: _ => false,
|
||||
quiescence: quiescence,
|
||||
streaming: scheduler);
|
||||
long generation = coordinator.Begin(
|
||||
RuntimePortalKind.Portal,
|
||||
0x3032001Cu);
|
||||
long generation = BeginPortal(
|
||||
coordinator,
|
||||
transit,
|
||||
0x3032001Cu,
|
||||
sequence: 1);
|
||||
|
||||
coordinator.ResetSession();
|
||||
|
||||
|
|
@ -317,12 +391,17 @@ public sealed class WorldRevealCoordinatorTests
|
|||
var scheduler = new RecordingDestinationScheduler();
|
||||
WorldRevealCoordinator coordinator = state.Build(streaming: scheduler);
|
||||
|
||||
long first = coordinator.Begin(
|
||||
RuntimePortalKind.Portal,
|
||||
0x11340021u);
|
||||
long second = coordinator.Begin(
|
||||
RuntimePortalKind.Portal,
|
||||
0x20210123u);
|
||||
long first = BeginPortal(
|
||||
coordinator,
|
||||
state.Transit,
|
||||
0x11340021u,
|
||||
sequence: 1);
|
||||
state.Transit.EndTeleport();
|
||||
long second = BeginPortal(
|
||||
coordinator,
|
||||
state.Transit,
|
||||
0x20210123u,
|
||||
sequence: 2);
|
||||
|
||||
Assert.Equal(
|
||||
[
|
||||
|
|
@ -342,12 +421,17 @@ public sealed class WorldRevealCoordinatorTests
|
|||
WorldRevealCoordinator coordinator =
|
||||
state.Build(renderResources: resources);
|
||||
|
||||
long first = coordinator.Begin(
|
||||
RuntimePortalKind.Portal,
|
||||
0x11340021u);
|
||||
long second = coordinator.Begin(
|
||||
RuntimePortalKind.Portal,
|
||||
0x20210123u);
|
||||
long first = BeginPortal(
|
||||
coordinator,
|
||||
state.Transit,
|
||||
0x11340021u,
|
||||
sequence: 1);
|
||||
state.Transit.EndTeleport();
|
||||
long second = BeginPortal(
|
||||
coordinator,
|
||||
state.Transit,
|
||||
0x20210123u,
|
||||
sequence: 2);
|
||||
|
||||
Assert.Equal([first, second], resources.Begins);
|
||||
coordinator.RevealWorldViewport();
|
||||
|
|
@ -356,6 +440,33 @@ public sealed class WorldRevealCoordinatorTests
|
|||
Assert.Equal([second], resources.Ends);
|
||||
}
|
||||
|
||||
private static long BeginPortal(
|
||||
WorldRevealCoordinator coordinator,
|
||||
RuntimeWorldTransitState transit,
|
||||
uint destinationCell,
|
||||
ushort sequence)
|
||||
{
|
||||
Assert.True(transit.TryQueueTeleportStart(sequence));
|
||||
Assert.True(transit.ActivateQueuedTeleport());
|
||||
Assert.True(transit.OfferTeleportDestination(
|
||||
new RuntimeTeleportDestination(
|
||||
EntityGuid: 0x50000001u,
|
||||
InstanceSequence: 1,
|
||||
PositionSequence: 1,
|
||||
TeleportSequence: sequence,
|
||||
ForcePositionSequence: 1,
|
||||
Position: new Position(
|
||||
destinationCell,
|
||||
Vector3.Zero,
|
||||
Quaternion.Identity)),
|
||||
teleportTimestampAdvanced: true));
|
||||
Assert.True(coordinator.TryBeginPortal(
|
||||
sequence,
|
||||
destinationCell,
|
||||
out long generation));
|
||||
return generation;
|
||||
}
|
||||
|
||||
private sealed class RecordingAudioQuiescence : AcDream.App.Audio.IWorldAudioQuiescence
|
||||
{
|
||||
public int SuspendCalls { get; private set; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue