feat(rendering): complete current-path render referee

Extend the non-drawing oracle through ordered PView routes, dispatcher visibility and final instance payloads, and accepted retail selection parts. Lifecycle artifacts can now referee the later shadow scene without influencing production visibility or draw decisions.
This commit is contained in:
Erik 2026-07-24 21:28:12 +02:00
parent dbaea19269
commit f9b68f8f2a
11 changed files with 964 additions and 41 deletions

View file

@ -1,6 +1,7 @@
using System.Numerics;
using AcDream.App.Rendering;
using AcDream.App.Rendering.Scene;
using AcDream.App.Rendering.Wb;
using AcDream.Core.World;
namespace AcDream.App.Tests.Rendering;
@ -225,6 +226,143 @@ public sealed class CurrentRenderSceneOracleTests
Assert.Empty(oracle.Projections);
}
[Fact]
public void PViewDigestNamesRouteOrderAndRejectsObjectsOutsidePartition()
{
WorldEntity cellStatic = Entity(
id: 50,
serverGuid: 0,
parentCell: CellA);
WorldEntity dynamic = Entity(
id: 1_000_050,
serverGuid: 0x8000_0050,
parentCell: CellA);
var oracle = new CurrentRenderSceneOracle();
var result = new InteriorEntityPartition.Result();
InteriorEntityPartition.Partition(
result,
new HashSet<uint> { CellA },
new[] { Entry(LandblockA, cellStatic, dynamic) },
oracle);
oracle.BeginPViewFrame();
oracle.ObservePViewBucket(
CurrentRenderPViewRoute.CellStatic,
routeIndex: 0,
CellA,
[cellStatic]);
oracle.ObservePViewBucket(
CurrentRenderPViewRoute.DynamicLast,
routeIndex: 0,
cellId: 0,
[dynamic]);
oracle.CompletePViewFrame();
CurrentRenderSceneOracleSnapshot first = oracle.Snapshot;
oracle.BeginPViewFrame();
oracle.ObservePViewBucket(
CurrentRenderPViewRoute.DynamicLast,
routeIndex: 0,
cellId: 0,
[dynamic]);
oracle.ObservePViewBucket(
CurrentRenderPViewRoute.CellStatic,
routeIndex: 0,
CellA,
[cellStatic]);
oracle.CompletePViewFrame();
CurrentRenderSceneOracleSnapshot second = oracle.Snapshot;
Assert.Equal(2, first.PViewCandidateCount);
Assert.NotEqual(first.PViewDigest, second.PViewDigest);
Assert.Equal(
first.CompletedPViewFrameSequence + 1,
second.CompletedPViewFrameSequence);
oracle.BeginPViewFrame();
InvalidOperationException error = Assert.Throws<InvalidOperationException>(
() => oracle.ObservePViewBucket(
CurrentRenderPViewRoute.CellStatic,
routeIndex: 0,
CellA,
[Entity(51, 0, CellA)]));
Assert.Contains("absent from the current partition", error.Message);
oracle.AbortPViewFrame();
}
[Fact]
public void DispatcherDigestResetsPerFrameAndRecordsAcceptedMeshRefs()
{
WorldEntity entity = Entity(
id: 60,
serverGuid: 0,
parentCell: CellA);
var accepted = new List<(
WorldEntity Entity,
int MeshRefIndex,
uint LandblockId)>
{
(entity, 0, LandblockB),
};
var oracle = new CurrentRenderSceneOracle();
oracle.BeginDispatcherFrame();
oracle.ObserveDispatcherDraw(
WbDrawDispatcher.EntitySet.All,
entitiesWalked: 1,
accepted);
var submission = new CurrentRenderDispatcherSubmission(
VisibleInstanceCount: 3,
ImmediateInstanceCount: 2,
OpaqueGroupCount: 1,
TransparentGroupCount: 1,
TransparentDeferred: true,
Digest: new RenderSceneHash128(101, 202));
oracle.ObserveDispatcherSubmission(in submission);
CurrentRenderSceneOracleSnapshot first = oracle.Snapshot;
Assert.Equal(1uL, first.DispatcherFrameSequence);
Assert.Equal(1, first.DispatcherDrawCount);
Assert.Equal(1, first.DispatcherEntityCount);
Assert.Equal(1, first.DispatcherMeshRefCount);
Assert.Equal(3, first.DispatcherInstanceCount);
Assert.Equal(1, first.DispatcherOpaqueGroupCount);
Assert.Equal(1, first.DispatcherTransparentGroupCount);
CurrentRenderDispatcherFingerprint fingerprint =
Assert.Single(oracle.DispatcherCandidates);
Assert.Equal(LandblockB, fingerprint.TupleLandblockId);
Assert.Equal(LandblockA, fingerprint.CacheLandblockId);
oracle.BeginDispatcherFrame();
CurrentRenderSceneOracleSnapshot reset = oracle.Snapshot;
Assert.Equal(2uL, reset.DispatcherFrameSequence);
Assert.Equal(0, reset.DispatcherDrawCount);
Assert.Equal(0, reset.DispatcherMeshRefCount);
Assert.Empty(oracle.DispatcherCandidates);
Assert.NotEqual(first.DispatcherDigest, reset.DispatcherDigest);
}
[Fact]
public void DispatcherAbortDiscardsIncompleteCandidates()
{
WorldEntity entity = Entity(
id: 70,
serverGuid: 0x8000_0070,
parentCell: CellA);
var oracle = new CurrentRenderSceneOracle();
oracle.BeginDispatcherFrame();
oracle.ObserveDispatcherDraw(
WbDrawDispatcher.EntitySet.All,
entitiesWalked: 1,
[(entity, 0, LandblockA)]);
oracle.AbortDispatcherFrame();
Assert.Equal(1, oracle.Snapshot.AbortedDispatcherFrames);
Assert.Empty(oracle.DispatcherCandidates);
}
private static CurrentRenderProjectionFingerprint CaptureSingle(
WorldEntity entity,
uint landblockId,

View file

@ -1,6 +1,7 @@
using System.Numerics;
using System.Reflection;
using AcDream.App.Rendering;
using AcDream.App.Rendering.Scene;
using AcDream.Core.World;
namespace AcDream.App.Tests.Rendering;
@ -126,6 +127,37 @@ public sealed class RetailPViewPassExecutorTests
Assert.Contains("phantom-objects", executor.Operations);
}
[Fact]
public void DrawInside_referee_records_the_exact_routed_entity_buckets()
{
var oracle = new CurrentRenderSceneOracle();
var renderer = new RetailPViewRenderer(oracle);
using var executor = new RecordingExecutor();
LoadedCell interior = InteriorWithExit(0xA9B40100u);
WorldEntity cellStatic = Entity(20u, parentCellId: interior.CellId);
WorldEntity dynamic = Entity(
21u,
serverGuid: 0x80000021u,
parentCellId: interior.CellId);
renderer.DrawInside(Frame(interior, [cellStatic, dynamic]), executor);
Assert.Equal(1uL, oracle.Snapshot.CompletedPViewFrameSequence);
Assert.Equal(2, oracle.Snapshot.PViewCandidateCount);
Assert.Collection(
oracle.PViewCandidates,
candidate =>
{
Assert.Equal(CurrentRenderPViewRoute.CellStatic, candidate.Route);
Assert.Equal(cellStatic.Id, candidate.Projection.EntityId);
},
candidate =>
{
Assert.Equal(CurrentRenderPViewRoute.DynamicLast, candidate.Route);
Assert.Equal(dynamic.Id, candidate.Projection.EntityId);
});
}
[Fact]
public void DrawInside_interior_root_executes_the_nearby_building_look_in_punch()
{

View file

@ -1,5 +1,6 @@
using System.Numerics;
using AcDream.App.Rendering;
using AcDream.App.Rendering.Scene;
using AcDream.App.Rendering.Selection;
using AcDream.Core.Selection;
using AcDream.Core.World;
@ -68,6 +69,31 @@ public sealed class RetailSelectionSceneTests
Assert.Equal(published.Id, hit.Value.LocalEntityId);
}
[Fact]
public void CurrentPathRefereeRecordsOnlyAcceptedSelectionParts()
{
var oracle = new CurrentRenderSceneOracle();
var scene = CreateScene();
scene.SetCurrentRenderSceneObserver(oracle);
var entity = Entity(localId: 48u, serverGuid: 0x5000_0048u);
Publish(scene, entity);
Assert.Equal(1uL, oracle.Snapshot.CompletedSelectionFrameSequence);
Assert.Equal(1, oracle.Snapshot.SelectionPartCount);
CurrentRenderSelectionFingerprint part =
Assert.Single(oracle.SelectionParts);
Assert.Equal(entity.ServerGuid, part.ServerGuid);
Assert.Equal(entity.Id, part.LocalEntityId);
Assert.Equal(0, part.PartIndex);
Assert.Equal(0x0100_0001u, part.GfxObjId);
scene.BeginFrame();
scene.AbortFrame();
Assert.Equal(1, oracle.Snapshot.AbortedSelectionFrames);
Assert.Empty(oracle.SelectionParts);
}
private static RetailSelectionScene CreateScene(
RetailSelectionLightingPulse? pulse = null)
{