feat(physics): define deterministic flat collision assets
Add immutable indexed physics and containment BSP records, exact-bit polygon and Setup payloads, separated CellStruct/topology ownership, and iterative positive-before-negative flattening. Reject malformed graphs and ranges, and prove source identity over synthetic edge cases and installed retail DAT samples without cutting production traversal over.
This commit is contained in:
parent
16d182c2f0
commit
d9300c7854
11 changed files with 2094 additions and 21 deletions
104
docs/research/2026-07-25-slice-i2-flat-collision-schema.md
Normal file
104
docs/research/2026-07-25-slice-i2-flat-collision-schema.md
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# Slice I2 — deterministic immutable collision assets
|
||||
|
||||
**Status:** COMPLETE
|
||||
**Parent:** `docs/plans/2026-07-25-modern-runtime-slice-i.md`
|
||||
**Scope:** Core collision storage and preparation only. Production movement,
|
||||
BSP traversal, streaming publication, and package format are unchanged.
|
||||
|
||||
## Result
|
||||
|
||||
Slice I2 defines the immutable representation that will replace parsed
|
||||
collision DBObj graphs after the later shadow and differential gates:
|
||||
|
||||
- physics BSP nodes in deterministic positive-before-negative pre-order;
|
||||
- explicit signed child indices, where `-1` means absent;
|
||||
- one ordered leaf polygon-index stream;
|
||||
- polygon rows with checked vertex ranges and one contiguous vertex stream;
|
||||
- a separate, smaller cell-containment BSP schema;
|
||||
- ordered Setup cylinder/sphere rows and verbatim dimensions;
|
||||
- separate reusable CellStruct geometry and per-EnvCell topology;
|
||||
- direct prepared indices from portals and BSP leaves to polygon rows;
|
||||
- optional GfxObj root bounds and visual bounds.
|
||||
|
||||
All collections are immutable arrays. Per-EnvCell transforms remain
|
||||
publication state and are deliberately absent from reusable CellStruct
|
||||
geometry.
|
||||
|
||||
## Retail and source ordering
|
||||
|
||||
The storage contract is pinned to the existing retail traversal oracle:
|
||||
|
||||
- `BSPTREE::find_collisions` `0x0053A440`
|
||||
- `BSPNODE::find_walkable` `0x0053CC80`
|
||||
- `BSPLEAF::find_walkable` `0x0053D6F0`
|
||||
|
||||
The source graph is flattened iteratively. A stack pushes the negative child
|
||||
before the positive child, so the output records the current node, then its
|
||||
complete positive subtree, then its complete negative subtree. Leaf polygon
|
||||
references stay in their stored order. Polygon-table rows are sorted by ID,
|
||||
which makes output independent of dictionary insertion and bucket order;
|
||||
leaves and portals resolve IDs to direct indices during preparation.
|
||||
|
||||
No plane is reconstructed and no vector is normalized. `Plane`, `Vector3`,
|
||||
sphere, cylinder, Setup-dimension, and visual-bound floats are copied directly.
|
||||
Tests compare all components through `BitConverter.SingleToInt32Bits`.
|
||||
|
||||
## Corruption contracts
|
||||
|
||||
Construction rejects:
|
||||
|
||||
- unsupported BSP node types or child presence inconsistent with the encoded
|
||||
node type;
|
||||
- source cycles and shared child nodes;
|
||||
- flat cycles, shared children, unreachable nodes, and non-pre-order layouts;
|
||||
- child, polygon-index, polygon, or vertex ranges outside their arrays;
|
||||
- missing leaf or portal polygon IDs;
|
||||
- duplicate/unsorted polygon IDs or visible-cell IDs;
|
||||
- polygon key/row-ID disagreement or point-count disagreement;
|
||||
- default immutable arrays and null source rows.
|
||||
|
||||
An empty tree uses root index `-1`. A populated deterministic tree always uses
|
||||
root index `0`.
|
||||
|
||||
## Evidence
|
||||
|
||||
The synthetic suite covers:
|
||||
|
||||
- positive/negative child ordering;
|
||||
- multi-polygon leaf order;
|
||||
- dictionary-order independence;
|
||||
- negative-zero and nontrivial float payload preservation;
|
||||
- source mutation after preparation;
|
||||
- missing IDs, invalid ranges, malformed child patterns, cycles, shared
|
||||
children, and unreachable/non-pre-order shapes;
|
||||
- asymmetric containment trees;
|
||||
- a 20,000-node containment tree without call-stack recursion;
|
||||
- Setup row order and exact dimensions;
|
||||
- portal direct-index resolution and deterministic visible-cell ordering.
|
||||
|
||||
Installed retail DAT coverage:
|
||||
|
||||
- Facility Hub cells `0x8A02016E` and `0x8A02017A`;
|
||||
- Holtburg cottage cell `0xA9B4013F`;
|
||||
- cottage, stair/ramp, and multipart-door GfxObjs `0x01000A2B`,
|
||||
`0x01000AC5`, and `0x010044B5`;
|
||||
- player, wide-low collision-family, and multipart-door Setups `0x02000001`,
|
||||
`0x020019E3`, and `0x020019FF`.
|
||||
|
||||
For every installed sample, tests compare source node type, plane bits,
|
||||
positive/negative child identity, leaf index, solid marker, bounds, polygon
|
||||
order, polygon metadata, vertex bits, Setup shapes, dimensions, and visual
|
||||
bounds.
|
||||
|
||||
Release gates:
|
||||
|
||||
- I2 focused structural/installed-DAT tests: **13 passed**
|
||||
- expanded Slice I graph + flat oracle: **131 passed**
|
||||
- complete Core tests: **3,263 passed / 2 skipped**
|
||||
- `dotnet build AcDream.slnx -c Release --no-restore`: **passed**
|
||||
- complete solution tests: **8,355 passed / 5 skipped**
|
||||
|
||||
There is intentionally no traversal cutover and no new retail divergence in
|
||||
this commit. Slice I3 serializes these records into the package, adds typed
|
||||
prepared collision access, and bakes the complete installed catalog before any
|
||||
flat query can affect gameplay.
|
||||
Loading…
Add table
Add a link
Reference in a new issue