feat(render): S2 chunk 6 — particle emitters draw by their own cell (add_particle_shadow_to_cell)
Owner G2 finding: the purple cloud around an arriving character no longer drew. The server keeps the player Hidden until acdream sends LoginComplete at reveal completion (retail-correct); the Hidden-state script's emitters spawn in the arrival cell and are view-eligible when the world appears, but the walk drew an owner's emitters only through the owner's registry rows, and a hidden owner's shadow is suspended. Retail's CPhysicsObj::add_particle_shadow_to_cell (0x00514a70) gives an emitter one shadow in its OWN current cell, drawn at that cell's turn regardless of the parent's hidden state (add_shadows_to_cells 0x00514aed skips the flood for state & 0x1000). Port: ParticleSystem keeps a per-pass cell -> renderable-handles index (maintained at every renderable/OwnerCellId change) and CopyRenderableEmittersInCell; ParticleRenderer.DrawForCell; the walk draws particles BY CELL at the existing turns (interior CellParticles, landscape LandscapeCellParticles), the events fire for every visited cell, and every owner-union particle path is deleted (UnionOwners/UnionNewOwners for particles, the outdoor drawn-owner dedupe, the executor's owner classification sets, the context ParticleOwnerIds members). The post-replay per-cell pass double-submitted the root flood's emitters and is deleted: an emitter draws once, at its cell's replay turn. AD-117 item 4 becomes a port note (the index lives in the particle system; an emitter is not a physics object in acdream). The temporary [pes-spawn]/[pes-vis] traces are removed and the ACDREAM_DUMP_PLAYSCRIPT row restored. Verified: timed arrival route logs/selfgate-20260903-062522-haze-chunk6, frame h02-arrive-400ms shows the cloud at the character in Facility Hub. Gates (Release): Core 4,987/4,987; Content 214/214; Runtime 1,884/1,884; App hermetic lane 6,760/6,760; App InstalledDat 217 pass / 2 pre-existing #383. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
2d20ee917b
commit
f6b4584bf3
14 changed files with 400 additions and 336 deletions
|
|
@ -18,13 +18,6 @@ internal sealed class RetailPViewRenderer
|
|||
private readonly ClipFrameAssembly _clipAssemblyScratch = new();
|
||||
private readonly RetailPViewFrameResult _frameResultScratch = new();
|
||||
|
||||
private static readonly ClipViewSlice NoClipSlice =
|
||||
new(0, new Vector4(-1f, -1f, 1f, 1f), Array.Empty<Vector4>());
|
||||
private static readonly IReadOnlySet<uint> NoParticleOwners =
|
||||
new HashSet<uint>();
|
||||
|
||||
private readonly HashSet<uint> _cellParticleOwnerScratch = new();
|
||||
|
||||
// MP-Alloc (2026-07-05): DrawInside's drawable-cell set, reused across
|
||||
// frames instead of `new HashSet<uint>(pvFrame.OrderedVisibleCells)` every
|
||||
// call. Every walk consumer reads it synchronously in this frame.
|
||||
|
|
@ -579,38 +572,12 @@ internal sealed class RetailPViewRenderer
|
|||
// building's pre-punch AlphaBarrier drains the farther content
|
||||
// against still-true depth before its punch stamps far-Z.
|
||||
|
||||
// Cell-stage particle owners for the interior root's OWN flood cells
|
||||
// (non-look-in — the walk draws their statics too, via
|
||||
// OnInteriorFloodDrawTurn/EmitCellTurn, so the retired CellStatic
|
||||
// route's cell-particle submission needs the same re-sourcing).
|
||||
// These stay POST-replay: interior emitters draw in the final world
|
||||
// scope where the cell walls already own depth (retail's cell-walk
|
||||
// insertion). Look-in cells get their OWN per-cell union in
|
||||
// DrawBuildingLookInDynamics so a static owner is never submitted
|
||||
// twice.
|
||||
_cellParticleOwnerScratch.Clear();
|
||||
foreach (uint cellId in driver.VisitedCells)
|
||||
{
|
||||
if (driver.LookInCells.Contains(cellId))
|
||||
continue;
|
||||
UnionRecordOwners(_walkWorldData!.GetCellStatics(cellId), _cellParticleOwnerScratch);
|
||||
}
|
||||
if (_cellParticleOwnerScratch.Count > 0)
|
||||
{
|
||||
passes.DrawCellParticles(
|
||||
ctx,
|
||||
new RetailPViewCellSliceContext(0u, NoClipSlice, _cellParticleOwnerScratch));
|
||||
}
|
||||
}
|
||||
|
||||
private static void UnionRecordOwners(
|
||||
Walk.WalkFrameStaticRecords records, HashSet<uint> destination)
|
||||
{
|
||||
foreach (RenderProjectionRecord record in records.Records)
|
||||
{
|
||||
if (record.Source.LocalEntityId != 0)
|
||||
destination.Add(record.Source.LocalEntityId);
|
||||
}
|
||||
// Campaign OVERHAUL S2 chunk 6: an emitter draws ONCE, at its own
|
||||
// cell's turn inside Replay (WalkFrameEventKind.CellParticles fires for
|
||||
// every visited interior cell — root flood and look-in alike), exactly
|
||||
// retail's add_particle_shadow_to_cell (0x00514a70) membership. The
|
||||
// former post-replay per-cell pass double-submitted the root flood's
|
||||
// emitters and is deleted.
|
||||
}
|
||||
|
||||
/// <summary>Campaign FW3.2b-2: the DYNAMICS-only remainder of the old
|
||||
|
|
@ -857,24 +824,9 @@ public sealed class RetailPViewFrameResult
|
|||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scene-particle owners for ONE unclipped landscape-stage submission (the
|
||||
/// union of every outside slice's cone survivors). Mesh alpha for the same
|
||||
/// owners is already queued by the entity routes; retail inserts each
|
||||
/// emitter's polys into the single alpha list once, during its owner cell's
|
||||
/// walk turn, with no portal-view clip.
|
||||
/// </summary>
|
||||
public readonly record struct RetailPViewLandscapeStaticParticleContext(
|
||||
IReadOnlySet<uint> ParticleOwnerIds);
|
||||
|
||||
/// <summary>#131/#132: the late landscape phase's per-slice payload —
|
||||
/// outside-stage dynamics to mesh-draw, plus the particle owners not already
|
||||
/// submitted at a pre-building barrier.</summary>
|
||||
public readonly record struct RetailPViewLandscapeLateSliceContext(
|
||||
ClipViewSlice Slice,
|
||||
IReadOnlyList<WorldEntity> Dynamics);
|
||||
|
||||
public readonly record struct RetailPViewCellSliceContext(
|
||||
uint CellId,
|
||||
ClipViewSlice Slice,
|
||||
IReadOnlySet<uint> ParticleOwnerIds);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue