feat(core): S1 one CellStruct interpretation, installed-DAT scan, retire AP-234

Campaign OVERHAUL S1 chunk B.

- CellMesh.Build's render role is deleted; CellMesh.HasDrawableGeometry
  is the exact predicate (any sides_type candidate whose resolved surface
  passes the built-EnvCell (Surface.Type & 6) != 0 test), and the
  streaming build job consumes it. Core and Content no longer carry two
  CellStruct interpretations.
- Installed-DAT scan over the complete Environment corpus (5,346
  landblocks, 729,888 cells, 8,601,560 polygons, 8,608,746 candidates):
  3,197 old-rule admissions were untextured surfaces the NoPos proxy let
  through; zero new-only; zero unexplained; zero unknown sides values;
  counts pinned as goldens against the contract's DAT hashes.
- Canonical pins: 0xF4180104 has eight ST_DOUBLE clip-map polygons and 44
  drawable side calls; the canonical NoPos surfaces are type 0x11 and are
  constructed but skipped; two independent extractions of all ten
  canonical cells hash identically.
- AP-234 retired from the divergence register (161 active rows) with
  ConstructMesh 0x0059DFA0 / DrawEnvCell 0x0059F170 / DrawMesh 0x0059D4A0.
- StipplingSurfaceEquivalenceTests no longer claims a build-time NoPos
  skip; the cell half is report-only, the building half stays pinned.
- Inventory and policy remarks updated; plan ledger records chunk A and
  the capture kit.

Core Meshing+Conformance 95/95, Content 208/208 (Lane!=Timing,
Lane!=PreparedPackage), App EnvCell/LandblockBuild/Streaming 432/432,
Release solution build 0 warnings / 0 errors.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-09-02 19:11:17 +02:00
parent acf172469e
commit b681717c30
9 changed files with 631 additions and 154 deletions

View file

@ -2110,6 +2110,18 @@ namespace AcDream.App.Rendering.Wb
indexSegments);
}
// OH2/S1 (docs/research/2026-09-01-overhaul/oh2-cellstruct-surface-contract.md
// §3.6 point 5): for a cell-shell mesh (batch.IsCellShell true),
// this dictionary walk groups by (Width,Height,Format) for
// atlas/storage packing only — it is NOT retail's ascending
// source-surface-index subset draw order. The resulting
// `renderBatches` list order is what EnvCellRenderer later
// replays as draw order. Recovering the exact retail order
// requires walking AcDream.Content.CellSurfaceSubsets.
// InAscendingSurfaceOrder(meshData) instead; no consumer does
// that yet (OH7's ordered draw stream is the intended owner) so
// this upload path still does not preserve retail's subset
// order for cell shells.
foreach (var (format, batches) in meshData.TextureBatches)
{
foreach (var batch in batches)

View file

@ -526,9 +526,11 @@ public sealed class LandblockBuildFactory
&& environment.Cells.TryGetValue(envCell.CellStructure, out cellStruct))
{
// Phase A8 (2026-05-28): cells render through EnvCellRenderer, NOT as
// WorldEntities with fake MeshRefs. CellMesh.Build remains the existing
// drawable-geometry predicate; the actual shell placement is now owned
// by this streaming job's EnvCellLandblockBuild transaction.
// WorldEntities with fake MeshRefs. CellMesh.HasDrawableGeometry (OH2/S1
// chunk B, retired CellMesh.Build's render-production role and AP-234's
// NoPos approximation with it) remains the drawable-geometry predicate;
// the actual shell placement is now owned by this streaming job's
// EnvCellLandblockBuild transaction.
// Static objects inside the cell continue to flow through the dispatcher
// as WorldEntity records below — they have real GfxObj MeshRefs that work
// fine; EnvCellRenderer receives only the completed shell transaction.
@ -548,7 +550,7 @@ public sealed class LandblockBuildFactory
var physicsCellTransform = cellTransform;
// PORTAL VISIBILITY: register EVERY cell with a valid cellStruct, regardless
// of whether CellMesh.Build produced drawable sub-meshes. A portals-only
// of whether CellMesh.HasDrawableGeometry reports drawable geometry. A portals-only
// pass-through connector (a ramp / stair / cellar mouth) yields 0 render
// sub-meshes but MUST be in the visibility graph so the flood can traverse it
// to the cells beyond — otherwise the flood lookup-misses the unregistered
@ -560,7 +562,8 @@ public sealed class LandblockBuildFactory
// the render sub-meshes. The +0.02 m render lift is a DRAW concern only and
// is intentionally NOT fed into the visibility transform (#119-residual: the
// lift shifted horizontal portal planes 2 cm, side-culling deck/stair cells).
var cellSubMeshes = AcDream.Core.Meshing.CellMesh.Build(envCell, cellStruct, _dats);
bool hasDrawableGeometry =
AcDream.Core.Meshing.CellMesh.HasDrawableGeometry(envCell, cellStruct, _dats);
envCellBuild.AddCell(
envCellId,
envCell,
@ -569,7 +572,7 @@ public sealed class LandblockBuildFactory
physicsCellTransform,
cellOrigin,
cellTransform,
hasDrawableGeometry: cellSubMeshes.Count > 0);
hasDrawableGeometry: hasDrawableGeometry);
}
}