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>
38 lines
1.5 KiB
C#
38 lines
1.5 KiB
C#
using AcDream.Core.Meshing;
|
|
using Xunit;
|
|
|
|
namespace AcDream.Core.Tests.Meshing;
|
|
|
|
/// <summary>
|
|
/// #79/#93 (2026-07-09) — the Town Network fountain room's only dat-authored
|
|
/// light (Setup 0x02000365, a ceiling fixture) never registered: its sole
|
|
/// visual part is a #136-class runtime-hidden marker, so it flattens to zero
|
|
/// mesh refs, and GameWindow.cs's hydration loop dropped the ENTIRE entity —
|
|
/// light included — whenever meshRefs was empty. Retail's light registration
|
|
/// (CObjCell::add_light, CEnvCell::UnPack) is entirely independent of a
|
|
/// fixture's own mesh visibility; the mesh-empty gate must not also swallow
|
|
/// a Setup's Lights.
|
|
/// </summary>
|
|
public class EntityHydrationRulesTests
|
|
{
|
|
[Fact]
|
|
public void ShouldKeepEntity_NoMeshNoLights_False()
|
|
{
|
|
Assert.False(EntityHydrationRules.ShouldKeepEntity(meshRefCount: 0, setupLightCount: 0));
|
|
}
|
|
|
|
[Fact]
|
|
public void ShouldKeepEntity_NoMeshWithLights_True()
|
|
{
|
|
// The exact fountain-room case: a mesh-less "light attach point" must
|
|
// still survive hydration so its Lights can be registered.
|
|
Assert.True(EntityHydrationRules.ShouldKeepEntity(meshRefCount: 0, setupLightCount: 1));
|
|
}
|
|
|
|
[Fact]
|
|
public void ShouldKeepEntity_HasMesh_TrueRegardlessOfLights()
|
|
{
|
|
Assert.True(EntityHydrationRules.ShouldKeepEntity(meshRefCount: 1, setupLightCount: 0));
|
|
Assert.True(EntityHydrationRules.ShouldKeepEntity(meshRefCount: 3, setupLightCount: 2));
|
|
}
|
|
}
|