refactor(runtime): own world reveal generation
This commit is contained in:
parent
4ab98b080e
commit
a6860d5563
26 changed files with 1294 additions and 502 deletions
|
|
@ -1,9 +1,13 @@
|
|||
using AcDream.Runtime;
|
||||
using AcDream.Runtime.World;
|
||||
|
||||
namespace AcDream.App.Streaming;
|
||||
|
||||
/// <summary>
|
||||
/// Generation-scoped destination-work seam. The reveal coordinator is the
|
||||
/// canonical owner of login/portal lifetime; the streaming scheduler only
|
||||
/// reserves capacity for the exact generation and destination it is given.
|
||||
/// graphical host for Runtime's canonical login/portal lifetime; the
|
||||
/// streaming scheduler only reserves capacity for the exact generation and
|
||||
/// destination it is given.
|
||||
/// </summary>
|
||||
internal interface IWorldRevealStreamingScheduler
|
||||
{
|
||||
|
|
@ -26,23 +30,23 @@ internal interface IWorldRevealRenderResourceScheduler
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Owns one login/portal reveal lifetime across readiness and lifecycle
|
||||
/// diagnostics. This keeps the destination barrier and its observations on a
|
||||
/// single seam so callers cannot begin, prepare, or evaluate one owner while
|
||||
/// forgetting the other.
|
||||
/// Graphical-host adapter for one canonical Runtime login/portal reveal
|
||||
/// lifetime. App owns render/collision readiness and destination resource
|
||||
/// reservations; Runtime owns generation, destination, materialization,
|
||||
/// simulation availability, completion, and cancellation.
|
||||
/// </summary>
|
||||
internal sealed class WorldRevealCoordinator
|
||||
{
|
||||
private readonly RuntimeWorldTransitState _transit;
|
||||
private readonly WorldRevealReadinessBarrier _readiness;
|
||||
private readonly WorldRevealLifecycleTelemetry _lifecycle;
|
||||
private readonly WorldGenerationQuiescence? _quiescence;
|
||||
private readonly IWorldRevealStreamingScheduler? _streaming;
|
||||
private readonly IWorldRevealRenderResourceScheduler? _renderResources;
|
||||
private long _activeGeneration;
|
||||
private bool _worldSimulationReleased;
|
||||
private long _reservationGeneration;
|
||||
private bool _worldViewportReleased;
|
||||
|
||||
public WorldRevealCoordinator(
|
||||
RuntimeWorldTransitState transit,
|
||||
Func<uint, int, bool> isRenderNeighborhoodReady,
|
||||
Func<uint, bool> isSpawnCellReady,
|
||||
Func<uint, int, bool> isTerrainNeighborhoodReady,
|
||||
|
|
@ -50,11 +54,11 @@ internal sealed class WorldRevealCoordinator
|
|||
Action<uint, int> prepareCompositeTextures,
|
||||
Action invalidateCompositeTextures,
|
||||
Func<uint, bool> isSpawnClaimUnhydratable,
|
||||
Action<string>? log = null,
|
||||
WorldGenerationQuiescence? quiescence = null,
|
||||
IWorldRevealStreamingScheduler? streaming = null,
|
||||
IWorldRevealRenderResourceScheduler? renderResources = null)
|
||||
{
|
||||
_transit = transit ?? throw new ArgumentNullException(nameof(transit));
|
||||
_readiness = new WorldRevealReadinessBarrier(
|
||||
isRenderNeighborhoodReady,
|
||||
isSpawnCellReady,
|
||||
|
|
@ -63,27 +67,28 @@ internal sealed class WorldRevealCoordinator
|
|||
prepareCompositeTextures,
|
||||
invalidateCompositeTextures,
|
||||
isSpawnClaimUnhydratable);
|
||||
_lifecycle = new WorldRevealLifecycleTelemetry(log);
|
||||
_quiescence = quiescence;
|
||||
_streaming = streaming;
|
||||
_renderResources = renderResources;
|
||||
}
|
||||
|
||||
public WorldRevealLifecycleSnapshot Snapshot => _lifecycle.Snapshot;
|
||||
public int PortalMaterializationCount => _lifecycle.PortalMaterializationCount;
|
||||
public bool WaitCueShown => _lifecycle.WaitCueShown;
|
||||
public RuntimePortalSnapshot Snapshot => _transit.Snapshot;
|
||||
public int PortalMaterializationCount =>
|
||||
_transit.Snapshot.PortalMaterializationCount;
|
||||
public bool WaitCueShown => _transit.Snapshot.WaitCueShown;
|
||||
|
||||
public long Begin(WorldRevealKind kind, uint destinationCell)
|
||||
public long Begin(RuntimePortalKind kind, uint destinationCell)
|
||||
{
|
||||
if (destinationCell == 0u)
|
||||
throw new ArgumentOutOfRangeException(nameof(destinationCell));
|
||||
|
||||
WorldGenerationQuiescenceEdge quiescenceEdge =
|
||||
_quiescence?.CaptureBegin() ?? default;
|
||||
_readiness.Begin();
|
||||
long generation = _lifecycle.Begin(kind);
|
||||
_activeGeneration = generation;
|
||||
_worldSimulationReleased = false;
|
||||
long generation = _transit.BeginReveal(kind, destinationCell);
|
||||
_quiescence?.CommitBegin(quiescenceEdge);
|
||||
_reservationGeneration = generation;
|
||||
_worldViewportReleased = false;
|
||||
_quiescence?.Begin(generation);
|
||||
_streaming?.BeginDestinationReservation(
|
||||
generation,
|
||||
destinationCell,
|
||||
|
|
@ -105,7 +110,20 @@ internal sealed class WorldRevealCoordinator
|
|||
public WorldRevealReadinessSnapshot Evaluate(uint destinationCell)
|
||||
{
|
||||
WorldRevealReadinessSnapshot snapshot = _readiness.Evaluate(destinationCell);
|
||||
_lifecycle.ObserveReadiness(snapshot);
|
||||
RuntimePortalSnapshot portal = _transit.Snapshot;
|
||||
if (portal.Generation != 0)
|
||||
{
|
||||
_transit.AcknowledgeDestinationReadiness(
|
||||
new RuntimeDestinationReadiness(
|
||||
portal.Generation,
|
||||
snapshot.DestinationCell,
|
||||
snapshot.IsIndoor,
|
||||
snapshot.IsUnhydratable,
|
||||
snapshot.RequiredRenderRadius,
|
||||
snapshot.IsRenderNeighborhoodReady,
|
||||
snapshot.AreCompositeTexturesReady,
|
||||
snapshot.IsCollisionReady));
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
|
|
@ -122,15 +140,30 @@ internal sealed class WorldRevealCoordinator
|
|||
/// </remarks>
|
||||
public void ObserveMaterialized()
|
||||
{
|
||||
_lifecycle.ObserveMaterialized();
|
||||
ReleaseWorldSimulation();
|
||||
RuntimePortalSnapshot snapshot = _transit.Snapshot;
|
||||
if (snapshot.Generation == 0)
|
||||
return;
|
||||
|
||||
bool wasAvailable = _transit.IsWorldSimulationAvailable;
|
||||
_transit.AcknowledgeMaterialized(
|
||||
snapshot.Generation,
|
||||
snapshot.DestinationCell);
|
||||
ObserveSimulationRelease(wasAvailable);
|
||||
}
|
||||
|
||||
public void ObserveWorldViewportVisible() =>
|
||||
_lifecycle.ObserveWorldViewportVisible();
|
||||
public void ObserveWorldViewportVisible()
|
||||
{
|
||||
long generation = _transit.Snapshot.Generation;
|
||||
if (generation != 0)
|
||||
_transit.AcknowledgeWorldViewportVisible(generation);
|
||||
}
|
||||
|
||||
public bool ObserveWait(TimeSpan elapsed) =>
|
||||
_lifecycle.ObserveWait(elapsed);
|
||||
public bool ObserveWait(TimeSpan elapsed)
|
||||
{
|
||||
long generation = _transit.Snapshot.Generation;
|
||||
return generation != 0
|
||||
&& _transit.ObserveWait(generation, elapsed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the destination streaming/resource reservation at retail's
|
||||
|
|
@ -140,7 +173,7 @@ internal sealed class WorldRevealCoordinator
|
|||
/// </summary>
|
||||
public void RevealWorldViewport()
|
||||
{
|
||||
long generation = _activeGeneration;
|
||||
long generation = _reservationGeneration;
|
||||
if (generation == 0 || _worldViewportReleased)
|
||||
return;
|
||||
|
||||
|
|
@ -151,36 +184,53 @@ internal sealed class WorldRevealCoordinator
|
|||
|
||||
public void Complete()
|
||||
{
|
||||
_lifecycle.Complete();
|
||||
EndLifetime();
|
||||
long generation = _transit.Snapshot.Generation;
|
||||
if (generation == 0)
|
||||
return;
|
||||
|
||||
bool wasAvailable = _transit.IsWorldSimulationAvailable;
|
||||
_transit.Complete(generation);
|
||||
ObserveSimulationRelease(wasAvailable);
|
||||
EndHostLifetime();
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
_lifecycle.Cancel();
|
||||
EndLifetime();
|
||||
}
|
||||
|
||||
private void EndLifetime()
|
||||
{
|
||||
long generation = _activeGeneration;
|
||||
long generation = _transit.Snapshot.Generation;
|
||||
if (generation == 0)
|
||||
return;
|
||||
|
||||
bool wasAvailable = _transit.IsWorldSimulationAvailable;
|
||||
_transit.Cancel(generation);
|
||||
ObserveSimulationRelease(wasAvailable);
|
||||
EndHostLifetime();
|
||||
}
|
||||
|
||||
public void ResetSession()
|
||||
{
|
||||
bool wasAvailable = _transit.IsWorldSimulationAvailable;
|
||||
long generation = _transit.Snapshot.Generation;
|
||||
if (generation != 0)
|
||||
_transit.Cancel(generation);
|
||||
ObserveSimulationRelease(wasAvailable);
|
||||
EndHostLifetime();
|
||||
_transit.ResetSession();
|
||||
}
|
||||
|
||||
private void EndHostLifetime()
|
||||
{
|
||||
long generation = _reservationGeneration;
|
||||
if (generation == 0)
|
||||
return;
|
||||
|
||||
ReleaseWorldSimulation();
|
||||
RevealWorldViewport();
|
||||
_activeGeneration = 0;
|
||||
_worldSimulationReleased = false;
|
||||
_reservationGeneration = 0;
|
||||
_worldViewportReleased = false;
|
||||
}
|
||||
|
||||
private void ReleaseWorldSimulation()
|
||||
private void ObserveSimulationRelease(bool wasAvailable)
|
||||
{
|
||||
long generation = _activeGeneration;
|
||||
if (generation == 0 || _worldSimulationReleased)
|
||||
return;
|
||||
|
||||
_quiescence?.End(generation);
|
||||
_worldSimulationReleased = true;
|
||||
if (!wasAvailable && _transit.IsWorldSimulationAvailable)
|
||||
_quiescence?.ObserveReleased();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue