fix(physics): validate retail cell containment roots
This commit is contained in:
parent
7716c2ee89
commit
3e0f3b6206
23 changed files with 429 additions and 197 deletions
|
|
@ -64,8 +64,10 @@ accepted-divergence entries (#96, #49, #50).
|
|||
|
||||
## 2. Adaptation (AD) — 44 active rows
|
||||
|
||||
Recent retirements: AD-3/AD-4 retired 2026-07-31 by the exact loaded-cell
|
||||
availability and null-root containment port; AD-25 retired 2026-07-30 by the
|
||||
Recent retirements: AD-3/AD-4 retired 2026-07-31 by exact active/per-candidate
|
||||
visible-cell availability, full-catalog containment-root validation, and the
|
||||
zero-portals point-in-cell guard (rootless payloads are quarantined; only a
|
||||
missing positive child below a valid root is the inside base case); AD-25 retired 2026-07-30 by the
|
||||
shared `PhysicsObjUpdate.HandleAllCollisions` remote path; AD-11 retired
|
||||
2026-07-23 by the exact low-bit ItemUses predicate; AD-31 retired 2026-07-15
|
||||
by the DAT-authored portal-space viewport. Recent additions and splits:
|
||||
|
|
|
|||
|
|
@ -178,13 +178,18 @@ package schema, bake, DAT reader, collision formula, or render portal graph
|
|||
changed. Evidence:
|
||||
`docs/research/2026-07-26-prepared-indoor-transit-regression.md`.
|
||||
|
||||
**Cell availability semantics (2026-07-31).** Raw and prepared CellStruct
|
||||
publication now retains a `CellPhysics` record even when authored physics or
|
||||
containment roots are empty. Payload absence is the unavailable state; a loaded
|
||||
null/-1 containment root keeps retail's universal-inside BSP base case.
|
||||
Registration-side outdoor floods still add outside cells but skip transit when
|
||||
the active CLandCell is unavailable, then recover through the existing reflood
|
||||
after terrain/cell hydration. No package schema or DAT reader changed.
|
||||
**Cell availability semantics (2026-07-31, corrected after full-catalog
|
||||
audit).** Raw and prepared CellStruct publication retains a `CellPhysics`
|
||||
record when the physics root is empty but requires a valid containment root.
|
||||
The installed 729,888-record raw and prepared catalogs contain zero rootless
|
||||
containment payloads. A malformed null/-1 root is quarantined atomically; the
|
||||
recursive inside base case applies only to a missing positive child below a
|
||||
valid root. Registration-side outdoor floods still add outside cells but skip
|
||||
transit when the active CLandCell is unavailable, and every later outdoor
|
||||
candidate independently requires its own visible landcell before building
|
||||
transit. The existing reflood retries after terrain/cell hydration. Both raw
|
||||
and prepared point-in-cell paths preserve retail's zero-portals guard. No
|
||||
package schema or DAT reader changed.
|
||||
Evidence: `docs/research/2026-07-31-cell-availability-semantics.md`.
|
||||
|
||||
**Retail VFX hook compatibility seam (2026-07-14).** Chorizite.DatReaderWriter
|
||||
|
|
|
|||
|
|
@ -1,26 +1,41 @@
|
|||
# Retail cell availability and null-root containment — 2026-07-31
|
||||
# Retail cell availability and containment-root validation — 2026-07-31
|
||||
|
||||
## Scope
|
||||
|
||||
This note closes divergence rows AD-3 and AD-4. It does not begin AD-6's
|
||||
atomic streaming-generation work.
|
||||
|
||||
The bug was one collapsed state. acdream treated all three of these as
|
||||
“containment unavailable”:
|
||||
The corrected port distinguishes these states:
|
||||
|
||||
1. no visible cell payload is loaded;
|
||||
2. a loaded CellStruct has a null containment root;
|
||||
3. a loaded CellStruct has an authored containment root.
|
||||
2. a malformed raw/prepared payload has no containment root;
|
||||
3. a loaded CellStruct has a valid authored containment root (its physics root
|
||||
may independently be absent).
|
||||
|
||||
Retail distinguishes (1) from (2). A failed visible-cell lookup is
|
||||
unavailable. A loaded CellStruct remains a real cell even when its BSPTREE
|
||||
root is null, and the containment query's null-node base case is inside.
|
||||
Only (3) is published. State (1) remains unavailable and retryable. State (2)
|
||||
is quarantined atomically so a later valid hydration can retry; it must not
|
||||
become a world-wide containing cell.
|
||||
|
||||
## Installed-data audit
|
||||
|
||||
The complete installed EoR catalog and matching prepared package were audited
|
||||
before choosing this invariant:
|
||||
|
||||
- enumerated EnvCells: **729,888**;
|
||||
- raw: 0 missing EnvCells, 0 missing Environments, 0 missing CellStructs,
|
||||
0 null `CellBSP` objects, **0 null `CellBSP.Root`**, 729,888 valid roots;
|
||||
- prepared `acdream.pak`: 0 missing aliases, 0 corrupt payloads,
|
||||
**0 `ContainmentBsp.RootIndex < 0`**, 729,888 valid roots;
|
||||
- 6,940 raw EnvCells have zero portals, so the retail portal-pointer guard is
|
||||
a real catalog path rather than dead defensive code.
|
||||
|
||||
There are therefore no root-null record IDs to preserve in either source.
|
||||
|
||||
## Retail oracle
|
||||
|
||||
`CObjCell::find_cell_list @ 0x0052B4E0` in
|
||||
`docs/research/named-retail/acclient_2013_pseudo_c.txt:308742` establishes the
|
||||
availability gate:
|
||||
availability gates:
|
||||
|
||||
- `CEnvCell::GetVisible` / `CLandCell::GetVisible` resolves the active seed at
|
||||
`0x0052B50C..0x0052B515`;
|
||||
|
|
@ -31,32 +46,47 @@ availability gate:
|
|||
- each later candidate is independently skipped when its stored cell pointer
|
||||
is null at `0x0052B58E`.
|
||||
|
||||
`CCellStruct::point_in_cell @ 0x005338F0` delegates directly to
|
||||
`BSPTREE::point_inside_cell_bsp @ 0x005398C0`. The already-ported graph and
|
||||
flat BSP queries preserve the retail null-root base case: a negative/null root
|
||||
returns true. Root presence is therefore not an availability predicate.
|
||||
`CEnvCell::point_in_cell @ 0x0052C300` first returns false when
|
||||
`this->portals == 0`, then transforms the point and calls
|
||||
`CCellStruct::point_in_cell`.
|
||||
|
||||
`CCellStruct::point_in_cell @ 0x005338F0` calls
|
||||
`BSPTREE::point_inside_cell_bsp @ 0x005398C0`, which immediately invokes
|
||||
`BSPNODE::point_inside_cell_bsp(this->root_node, ...)`. The BSP node method at
|
||||
`0x0053C1F0` dereferences `this` before walking positive children. Only a
|
||||
missing **positive child below a valid root** is the inside terminal case. A
|
||||
missing root is not.
|
||||
|
||||
## Ported behavior
|
||||
|
||||
- `PhysicsDataCache` now publishes a `CellPhysics` record whenever an authored
|
||||
raw or prepared CellStruct payload exists, even if its physics BSP and/or
|
||||
containment BSP root is absent.
|
||||
- `CollisionTraversal.HasCellContainment` tests representation payload
|
||||
availability, not `Root` / `RootIndex`. `PointInsideCell` then lets the
|
||||
graph or flat query return true for the null-root base case.
|
||||
- `PhysicsDataCache` publishes graph, collision, and prepared records only
|
||||
after a valid raw/prepared containment root is present. A missing physics
|
||||
root is retained as a valid non-colliding cell. Invalid containment
|
||||
publication changes no cache, so later hydration can retry.
|
||||
- `CollisionTraversal.HasCellContainment` tests `Root` / `RootIndex`.
|
||||
- Both raw and prepared `EnvCell.PointInCell` paths apply the zero-portals
|
||||
guard before containment. `CellTransit` applies the same guard to its
|
||||
`CellPhysics` representation.
|
||||
- `CellTransit.BuildShadowCellSet` still seeds all overlapped outdoor cells,
|
||||
but skips the transit walk when the active outdoor seed cannot be resolved
|
||||
from `CellGraph`. A separately cached building can no longer promote an
|
||||
object through an unavailable landcell.
|
||||
from `CellGraph`. Every later outdoor candidate independently resolves via
|
||||
`GetVisible` before building transit, so a stale building cannot promote an
|
||||
object through an unavailable adjacent landcell.
|
||||
- The existing reflood lifecycle remains the recovery mechanism. Once terrain
|
||||
or an indoor CellStruct publishes, the next reflood walks the same authored
|
||||
or a valid indoor CellStruct publishes, the next reflood walks the authored
|
||||
portal/building relationships without reconstructing a different rule.
|
||||
|
||||
## Gates
|
||||
|
||||
Focused tests cover raw graph and prepared flat cache publication, absent
|
||||
versus loaded-null-root containment, indoor and outdoor seeds, preservation of
|
||||
outside-cell seeding, suppression of spurious building promotion, and
|
||||
hydration/reflood recovery. Final Release gates passed: Core 4,162 / 1 skipped,
|
||||
Runtime 440 / 0 skipped, App 4,002 / 3 skipped, plus the complete solution
|
||||
build with zero errors.
|
||||
Focused tests cover raw/prepared rootless quarantine and valid retry, valid
|
||||
containment with missing physics, raw/prepared zero-portal parity, indoor and
|
||||
outdoor seeds, preservation of outside-cell seeding, per-candidate adjacent
|
||||
landcell availability, suppression of stale-building promotion, and
|
||||
hydration/reflood recovery. The corrective checkpoint passes:
|
||||
|
||||
- focused cell-availability suite: **54/54**;
|
||||
- Core Release: **4,165 passed / 1 skipped**;
|
||||
- Runtime Release: **440/440**;
|
||||
- App Release: **4,002 passed / 3 skipped**;
|
||||
- complete Release solution: **10,122 passed / 4 skipped**;
|
||||
- `dotnet build AcDream.slnx -c Release`: **0 warnings / 0 errors**.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue