diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index a60ed6a8..2365ca14 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -5097,6 +5097,7 @@ public sealed class GameWindow : IDisposable // #131 [outstage-pt] probe state (throwaway — strip when #131 closes). private string? _lastOutStagePtSig; private readonly HashSet _outStageUnmatchedScratch = new(); + private readonly HashSet _outStageMatchedScratch = new(); private static System.Numerics.Vector3 SkyPesAnchor( AcDream.Core.World.SkyObjectData obj, @@ -9742,19 +9743,28 @@ public sealed class GameWindow : IDisposable { int matched = 0, attached = 0, unattached = 0; _outStageUnmatchedScratch.Clear(); + _outStageMatchedScratch.Clear(); foreach (var (emitter, _) in _particleSystem.EnumerateLive()) { if (emitter.AttachedObjectId == 0) { unattached++; continue; } attached++; - if (_outdoorSceneParticleEntityIds.Contains(emitter.AttachedObjectId)) matched++; + if (_outdoorSceneParticleEntityIds.Contains(emitter.AttachedObjectId)) + { + matched++; + if (_outStageMatchedScratch.Count < 48) + _outStageMatchedScratch.Add(emitter.AttachedObjectId); + } else if (_outStageUnmatchedScratch.Count < 12) _outStageUnmatchedScratch.Add(emitter.AttachedObjectId); } var unm = new System.Text.StringBuilder(96); foreach (uint id in _outStageUnmatchedScratch) unm.Append(System.FormattableString.Invariant($" 0x{id:X8}")); + var mat = new System.Text.StringBuilder(192); + foreach (uint id in _outStageMatchedScratch) + mat.Append(System.FormattableString.Invariant($" 0x{id:X8}")); string ptSig = System.FormattableString.Invariant( - $"ids={_outdoorSceneParticleEntityIds.Count} attachedEmitters={attached} matched={matched} unattached={unattached} unmatchedIds=[{unm}]"); + $"ids={_outdoorSceneParticleEntityIds.Count} attachedEmitters={attached} matched={matched} unattached={unattached} matchedIds=[{mat}] unmatchedIds=[{unm}]"); if (ptSig != _lastOutStagePtSig) { _lastOutStagePtSig = ptSig; diff --git a/tests/AcDream.App.Tests/Rendering/Issue131SetupProbeTests.cs b/tests/AcDream.App.Tests/Rendering/Issue131SetupProbeTests.cs new file mode 100644 index 00000000..49cca50f --- /dev/null +++ b/tests/AcDream.App.Tests/Rendering/Issue131SetupProbeTests.cs @@ -0,0 +1,69 @@ +using System; +using DatReaderWriter; +using DatReaderWriter.Options; +using Xunit; +using Xunit.Abstractions; +using DatSetup = DatReaderWriter.DBObjs.Setup; +using DatGfxObj = DatReaderWriter.DBObjs.GfxObj; + +namespace AcDream.App.Tests.Rendering; + +/// +/// #131 diagnostic (throwaway): identify the Holtburg portal among the +/// outside-stage setup ids captured by the [outstage] probe, by dumping each +/// candidate setup's parts + bounds from the dat. The portal's setup is the +/// translucent swirl; lamp posts / creatures / signs identify by part shape. +/// +public class Issue131SetupProbeTests +{ + private readonly ITestOutputHelper _out; + public Issue131SetupProbeTests(ITestOutputHelper output) => _out = output; + + [Fact] + public void Diagnostic_DumpOutstageCandidateSetups() + { + var datDir = CornerFloodReplayTests.ResolveDatDir(); + if (datDir is null) { _out.WriteLine("SKIP: dats unavailable"); return; } + using var dats = new DatCollection(datDir, DatAccessType.Read); + + uint[] candidates = + { + 0x020010AC, // 0x7A9B4050 PASS r=11.9 — portal candidate A + 0x02000B8E, // 0x7A9B403B PASS r=11.6 — portal candidate B + 0x020019FF, // many instances (lamp posts?) + 0x02000290, + 0x02000001, // baseline (human?) + 0x02000E08, + }; + + foreach (uint setupId in candidates) + { + var setup = dats.Get(setupId); + if (setup is null) + { + _out.WriteLine(FormattableString.Invariant($"setup 0x{setupId:X8}: NOT FOUND")); + continue; + } + _out.WriteLine(FormattableString.Invariant( + $"setup 0x{setupId:X8}: parts={setup.Parts.Count}")); + int shown = 0; + foreach (uint partId in setup.Parts) + { + if (shown++ >= 4) { _out.WriteLine(" ..."); break; } + var gfx = dats.Get(partId); + if (gfx is null) { _out.WriteLine(FormattableString.Invariant($" part 0x{partId:X8}: not found")); continue; } + var sb = new System.Text.StringBuilder(); + sb.Append(FormattableString.Invariant( + $" part 0x{partId:X8}: polys={gfx.Polygons.Count} verts={gfx.VertexArray.Vertices.Count} surfaces=[")); + int sShown = 0; + foreach (uint surfId in gfx.Surfaces) + { + if (sShown++ >= 6) { sb.Append(" ..."); break; } + sb.Append(FormattableString.Invariant($" 0x{surfId:X8}")); + } + sb.Append(" ]"); + _out.WriteLine(sb.ToString()); + } + } + } +}