checkpoint: preserve cathedral look-in investigation state
This commit is contained in:
parent
c287db8651
commit
572de1ec30
11 changed files with 757 additions and 197 deletions
|
|
@ -110,6 +110,12 @@ public sealed class RetailPViewRenderer
|
|||
private bool? _probeWalkRootPrevOutdoor;
|
||||
private int _probeWalkRootFramesLeft;
|
||||
private ulong _probeWalkRootFrame;
|
||||
private string? _probeLookInState;
|
||||
|
||||
// The parked remote player's authoritative parent cell for the current
|
||||
// cathedral FW4 investigation. This is diagnostic scope only: it changes
|
||||
// no visibility or draw decision.
|
||||
private const uint ProbeCathedralRemoteCellId = 0xF4180112u;
|
||||
|
||||
// Campaign FW3.2b-2: the walk's production world-data registries
|
||||
// (published/retired by LandblockRenderPublisher) plus the per-frame
|
||||
|
|
@ -263,6 +269,7 @@ public sealed class RetailPViewRenderer
|
|||
// runs at append time, not at Replay time), so the world data must
|
||||
// already be rebuilt for this frame before the walk starts.
|
||||
Walk.WalkFrameDriver? walkDriver = null;
|
||||
WalkProductionLeafRenderer? walkLeafRenderer = null;
|
||||
if (walkActive)
|
||||
{
|
||||
Matrix4x4 view = ctx.CameraView;
|
||||
|
|
@ -343,9 +350,12 @@ public sealed class RetailPViewRenderer
|
|||
Action drawExitSeals = () =>
|
||||
DrawWalkExitPortalMasks(ctx, passes, clipAssembly, walkDriver!);
|
||||
|
||||
var leafRenderer = new WalkProductionLeafRenderer(
|
||||
walkLeafRenderer = new WalkProductionLeafRenderer(
|
||||
walkExecutor!, ctx, clipAssembly, clearInteriorDepth, drawExitSeals);
|
||||
walkDriver = new Walk.WalkFrameDriver(walkExecutor!.Dispatcher, leafRenderer, _walkWorldData);
|
||||
walkDriver = new Walk.WalkFrameDriver(
|
||||
walkExecutor!.Dispatcher,
|
||||
walkLeafRenderer,
|
||||
_walkWorldData);
|
||||
|
||||
if (AcDream.Core.Rendering.RenderingDiagnostics.ProbeWalkRootEnabled)
|
||||
{
|
||||
|
|
@ -527,7 +537,8 @@ public sealed class RetailPViewRenderer
|
|||
pvFrame,
|
||||
clipAssembly,
|
||||
viewcone,
|
||||
_lookInFrames,
|
||||
walkActive ? walkDriver!.LookInCellTurns : [],
|
||||
walkActive ? walkDriver : null,
|
||||
outsideStageFlood,
|
||||
ctx.Cells,
|
||||
ctx.AnimatedEntityIds,
|
||||
|
|
@ -539,6 +550,8 @@ public sealed class RetailPViewRenderer
|
|||
frameViewBorrowed = true;
|
||||
frameEntityPasses!.BeginEntityFrame(in frameView);
|
||||
entityFrameOpen = true;
|
||||
if (walkActive)
|
||||
walkLeafRenderer!.BindEntityFrame(in frameView);
|
||||
}
|
||||
|
||||
// The retained scene product is the production object source.
|
||||
|
|
@ -651,6 +664,7 @@ public sealed class RetailPViewRenderer
|
|||
clipAssembly,
|
||||
capturedPartition,
|
||||
capturedViewcone,
|
||||
capturedDriver,
|
||||
capturedPasses,
|
||||
in capturedView);
|
||||
};
|
||||
|
|
@ -666,6 +680,7 @@ public sealed class RetailPViewRenderer
|
|||
clipAssembly,
|
||||
partition,
|
||||
viewcone,
|
||||
walkDriver!,
|
||||
frameEntityPasses,
|
||||
in frameView);
|
||||
}
|
||||
|
|
@ -1404,7 +1419,7 @@ public sealed class RetailPViewRenderer
|
|||
_cellParticleOwnerScratch.Clear();
|
||||
foreach (uint cellId in driver.VisitedCells)
|
||||
{
|
||||
if (_lookInCellIds.Contains(cellId))
|
||||
if (driver.LookInCells.Contains(cellId))
|
||||
continue;
|
||||
UnionRecordOwners(_walkWorldData!.GetCellStatics(cellId), _cellParticleOwnerScratch);
|
||||
}
|
||||
|
|
@ -1431,15 +1446,16 @@ public sealed class RetailPViewRenderer
|
|||
/// split — the walk now draws every STATIC route (see
|
||||
/// <see cref="DrawWalkDrivenStatics"/>); this method keeps ONLY what
|
||||
/// stays on the OLD visibility pipeline per the plan's dual-compute
|
||||
/// split: outdoor-cell unattached particles, LookInObject dynamics + their
|
||||
/// per-cell particles, the late per-slice outside-dynamics/weather loop,
|
||||
/// and the late particle union submission.</summary>
|
||||
/// split: outdoor-cell unattached particles, the late per-slice outside-
|
||||
/// dynamics/weather loop, and the late particle union submission. Look-in
|
||||
/// dynamics and their cell particles are now walk-turn-owned.</summary>
|
||||
private void DrawLandscapeDynamicsPhase(
|
||||
RetailPViewFrameInput ctx,
|
||||
IRetailPViewPassExecutor passes,
|
||||
ClipFrameAssembly clipAssembly,
|
||||
InteriorEntityPartition.Result? partition,
|
||||
ViewconeCuller viewcone,
|
||||
Walk.WalkFrameDriver walkDriver,
|
||||
IRenderFrameEntityPassExecutor? frameEntityPasses,
|
||||
in RenderFrameView frameView)
|
||||
{
|
||||
|
|
@ -1452,8 +1468,10 @@ public sealed class RetailPViewRenderer
|
|||
// (the walk owns its own alpha barriers — WalkFrameDriver.OnBuildingTurn).
|
||||
passes.DrawUnattachedSceneParticles(ctx, outdoorCells: true);
|
||||
|
||||
DrawBuildingLookInDynamics(
|
||||
ctx, passes, clipAssembly, partition, frameEntityPasses, in frameView);
|
||||
// Trace-only now. Look-in dynamics no longer have a late production
|
||||
// phase: WalkFrameDriver replays each packed route at the walk's own
|
||||
// per-cell DrawCells turn, before the enclosing building shell.
|
||||
ProbeBuildingLookInFrames(ctx, passes, walkDriver);
|
||||
|
||||
// LATE phase (per slice): outside-stage dynamics' meshes + weather —
|
||||
// unchanged from DrawLandscapeThroughOutsideView's own late loop.
|
||||
|
|
@ -1527,129 +1545,72 @@ public sealed class RetailPViewRenderer
|
|||
passes.UseIndoorMembershipOnlyRouting();
|
||||
}
|
||||
|
||||
/// <summary>Campaign FW3.2b-2: the DYNAMICS-only remainder of the old
|
||||
/// <see cref="DrawBuildingLookIns"/> — punches, shells, and look-in cell
|
||||
/// STATICS are now walk-owned (<see cref="Walk.WalkFrameDriver"/>'s
|
||||
/// Building/BuildingShell/LookInStatic turns); this method keeps ONLY the
|
||||
/// LookInObject route (now dynamic-classified — see
|
||||
/// <c>RenderScenePViewFrameBuilder.BuildLookInRoutes</c>) and the per-cell
|
||||
/// particle union that route's owners feed, unioned with the walk's
|
||||
/// static owners for that SAME cell (plan §FW3 item 4 — GetCellStatics
|
||||
/// fills the gap the retired CellStatic-route particle submission left
|
||||
/// for look-in cells specifically).</summary>
|
||||
private void DrawBuildingLookInDynamics(
|
||||
/// <summary>ACDREAM_PROBE_WALK_ROOT companion for FW4's surviving
|
||||
/// through-wall dynamic. It compares the now-diagnostic-only legacy
|
||||
/// look-in frames with the production walk's exact look-in set and reports
|
||||
/// the two punch producers separately. Print-only; never participates in
|
||||
/// admission.</summary>
|
||||
private void ProbeBuildingLookInFrames(
|
||||
RetailPViewFrameInput ctx,
|
||||
IRetailPViewPassExecutor passes,
|
||||
ClipFrameAssembly clipAssembly,
|
||||
InteriorEntityPartition.Result? partition,
|
||||
IRenderFrameEntityPassExecutor? frameEntityPasses,
|
||||
in RenderFrameView frameView)
|
||||
Walk.WalkFrameDriver walkDriver)
|
||||
{
|
||||
if (_lookInFrames.Count == 0)
|
||||
if (!AcDream.Core.Rendering.RenderingDiagnostics.ProbeWalkRootEnabled)
|
||||
return;
|
||||
|
||||
int lookInRouteIndex = 0;
|
||||
for (int frameIndex = 0; frameIndex < _lookInFrames.Count; frameIndex++)
|
||||
uint[] walkLookInCells = walkDriver.LookInCells
|
||||
.OrderBy(cellId => cellId)
|
||||
.ToArray();
|
||||
bool legacyHasTarget = _lookInFrames.Any(
|
||||
frame => frame.OrderedVisibleCells.Contains(ProbeCathedralRemoteCellId));
|
||||
bool walkHasTarget = Array.IndexOf(
|
||||
walkLookInCells, ProbeCathedralRemoteCellId) >= 0;
|
||||
string legacyShape = string.Join(
|
||||
";",
|
||||
_lookInFrames.Select((frame, index) =>
|
||||
$"{index}:b{frame.SourceBuildingKey:x8}/lb{frame.SourceBuildingLandblockId:x8}"
|
||||
+ $"/s{frame.ExteriorSeedPortals.Count}/c["
|
||||
+ string.Join(",", frame.OrderedVisibleCells.Select(cell => cell.ToString("x8")))
|
||||
+ "]"));
|
||||
string walkShape = string.Join(",", walkLookInCells.Select(cell => cell.ToString("x8")));
|
||||
int walkPunches = passes is RetailPViewPassExecutor concrete
|
||||
? concrete.WalkLookInPunchCountThisFrame
|
||||
: -1;
|
||||
int legacyPunches = passes is RetailPViewPassExecutor concreteLegacy
|
||||
? concreteLegacy.LegacyLookInPunchCountThisFrame
|
||||
: -1;
|
||||
string state =
|
||||
$"viewer={ctx.ViewerCellId:x8}|root={ctx.RootCell.CellId:x8}"
|
||||
+ $"|phase={AcDream.Core.Rendering.RenderingDiagnostics.WalkRootPhase}"
|
||||
+ $"|legacy={legacyShape}|walk={walkShape}"
|
||||
+ $"|p={walkPunches}/{legacyPunches}";
|
||||
bool emit = state != _probeLookInState || _probeWalkRootFrame % 30 == 0;
|
||||
_probeLookInState = state;
|
||||
if (!emit)
|
||||
return;
|
||||
|
||||
Console.WriteLine(
|
||||
$"[lookin-frame] f={_probeWalkRootFrame} "
|
||||
+ $"viewer=0x{ctx.ViewerCellId:X8} root=0x{ctx.RootCell.CellId:X8} "
|
||||
+ $"phase={AcDream.Core.Rendering.RenderingDiagnostics.WalkRootPhase} "
|
||||
+ $"legacyFrames={_lookInFrames.Count} legacy112={(legacyHasTarget ? 1 : 0)} "
|
||||
+ $"walkLookIn={walkLookInCells.Length} walk112={(walkHasTarget ? 1 : 0)} "
|
||||
+ $"punches=walk:{walkPunches},legacy:{legacyPunches}");
|
||||
for (int index = 0; index < _lookInFrames.Count; index++)
|
||||
{
|
||||
PortalVisibilityFrame frame = _lookInFrames[frameIndex];
|
||||
for (int i = frame.OrderedVisibleCells.Count - 1; i >= 0; i--)
|
||||
{
|
||||
uint cellId = frame.OrderedVisibleCells[i];
|
||||
var clipKey = new LookInClipCell(frameIndex, cellId);
|
||||
if (!clipAssembly.LookInCellToViewSlices.TryGetValue(
|
||||
clipKey,
|
||||
out ClipViewSlice[]? cellSlices)
|
||||
|| cellSlices.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_cellStaticScratch.Clear();
|
||||
if (partition is not null)
|
||||
{
|
||||
foreach (var e in partition.Dynamics)
|
||||
if (e.ParentCellId == cellId)
|
||||
_cellStaticScratch.Add(e);
|
||||
}
|
||||
|
||||
bool cellDrewObjects = false;
|
||||
_cellParticleUnionScratch.Clear();
|
||||
foreach (ClipViewSlice slice in cellSlices)
|
||||
{
|
||||
int routeIndex = lookInRouteIndex++;
|
||||
passes.UseCellPortalViewRouting(cellId, slice);
|
||||
|
||||
if (frameEntityPasses is not null)
|
||||
{
|
||||
RenderFrameRouteOwnerSelector.Replace(
|
||||
_cellParticleOwnerScratch,
|
||||
in frameView,
|
||||
RenderFrameCandidateRoute.LookInObject,
|
||||
routeIndex,
|
||||
cellId);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReplaceOwnerIds(
|
||||
_cellParticleOwnerScratch,
|
||||
_cellStaticScratch);
|
||||
}
|
||||
|
||||
if (frameEntityPasses is not null
|
||||
|| _cellStaticScratch.Count > 0)
|
||||
{
|
||||
_candidateObserver?.ObservePViewBucket(
|
||||
CurrentRenderPViewRoute.LookInObject,
|
||||
routeIndex,
|
||||
cellId,
|
||||
_cellStaticScratch);
|
||||
_oneCell.Clear();
|
||||
_oneCell.Add(cellId);
|
||||
DrawEntityRouteOrLegacy(
|
||||
ctx,
|
||||
passes,
|
||||
frameEntityPasses,
|
||||
in frameView,
|
||||
RenderFrameCandidateRoute.LookInObject,
|
||||
routeIndex,
|
||||
cellId,
|
||||
_cellStaticScratch,
|
||||
_oneCell);
|
||||
|
||||
cellDrewObjects = true;
|
||||
_cellParticleUnionScratch.UnionWith(
|
||||
_cellParticleOwnerScratch);
|
||||
}
|
||||
}
|
||||
|
||||
// The walk already drew this cell's STATIC content
|
||||
// (WalkFrameDriver's LookInStatic turn) but never submits
|
||||
// particles for it — GetCellStatics fills that gap, unioned
|
||||
// with the dynamic route's own owners so ONE
|
||||
// DrawCellParticles call covers both.
|
||||
if (_walkWorldData is not null)
|
||||
{
|
||||
Walk.WalkFrameStaticRecords statics =
|
||||
_walkWorldData.GetCellStatics(cellId);
|
||||
foreach (RenderProjectionRecord record in statics.Records)
|
||||
{
|
||||
if (record.Source.LocalEntityId != 0)
|
||||
{
|
||||
_cellParticleUnionScratch.Add(record.Source.LocalEntityId);
|
||||
cellDrewObjects = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cellDrewObjects)
|
||||
{
|
||||
passes.DrawCellParticles(ctx, new RetailPViewCellSliceContext(
|
||||
cellId, NoClipSlice, _cellParticleUnionScratch));
|
||||
}
|
||||
}
|
||||
|
||||
passes.UseIndoorMembershipOnlyRouting();
|
||||
PortalVisibilityFrame frame = _lookInFrames[index];
|
||||
Console.WriteLine(
|
||||
$"[lookin-frame] f={_probeWalkRootFrame} index={index} "
|
||||
+ $"building=0x{frame.SourceBuildingKey:X8} "
|
||||
+ $"landblock=0x{frame.SourceBuildingLandblockId:X8} "
|
||||
+ $"seeds={frame.ExteriorSeedPortals.Count} "
|
||||
+ $"has112={(frame.OrderedVisibleCells.Contains(ProbeCathedralRemoteCellId) ? 1 : 0)} "
|
||||
+ $"cells=[{string.Join(",", frame.OrderedVisibleCells.Select(cell => $"0x{cell:X8}"))}]");
|
||||
}
|
||||
Console.WriteLine(
|
||||
$"[lookin-frame] f={_probeWalkRootFrame} walkCells=["
|
||||
+ string.Join(",", walkLookInCells.Select(cell => $"0x{cell:X8}"))
|
||||
+ "]");
|
||||
}
|
||||
|
||||
private void DrawLandscapeThroughOutsideView(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue