feat(physics): S2 chunk 1b - callers supply the visual part array; installed-DAT comparator
Every production registration now hands ShadowObjectRegistry the object's whole visual part array beside its collision dispatch: static publication (App LandblockPhysicsPublisher and the headless Content twin) through ShadowShapeBuilder.FromStaticRenderParts, live entities (Runtime LiveEntityCollisionBuilder) through the new FromSetupRenderParts, which walks every Setup part with the same physics-sphere-else-drawing-sphere and part-box rule from the PhysicsDataCache Runtime already reaches. Nothing consumes the retail products yet; the App hermetic lane still passes 6,758/6,758. The Lane=InstalledDat comparator registers five real fixtures through the real publication inputs and prints retail CELLARRAY, collision cells, and the old render cells side by side: Facility Hub stair Setup 0x02000623 (7 cells incl. 0x8A02015F/015E), cathedral ramp 0x020009A2 (3 cells, the genuine multi-part case), the #334 Neftet formation (25 cells), and a landblock-edge crosser (6 cells, 2 in the neighbor block). All three answers agree for BSP-bearing objects, as the shared primitive predicts; the divergence chunk 3 expects appears only for decorative non-BSP parts. Core Physics 2,202/2,202; Runtime 1,884/1,884; App hermetic 6,758/6,758; comparator + stair pin 5/5; solution Release build 0 warnings / 0 errors. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
059b8883ab
commit
5a2792d689
7 changed files with 908 additions and 11 deletions
|
|
@ -638,7 +638,7 @@ Update immediately when a slice changes state. Chat is not the ledger.
|
|||
| v1 OH1 | SUPERSEDED | research contracts committed at `5cd4fd2c`/`5d907ae9` (kept, binding) | T0–T3 evidence grammar parked on `quarantine/oh1-evidence-grammar-2026-09-02` | reviews found the grammar a false oracle three times | n/a | n/a | see §15 |
|
||||
| S1 Geometry | **CLOSED — G1 PASSED 2026-09-02** | `oh2-cellstruct-surface-contract.md` (§3.5 arbitrated on the binary) | chunk A `acf17246`; chunk B `b681717c`; hygiene `0840d5fb`; review fixes `e2543d0e`; G1 regression fix `8c6563ca` (segment/batch pairing) + its pin test (next commit) | lead verified both chunks against the named pseudo-C and the paired binary; two Opus lens reviews, 8 findings all verified by the lead and fixed; the review round's own upload-order change desynchronized cell-shell index segments from batches (first G1 launch: magenta/stretched/missing walls in every dungeon) and was root-caused and fixed by the lead before the re-gate | build 0/0; Content 213/213 (incl. PreparedPackage on the recipe-8 pak); Core 4,948/4,948 (one load-sensitive allocation test outside S1 passes alone); Bake 21/21; Launcher.Core 365/365; Runtime 1,884/1,884; App hermetic 6,757/6,757 | **G1 PASS**: Facility Hub stairs/doorways, Holtburg house interior, ordinary dungeon, town portal network all whole with correct materials on `8c6563ca` + recipe 8; cathedral shows the ORIGINAL symptom family (neighbor-cell walls drawn through portals over the room), explicitly outside G1 and carried to S3/S4 | dev pak recipe 8 (597,369,112 B; `acdream.recipe7.pak` kept); TOC delta explained; corpus scan old-only 3,197 (all untextured), new-only 0, unexplained 0 |
|
||||
| Capture | READY | §7 + `tools/walk-oracle/oh/README.md` | scripts committed `ebaa41df` + `14d8fe64`; lead resolved DBObj::m_DID=+0x28 and the cdecl alpha-function conventions; recon attach re-confirms | — | recon dt/x/uf dumps at session start | owner session ~1 h | before S3 |
|
||||
| S2 World graph | IN PROGRESS (planning: ownership map research running) | `oh1-construction-landscape-contract.md` | — | — | — | G2 | seeds in `b3b7d922` |
|
||||
| S2 World graph | IN PROGRESS | `s2-membership-ownership-map.md` (plan packet, `e7ad25a7`) + `oh1-construction-landscape-contract.md` Contracts A/B | chunk 1a `059b8883` (Core: retail CELLARRAY + per-part entries beside the collision flood, zero behavior change); chunk 1b (App/Runtime callers + installed-DAT comparator) in progress | lead corrected 1a's route decision (cylsphere route reads the Setup's collision cylspheres, not the visual part array) before landing | Core Physics 2,202/2,202 after 1a | G2 pending | seeds in `b3b7d922` preserved; topology triplication deferred to S3 |
|
||||
| S3 Walk | PLANNED | built-mesh/world contracts + captures | — | — | — | folded into G3 | |
|
||||
| S4 Depth + alpha | PLANNED | depth/alpha contracts + captures | — | — | — | G3 | retires AP-34 |
|
||||
| S5 Consumers + closeout | PLANNED | landscape contract; AP-232 | — | — | — | G4 | retires AP-117/AP-232; deletes probes |
|
||||
|
|
|
|||
|
|
@ -111,3 +111,116 @@ FacilityStairAssembly_RegisterAcross015FTo015EWithoutCollisionRows`, the
|
|||
and `ShadowShapeBuilder*`, `LiveEntityCollisionBuilderTests`,
|
||||
`LandblockPhysicsPublisherTests`, `Issue334*`, the flood replay fixtures, and
|
||||
the Runtime placement/physics suites (full list in the 2026-09-02 trace).
|
||||
|
||||
## 5. Chunk 1 evidence (2026-09-02, chunk 1b)
|
||||
|
||||
Chunk 1b threaded the whole visual part array through every production
|
||||
`RegisterMultiPart`/`ReplaceMultiPartPayload` caller as a zero-pixel-change
|
||||
side product:
|
||||
|
||||
- `LandblockPhysicsPublisher.PublishStaticEntity` — builds
|
||||
`ShadowShapeBuilder.FromStaticRenderParts(entity.MeshRefs,
|
||||
publication.StagingCache.GetGfxObj, publication.StagingCache.GetVisualBounds,
|
||||
out _)` once per static and passes it as `partArray:` to BOTH the
|
||||
BSP-branch and the Setup cylinder/sphere fallback-branch `RegisterMultiPart`
|
||||
calls. The visual-bounds source is `publication.StagingCache`, the SAME
|
||||
`PhysicsDataCache` `WalkProductionWorldData.ResolveStaticRenderCells`
|
||||
already reads (`cache.GetGfxObj`/`cache.GetVisualBounds`) — no new source
|
||||
was threaded, none was needed.
|
||||
- `LandblockPhysicsContentBuilder.PublishStaticCollision` (the no-window/
|
||||
Headless twin, driven from `HeadlessSessionWorldProjection`) — same
|
||||
treatment, same `cache.GetGfxObj`/`cache.GetVisualBounds` pair.
|
||||
- `LiveEntityCollisionBuilder` — added `ShadowShapeBuilder.FromSetupRenderParts`
|
||||
(Core, mirrors `FromStaticRenderParts`'s per-part dispatch but walks a
|
||||
Setup's parts directly instead of `MeshRef`s, since a live entity has no
|
||||
meshRef list). `LiveEntityCollisionRegistration` gained a `RenderParts`
|
||||
field; `Build()` computes it via two new resolvers
|
||||
(`Func<uint, GfxObjPhysics?> _getGfxObj`, `Func<uint, GfxObjVisualBounds?>
|
||||
_getVisualBounds`) that the public constructor wires to
|
||||
`PhysicsDataCache.GetGfxObj`/`GetVisualBounds` — the identical resolver
|
||||
SHAPE `FromStaticRenderParts` takes, so a static and a live Setup sharing a
|
||||
GfxObj id read the same render geometry. Both new constructor parameters
|
||||
default to a no-op resolver, so every existing 2-arg test fixture keeps its
|
||||
exact prior behavior (`RenderParts` resolves to an empty list, entering
|
||||
`RecomputeRetailCellArray`'s `partArray.Count == 0` early return — a no-op
|
||||
on every dictionary chunk 1a introduced). `Register`/`ReconcileAppearance`
|
||||
pass `partArray: registration.RenderParts` into `RegisterMultiPart`/
|
||||
`ReplaceMultiPartPayload`.
|
||||
- No other production caller exists: a full-source grep for
|
||||
`.RegisterMultiPart(`/`.ReplaceMultiPartPayload(` after this change finds
|
||||
exactly these four call sites (App publisher ×2 branches, Content builder
|
||||
×2 branches, Runtime builder ×2 methods) plus the four in this list — every
|
||||
one now supplies `partArray:`.
|
||||
- Zero-behavior-change proof: App.Tests filtered to the non-InstalledDat
|
||||
lanes still passes exactly 6,758/6,758 (unchanged count), Core.Tests
|
||||
Physics 2,202/2,202, Runtime.Tests 1,884/1,884 — chunk 1b changed no
|
||||
observable production output.
|
||||
|
||||
### Installed-DAT comparator results
|
||||
|
||||
`tests/AcDream.App.Tests/Physics/RetailCellArrayComparatorInstalledDatTests.cs`
|
||||
registers each fixture through the real production dispatch
|
||||
(`ShadowShapeBuilder.FromLandblockBspParts` first, else the Setup
|
||||
CylSphere/Sphere fallback — `LandblockPhysicsPublisher.PublishStaticEntity`'s
|
||||
exact branch order — plus the `FromStaticRenderParts` part array) against a
|
||||
registry backed by the real `PhysicsDataCache`, then reads back retail's
|
||||
CELLARRAY (`TryGetRetailCellArray`), today's COLLISION cells
|
||||
(`GetOwnerCells`), and today's OLD RENDER cells (`ComputeStaticRenderCells`
|
||||
over the identical part array and seed).
|
||||
|
||||
| Fixture | Route | Parts | Retail cells | Collision cells | Old-render cells | Retail == old-render |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1: Facility Hub stair Setup `0x02000623` (parent `0x8A02015F`) | BoundingBox | 1 (single wide part, NOT multi-part — see below) | 7: `0x8A02015F,0x8A0201C1,0x8A02015E,0x8A0201C0,0x8A0201C7,0x8A020141,0x8A020163` | identical | identical | yes (exact set) |
|
||||
| 2: Cathedral ramp Setup `0x020009A2` (resolved parent `0xF4180112`) | BoundingBox | 7 (`0x01001FE8` + six `0x01001FE6` slabs) | 3: `0xF4180112,0xF4180113,0xF4180009` | identical | identical | yes (exact set) |
|
||||
| 3: #334 Neftet formation GfxObj `0x010046D8` (landblock `0x8764`) | BoundingBox | 1 | 25 (5×5 rectangle about landcell (2,2), entirely within `0x8764`) | identical | identical | yes (exact set) |
|
||||
| 4: outdoor landblock-edge crosser, GfxObj `0x010046EB` (landblock `0x8764`, origin (133.38, 183.52)) | BoundingBox | 1 | 6: `0x87640030,0x8764002F,0x87650029,0x87640037,0x87640038,0x87650031` — 2 of 6 in neighbor landblock `0x8765` | identical | identical | yes (exact set) |
|
||||
| 5: multi-part Setup, parts in different cells | — | — | — see note | — | — | — |
|
||||
|
||||
Every fixture reports retail == collision == old-render exactly (same
|
||||
ordered set), zero mismatches. This is a structural consequence of chunk 1a's
|
||||
route logic, not incidental: every one of these statics is BSP-bearing
|
||||
(`hasPhysicsBsp=True`), so `RecomputeRetailCellArray`'s dispatch always takes
|
||||
the `BoundingBox` branch (`CPhysicsObj::find_bbox_cell_list` over the SAME
|
||||
part array, same seed, same `PhysicsDataCache` — the identical primitive
|
||||
`ComputeStaticRenderCells` already calls). A retail-vs-collision difference
|
||||
never appeared for these five fixtures either — the collision dispatch for a
|
||||
BSP-bearing object also flows through the box-walk over the same shapes, so
|
||||
there is no decorative-vs-collision part split to observe here (that
|
||||
divergence needs a fixture with a non-colliding decorative part alongside a
|
||||
colliding one — none of the fixtures required by the plan packet happen to
|
||||
be that shape; it remains open evidence for chunk 3, not a gap in this
|
||||
chunk's coverage).
|
||||
|
||||
Per-cell part-entry counts (`GetRetailPartEntriesInCell`) confirm retail's
|
||||
CELLARRAY-then-part-array insertion order: fixture 1's single part appears
|
||||
once in each of its 7 cells (7 entries total); fixture 2's 7 parts each
|
||||
appear in each of its 3 cells (21 entries total — every part registers in
|
||||
every cell of the entity's CELLARRAY, not a per-part cell subset, matching
|
||||
`CPartArray::AddPartsShadow`'s exact semantics); fixtures 3 and 4's single
|
||||
part appears once per cell.
|
||||
|
||||
**Fixture-1 correction against the plan packet's assumption:** Facility Hub
|
||||
stair Setup `0x02000623` resolves via `SetupMesh.Flatten` to exactly ONE
|
||||
visual part, not several — its own wide vertex-array box spans all 7 crossed
|
||||
cells. It is a wide SINGLE-part static. The genuinely multi-part case (item
|
||||
5, "parts in different cells") is fixture 2, the Cathedral ramp: 7 real
|
||||
parts, whose combined CELLARRAY spans 3 cells, with every part entered in
|
||||
every one of those 3 cells per retail's `AddPartsShadow` semantics — "parts
|
||||
in different cells" is best read as "the entity's CELLARRAY spans multiple
|
||||
cells," not "each part is confined to its own cell" (retail's render index
|
||||
has no such per-part cell subsetting; S3 owns per-part draw admission
|
||||
separately). No installed-DAT fixture with genuinely per-part-confined
|
||||
membership was found among the test files this chunk was pointed at.
|
||||
|
||||
**Fixture-4 note:** the first candidate a bounding-SPHERE-based edge scan
|
||||
picked was fixture 3's own Neftet formation GfxObj `0x010046D8` (69 m sphere
|
||||
radius crosses the landblock's 0 m edge at its 63.78 m origin) — but the
|
||||
outdoor flood's governing geometry is the vertex-array BOX
|
||||
(`CLandCell::add_all_outside_cells` divides the BOX by `square_length`, #334),
|
||||
and that object's real 96 m box (48 m half-width) does not reach the edge
|
||||
from its centered position. The scan was corrected to key on
|
||||
`GfxObjPhysics.VisualBounds` (the box) instead, and to explicitly exclude
|
||||
`0x010046D8` so fixture 4 stays independent of fixture 3; it now resolves to
|
||||
a different Neftet-landblock GfxObj (`0x010046EB`) genuinely near the block's
|
||||
Y=192 edge, producing 2 of 6 retail cells in the neighboring landblock
|
||||
`0x8765`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue