checkpoint(render): G2 owner findings — terrain punch assigned to S4, portal-haze probe

Owner G2 check at 4b0b29e4: Facility Hub PASS, Holtburg house PASS,
cathedral leak unchanged (S3/S4). Two new findings:
- doorway-sized fragments of houses on the terrace below show through
  the hill in Holtburg: PortalDepthMaskRenderer draws every visited cell's
  exit-portal fan with depth compare Always + write, so a doorway behind
  terrain still punches far depth through it. Pre-existing; S4 owns the
  punch (ledger row updated).
- the purple UnHide haze (script type 0x75, played on the retail
  Hidden->visible physics-state edge) no longer shows on the local player
  after a portal. Under investigation: temporary print-only traces
  [pes-spawn]/[pes-vis] under ACDREAM_DUMP_PLAYSCRIPT=1 (launch-options row
  amended; both die with the investigation) and a timed arrival route
  tools/overhaul-selfgate/route-portal-haze.txt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-09-03 05:32:18 +02:00
parent 4b0b29e4cd
commit 7ec72765d7
6 changed files with 69 additions and 7 deletions

View file

@ -63,6 +63,9 @@ public sealed class ParticleHookSink : IAnimationHookSink
public Action<string>? DiagnosticSink { get; set; }
private static readonly bool SpawnTraceEnabled =
Environment.GetEnvironmentVariable("ACDREAM_DUMP_PLAYSCRIPT") == "1";
/// <summary>
/// Diagnostic ownership counts used by lifecycle stress gates. These count
/// the sink's retained bookkeeping, not only emitters still present in the
@ -431,11 +434,19 @@ public sealed class ParticleHookSink : IAnimationHookSink
return;
}
_system.UpdateEmitterOwnerPosition(handle, ownerPosition);
_system.UpdateEmitterOwnerCell(
handle,
_cells is not null && _cells.TryGetCellId(ownerLocalId, out uint cellId)
? cellId
: 0u);
uint ownerCellId = 0u;
bool haveOwnerCell =
_cells is not null && _cells.TryGetCellId(ownerLocalId, out ownerCellId);
_system.UpdateEmitterOwnerCell(handle, haveOwnerCell ? ownerCellId : 0u);
// TEMPORARY (2026-09-03 portal-haze investigation, dies with it):
// print-only, gated on ACDREAM_DUMP_PLAYSCRIPT=1 like the runner.
if (SpawnTraceEnabled)
{
DiagnosticSink?.Invoke(
$"[pes-spawn] emitter=0x{emitterInfoId:X8} owner=0x{ownerLocalId:X8} handle={handle} "
+ $"cell=0x{(haveOwnerCell ? ownerCellId : 0u):X8} "
+ $"hiddenPresentation={_hiddenPresentationOwners.Contains(ownerLocalId)} pass={renderPass}");
}
if (_hiddenPresentationOwners.Contains(ownerLocalId))
{
_system.SetEmitterPresentationVisible(handle, false);

View file

@ -860,11 +860,25 @@ public sealed class ParticleSystem : IParticleSystem
}
}
/// <summary>TEMPORARY (2026-09-03 portal-haze investigation, dies with
/// it): print-only trace of renderable-index flips, wired under
/// <c>ACDREAM_DUMP_PLAYSCRIPT=1</c> beside the hook sink's trace.</summary>
public Action<string>? DiagnosticSink { get; set; }
private static readonly bool DiagEnabled =
Environment.GetEnvironmentVariable("ACDREAM_DUMP_PLAYSCRIPT") == "1";
private void RefreshRenderableIndex(ParticleEmitter emitter, bool wasRenderable)
{
bool isRenderable = IsRenderable(emitter);
if (wasRenderable == isRenderable)
return;
if (DiagEnabled)
DiagnosticSink?.Invoke(
$"[pes-vis] handle={emitter.Handle} owner=0x{emitter.AttachedObjectId:X8} "
+ $"cell=0x{emitter.OwnerCellId:X8} renderable={isRenderable} "
+ $"viewEligible={emitter.ViewEligible} presentationVisible={emitter.PresentationVisible} "
+ $"pass={emitter.RenderPass}");
SortedSet<int> index =
_renderableHandlesByPass[RenderPassIndex(emitter.RenderPass)];