using System.Collections.Generic; using AcDream.Core.Physics; using DatReaderWriter; using DatReaderWriter.DBObjs; using DatReaderWriter.Enums; using DatReaderWriter.Options; namespace AcDream.Content.Tests; /// /// AP-155 population MEASUREMENT ONLY (contract /// docs/research/2026-08-07-s2-static-sphere-contract.md, "Measurement" /// section) — not a gate. Counts, over the installed client_portal.dat /// Setups (the same dats.GetAllIdsOfType<Setup>() enumeration /// and /// already sweep), how /// many actually REACH the fixed static-publication Sphere emission — i.e. /// 's production dispatch, at /// scale 1, emits ONLY shapes for /// them. That dispatch (not a raw "has Spheres, no CylSpheres" field read) is /// the correct population: a Setup can carry authored Spheres and STILL never /// reach the sphere branch if a physics-BSP part suppresses it (AP-152) — 99 /// of the 3,605 "sphere-only, no cylinder" Setups the reachability sweep /// already counted fall into exactly that trap. /// public sealed class Ap155StaticSpherePopulationMeasurementTests { [Fact] public void InstalledSetups_SphereOnlyStaticPopulation_Measured() { string? datDir = ContentConformanceDats.ResolveDatDir(); if (datDir is null) { Console.WriteLine("SKIP: installed retail DAT directory is unavailable."); return; } using var dats = new DatCollection(datDir, DatAccessType.Read); // Production physics-BSP predicate — same as // InstalledSetupBspPrimitiveDispatchTests / FlatCollisionAssetBuilder.cs:377-380. var physicsBspCache = new Dictionary(); bool HasPhysicsBsp(uint gfxObjId) { if (physicsBspCache.TryGetValue(gfxObjId, out bool cached)) return cached; bool result = dats.Portal.TryGet(gfxObjId, out GfxObj? gfx) && gfx is not null && gfx.Flags.HasFlag(GfxObjFlags.HasPhysics) && gfx.PhysicsBSP?.Root is not null && gfx.VertexArray is not null; physicsBspCache[gfxObjId] = result; return result; } int totalSetups = 0; int sphereOnlyReachable = 0; var samples = new List(); foreach (uint id in dats.GetAllIdsOfType()) { if (!dats.Portal.TryGet(id, out Setup? setup) || setup is null) continue; totalSetups++; // The classifier: production FromSetup output, not raw Setup // fields — this is what a landblock static entity built from // this Setup actually registers. var shapes = ShadowShapeBuilder.FromSetup(setup, 1f, HasPhysicsBsp); if (shapes.Count == 0) continue; bool sphereOnly = true; foreach (var shape in shapes) { if (shape.CollisionType != ShadowCollisionType.Sphere) { sphereOnly = false; break; } } if (!sphereOnly) continue; sphereOnlyReachable++; if (samples.Count < 3) samples.Add(id); } Console.WriteLine("===== AP-155 static-sphere population measurement ====="); Console.WriteLine($"Total installed Setups: {totalSetups}"); Console.WriteLine($"Reach the static Sphere emission (post-fix, production dispatch): {sphereOnlyReachable}"); Console.WriteLine("Three example object ids:"); foreach (uint sample in samples) Console.WriteLine($" 0x{sample:X8}"); Console.WriteLine("========================================================="); // Structural sanity only — this is a measurement, not a gate. Assert.True(totalSetups > 0, "Expected the installed DAT to enumerate at least one Setup."); Assert.True( sphereOnlyReachable > 0, "Expected at least one Setup to reach the static Sphere emission in the installed DAT."); } }