fix #176 site-A: idempotent static light registration on landblock re-apply - the stacking wash leak

ApplyLoadedTerrainLocked registered every static Setup light per apply, and RegisterOwnedLight appends unconditionally. A landblock can RE-apply without an unload in between (#168 ForceReloadWindow, Far->Near promotion) and static entity ids are deterministic, so each re-apply stacked another copy of the same lights under the same owner - the [seam-ent] x2->x4 growth, invisible to the identity-keyed [seam-blk] probe (stacked copies share one owner identity while intensity multiplies). The wash intensifies over the session and the stacked exact-tie copies destabilize the 128-cap pool selection sort. Fix: UnregisterOwner(entity.Id) before the per-entity register loop - re-apply idempotent, first apply a no-op. The live-spawn path keeps its existing guid-dedup teardown (GameWindow:3134 -> :4679). Suites green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-06 18:47:33 +02:00
parent f10fe4e96c
commit 87cddce24a

View file

@ -7724,6 +7724,15 @@ public sealed class GameWindow : IDisposable
datBundle.Setups.TryGetValue(src, out var datSetup); datBundle.Setups.TryGetValue(src, out var datSetup);
if (datSetup is not null && datSetup.Lights.Count > 0) if (datSetup is not null && datSetup.Lights.Count > 0)
{ {
// #176 site-A light-stacking leak: a landblock can RE-apply
// without an unload in between (#168 ForceReloadWindow, Far→Near
// promotion), and static entity ids are deterministic — so each
// re-apply appended another copy of the same lights under the
// same owner (observed ×2→×4 per session; the wash intensifies
// over time, and the stacked ties destabilize the 128-cap pool
// sort). Clear the owner's previous registration first: the
// re-apply becomes idempotent, and a first apply is a no-op.
_lightingSink.UnregisterOwner(entity.Id);
var loaded = AcDream.Core.Lighting.LightInfoLoader.Load( var loaded = AcDream.Core.Lighting.LightInfoLoader.Load(
datSetup, datSetup,
ownerId: entity.Id, ownerId: entity.Id,