Root-caused via dat-truth inspection, not inference: the A7.L1 visible- cell scoping fix (previous commit) had zero visual effect because the Town Network fountain room (cell 0x00070144) registers ZERO lights of its own — confirmed directly against the dat, not assumed. The room's one dat-authored fixture, Setup 0x02000365 (a ceiling light 5m above the fountain, warm color, intensity 100), has a single visual part that is a #136-class runtime-hidden marker. Flattened mesh ref count: 0. GameWindow 's per-stab hydration loop treated meshRefs.Count==0 as "doesn't exist" and dropped the whole entity before the Setup's Lights were ever read — so a mesh-less "light attach point" fixture, a normal AC dat authoring pattern, could never register. Retail's light registration (add_light, CEnvCell::UnPack) is architecturally independent of a fixture's own mesh visibility. Fix: track the stab's Setup.Lights.Count alongside meshRefs during hydration; keep the entity (with empty MeshRefs — nothing to draw, still something to light) whenever either is nonzero. Extracted the decision into EntityHydrationRules.ShouldKeepEntity (pure, unit-tested) since GameWindow's hydration loop isn't independently testable. Confirmed no downstream consumer assumes MeshRefs.Count >= 1 (WbDrawDispatcher already guards on it before any indexing). Core 2666+2skip / App 741+2skip / UI 425 / Net 385 green. Apparatus: Issue93TownNetworkFountainRoomLightInspectionTests (dat-truth dump, reusable for other rooms in this class). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
33 lines
1.6 KiB
C#
33 lines
1.6 KiB
C#
namespace AcDream.Core.Meshing;
|
|
|
|
/// <summary>
|
|
/// Should a hydrated stab/entity survive when its visual mesh flattens to
|
|
/// zero drawable parts?
|
|
///
|
|
/// <para>
|
|
/// <b>Why this exists (#79/#93, 2026-07-09).</b> A dat-authored "light attach
|
|
/// point" is a Setup whose sole purpose is to carry a <c>Setup.Lights</c>
|
|
/// entry — its own visual part is commonly a #136-class runtime-hidden
|
|
/// marker (degrades to nothing at any real distance, matching retail's
|
|
/// editor-only placement markers). Retail's light registration
|
|
/// (<c>CObjCell::add_light</c>, populated at <c>CEnvCell::UnPack</c>) is
|
|
/// entirely independent of a fixture's own mesh visibility — a mesh-less
|
|
/// carrier still lights the room. The Town Network fountain room's only
|
|
/// light (Setup 0x02000365, a ceiling fixture 5 m above the fountain) never
|
|
/// registered because the mesh-empty gate treated "nothing to draw" as
|
|
/// "nothing exists," dropping the entity — and its Lights — before the
|
|
/// light-registration pass ever saw it.
|
|
/// </para>
|
|
/// </summary>
|
|
public static class EntityHydrationRules
|
|
{
|
|
/// <summary>
|
|
/// True when the entity should still be added to the landblock's entity
|
|
/// set even with zero mesh refs, because it has dat-authored lights to
|
|
/// register. An entity with any mesh is always kept (unchanged from the
|
|
/// pre-existing gate); the entity is dropped only when it has neither
|
|
/// geometry to draw nor lights to register.
|
|
/// </summary>
|
|
public static bool ShouldKeepEntity(int meshRefCount, int setupLightCount)
|
|
=> meshRefCount > 0 || setupLightCount > 0;
|
|
}
|