fix(phys): #112 - remove the non-retail escape-hatch demote from the pick; lateral stab-graph recovery + retail keep-curr
Root cause (oracle: CLandCell::point_in_cell :316941 = terrain-poly only;
find_cell_list null-result keep-curr pc:308788-308825; CEnvCell::
check_building_transit :309827 = sphere_intersects_cell per portal-adjacent
cell): retail KEEPS curr_cell when nothing contains the centre — including
inside a house's containment gaps. Our 6dbbf95 escape hatch instead demoted
any hydrated indoor claim the sphere no longer overlaps to the outdoor
column; at the A9B3 hill cottage's real interior gap this stranded the
player outdoor-classified deep indoors, where re-promotion is portal-
adjacent-only (retail-identical) -> the outdoor flood rendered the interior
transparent (the user's "sometimes transparent" walk).
The hatch's actual target - poisoned (cell, position) SAVES - has been
handled at the SNAP by PhysicsEngine.Resolve's AdjustPosition validation
since #107/#111, so the per-tick pick reverts to retail semantics:
1. lateral recovery first - when the sphere no longer overlaps the claim,
search the claim's stab list for a containing cell (retail
find_visible_child_cell :311444, the same recovery AdjustPosition uses);
the #111 adjacent-claim shape now self-heals laterally (dat-backed test:
pick(seed 0x172) at a 0x171-interior point -> 0x171);
2. else KEEP curr_cell (retail null-result).
Two old tests asserting the hatch demote rewritten to the retail semantics
(tests-can-codify-bugs); P1 retail-golden conformance gates explicitly green
(FindCellListConformance + ThresholdPortalCrossing + CottageDoorway +
CameraCornerSeal = 11/11). New Issue112MembershipTests: the lateral-recovery
fact + a DocumentsResidual fact pinning the remaining at-doorway gap demote
(via the NORMAL outdoor-candidate path; open oracle read = retail's
add_all_outside_cells gate in CEnvCell::find_transit_cells pc:317499 -
sphere-proximity vs graph-reachability). Core 1383 + 4 pre-existing #99
failures + 1 skip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
e9c8a925d2
commit
2d6954ee44
4 changed files with 133 additions and 35 deletions
|
|
@ -621,34 +621,40 @@ public static class CellTransit
|
|||
// null → caller keeps curr_cell).
|
||||
if (outdoorResult != 0u) return outdoorResult;
|
||||
|
||||
// ── #106 gate-2 escape hatch: bogus-indoor-claim recovery ──────────
|
||||
// Restores the #83/A1.7 + #90 verification that lived in
|
||||
// PhysicsEngine.ResolveCellId before the collide-then-pick rewrite
|
||||
// moved membership here: an INDOOR current cell that IS hydrated but
|
||||
// whose CellBSP no longer overlaps ANY part of the foot sphere is a
|
||||
// bogus claim — a corrupt server save pairing an indoor cell with a
|
||||
// position far outside it, or the player walked out through an
|
||||
// unblocked gap. Keeping it wedges everything downstream: the BFS
|
||||
// can't reach an exit portal from a cell the sphere isn't in (no
|
||||
// candidates → frozen), ShadowObjectRegistry's #98 gate reads
|
||||
// "indoor primary" (no object collision anywhere), and there's no
|
||||
// wall BSP and no terrain (void fall). Demote to the outdoor column
|
||||
// under the sphere centre (LandDefs global math — cross-block safe).
|
||||
// ── No containing cell: lateral recovery, then retail keep-curr ────
|
||||
// Retail find_cell_list leaves *result null here and the CALLER KEEPS
|
||||
// curr_cell (pc:308788-308825) — including when the centre sits in a
|
||||
// containment GAP between a house's cell volumes. #112 (2026-06-10):
|
||||
// the A9B3 hill cottage has a real gap inside the house; the 6dbbf95
|
||||
// escape hatch that used to live here demoted such gaps to the
|
||||
// outdoor column, stranding the player outdoor-classified deep inside
|
||||
// the house (outdoor→indoor promotion is portal-adjacent-only, retail-
|
||||
// identical) → the outdoor flood rendered the interior transparent.
|
||||
// The hatch's actual target — poisoned (cell, position) SAVES — is
|
||||
// handled at the SNAP by PhysicsEngine.Resolve's AdjustPosition
|
||||
// validation since #107/#111; mid-session farness cannot arise (the
|
||||
// sphere moves continuously, and real building exits flow through
|
||||
// exterior portals → outside cells enter the candidate array → the
|
||||
// normal outdoorResult path above demotes there, retail-faithfully).
|
||||
//
|
||||
// Sphere-overlap (BSPQuery.SphereIntersectsCellBsp,
|
||||
// pseudo_c:317666→:323267), NOT point-in: a doorway push-back leaves
|
||||
// the centre a few cm outside while the sphere still overlaps — that
|
||||
// must NOT demote (#90's ping-pong). A cell with no hydrated CellBSP
|
||||
// cannot be verified — trust the claim (stale beats null while
|
||||
// streaming hydrates).
|
||||
if (currentLow >= 0x0100u && containingOutdoorId != 0u)
|
||||
// Before keeping a claim whose volume the sphere no longer overlaps,
|
||||
// try the claim's VISIBLE GRAPH for a containing cell (retail
|
||||
// CEnvCell::find_visible_child_cell in stab-list mode :311444 — the
|
||||
// same recovery AdjustPosition uses at :280028): a near-miss claim
|
||||
// one room off self-heals laterally instead of waiting for a doorway.
|
||||
if (currentLow >= 0x0100u)
|
||||
{
|
||||
var cur = cache.GetCellStruct(currentCellId);
|
||||
if (cur?.CellBSP?.Root is not null)
|
||||
{
|
||||
var curLocal = Vector3.Transform(worldSphereCenter, cur.InverseWorldTransform);
|
||||
if (!BSPQuery.SphereIntersectsCellBsp(cur.CellBSP.Root, curLocal, sphereRadius))
|
||||
return containingOutdoorId;
|
||||
{
|
||||
uint recovered = FindVisibleChildCell(
|
||||
cache, currentCellId, worldSphereCenter, useStabList: true);
|
||||
if (recovered != 0u && recovered != currentCellId)
|
||||
return recovered;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue