docs: #334 measured in game — a landblock-spanning object is registered by one sphere

The reach-filter theory I proposed is REFUTED by measurement, and the real
cause is found. Probe evidence committed as 334-neftet-probe.log (8,401 lines,
ACDREAM_PROBE_REACH at b61f5fd4).

Standing INSIDE the formation, the collision system reports inCell=2 exempt=2
reached=0 rejectedReach=0 — two candidates, both the player's own body spheres.
Nothing was rejected because nothing was there. That kills AP-158 as the cause:
the formation is not in the candidate set at all.

The blocking part the user found is what makes it diagnostic. One object does
collide — gfx=0x010046D8, a BSP with objR=69.471, the landblock's baked rock
geometry — and it appears in cells 0x8764000A and 0x87640012 while being absent
from 0x87640011, 0x87640019 and 0x87630018. Same object, same landblock,
present in one cell and missing from the one directly beside it (grid (2,1)
versus (2,0)).

Cause: BuildFloodSpheres derives cell membership from a single bounding sphere
per part. A 69.471 m radius cannot reach every cell of a 192 m landblock, so
cells beyond it get no registration and the player walks through. Retail does
not use a sphere here — calc_cross_cells 0x00515230 routes BSP objects to
find_bbox_cell_list 0x00510fc0 -> calc_cross_cells_static 0x00518160, a walk
over the object's extent.

Recorded explicitly because the null result was misleadable: AP-156 (b52967de)
did NOT fix this and was never going to. AP-156 corrected the sphere's
POSITION; this is about its COVERAGE. Sequential halves of one weakness, not
competing explanations — and without that note the next reader would reasonably
conclude AP-156 had failed.

Process note worth keeping: I proposed the reach filter, and a DAT sweep would
have "confirmed" it by finding exactly the oversized objects I predicted. The
user insisted on measuring in game instead, which produced the opposite answer
in one run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-06 17:56:08 +02:00
parent b61f5fd4fc
commit f0588725cf

View file

@ -10575,7 +10575,58 @@ did **not** resolve it either, which is itself a diagnostic clue (see below).
formations, and no floor above it — jumping over lands you inside/through.
"Solid near the middle, absent at the edges" is the shape to reason from.
### Leading candidate — AP-158 / #333, the broadphase reach filter
### MEASURED IN GAME 2026-08-06 — cause found, and it is NOT the reach filter
**The reach-filter theory is REFUTED.** A live probe (`ACDREAM_PROBE_REACH`,
commit `b61f5fd4`) was run with the user standing in front of, and then inside,
a Neftet formation. Evidence: `334-neftet-probe.log`, 8,401 lines.
Standing inside the formation the collision system reported:
```
[reach-q] cell=0x87640019 inCell=2 exempt=2 reached=0 rejectedReach=0 tested=0 blocked=0
```
**Two candidates, both the player's own body spheres.** Nothing was rejected
because there was nothing to reject — the formation is not in the collision
candidate set at all. `rejectedReach=0` kills AP-158 as the cause here.
**The blocking part the user found is the discriminator.** One object does
collide: `gfx=0x010046D8`, a BSP with `objR=69.471` — the landblock's baked
rock geometry, one object spanning a large area. Its coverage:
| Cell | Rock object present? |
|---|---|
| `0x8764000A`, `0x87640012` | **YES**`tested-collided` / `tested-slid`, player blocked |
| `0x87640011`, `0x87640019`, `0x87630018` | **NO**`inCell=2`, both entries the player |
**Same object, same landblock, present in some cells and absent from directly
adjacent ones.** `0x87640012` is cell index 17 → grid (2,1); `0x87640011` is
index 16 → grid (2,0), immediately beside it and empty.
### Cause: a landblock-spanning object is registered by a single bounding sphere
`ShadowObjectRegistry.BuildFloodSpheres` derives cell membership from one
sphere per part. This object's own radius is **69.471 m** while a landblock is
**192 m** across, so a single sphere cannot geometrically reach every cell the
mesh occupies. Cells beyond its reach receive no registration and the player
walks through.
Retail does not use a sphere here. `CPhysicsObj::calc_cross_cells` @`0x00515230`
routes BSP-bearing objects to `find_bbox_cell_list` @`0x00510fc0`
`calc_cross_cells_static` @`0x00518160`, i.e. a walk over the object's
**extent**, not a single enclosing sphere.
**Relationship to AP-156 (`b52967de`), which did not fix this and was not
expected to:** AP-156 moved the flood sphere to the right *place* (it was
centred on the part origin while sized from the geometry). That was necessary
and is confirmed correct — but the sphere is also the wrong *shape* for objects
whose extent exceeds their own radius. AP-156 fixed position; this issue is
about coverage. Sequential, not alternative.
### Superseded — the original leading candidate, retained for provenance
### Superseded detail — AP-158 / #333, the broadphase reach filter
`TransitionTypes.cs:3898`-ish measures `currPos - obj.Position` (the part
**origin**) against `obj.Radius`, admitting a contact only when the geometry