test(streaming): expose world reveal lifecycle

This commit is contained in:
Erik 2026-07-20 22:32:23 +02:00
parent b60cb67009
commit db45b81f75
6 changed files with 532 additions and 11 deletions

View file

@ -1,5 +1,29 @@
namespace AcDream.App.Streaming;
/// <summary>
/// One evaluation of the destination domains guarded by
/// <see cref="WorldRevealReadinessBarrier"/>. Keeping the individual facts in
/// the canonical owner lets diagnostics and automation observe readiness
/// without duplicating (and eventually drifting from) the reveal predicate.
/// </summary>
internal readonly record struct WorldRevealReadinessSnapshot(
uint DestinationCell,
bool IsIndoor,
bool IsUnhydratable,
int RequiredRenderRadius,
bool IsRenderNeighborhoodReady,
bool AreCompositeTexturesReady,
bool IsCollisionReady)
{
public bool HasDestination => DestinationCell != 0u;
public bool IsReady => HasDestination
&& (IsUnhydratable
|| (IsRenderNeighborhoodReady
&& AreCompositeTexturesReady
&& IsCollisionReady));
}
/// <summary>
/// Joins the render-publication, texture, and collision domains that must be
/// complete before the normal world viewport is revealed. Retail keeps
@ -73,20 +97,46 @@ internal sealed class WorldRevealReadinessBarrier
/// existing loud forced-placement path can expose the invalid server data.
/// </summary>
public bool IsReady(uint destinationCell)
=> Evaluate(destinationCell).IsReady;
/// <summary>
/// Evaluates each readiness domain once and returns the complete decision.
/// Consumers must use this snapshot rather than reimplementing the join.
/// </summary>
public WorldRevealReadinessSnapshot Evaluate(uint destinationCell)
{
if (destinationCell == 0)
return false;
if (_isSpawnClaimUnhydratable(destinationCell))
return true;
return default;
bool isIndoor = IsIndoor(destinationCell);
int radius = RequiredRenderRadius(destinationCell);
if (!_isRenderNeighborhoodReady(destinationCell, radius)
|| !_areCompositeTexturesReady())
return false;
if (_isSpawnClaimUnhydratable(destinationCell))
{
return new WorldRevealReadinessSnapshot(
destinationCell,
isIndoor,
IsUnhydratable: true,
radius,
IsRenderNeighborhoodReady: false,
AreCompositeTexturesReady: false,
IsCollisionReady: false);
}
return IsIndoor(destinationCell)
? _isSpawnCellReady(destinationCell)
: _isTerrainNeighborhoodReady(destinationCell, radius);
bool renderReady = _isRenderNeighborhoodReady(destinationCell, radius);
bool compositesReady = renderReady && _areCompositeTexturesReady();
bool collisionReady = renderReady && compositesReady
&& (isIndoor
? _isSpawnCellReady(destinationCell)
: _isTerrainNeighborhoodReady(destinationCell, radius));
return new WorldRevealReadinessSnapshot(
destinationCell,
isIndoor,
IsUnhydratable: false,
radius,
renderReady,
compositesReady,
collisionReady);
}
private static int RequiredRenderRadius(uint destinationCell) =>