fix(teleport D): cell-march preserves seed landblock id when no resident LB (no more lbX=0 outbound)
BuildCellSetAndPickContaining discarded the bool from TryGetTerrainOrigin — when the current landblock's terrain hadn't been applied yet (priority-apply in flight after a teleport or dungeon exit), blockOrigin was silently set to (0,0,0). The AdjustToOutside/GetOutsideLcoord math treated world-frame sphere coordinates as block-local and marched the cell one landblock per tick in the direction of movement until lbX or lbY underflowed to 0x00. ACE rejected every subsequent move as a failed transition. Fix: honor the bool return. When terrain is unregistered for an OUTDOOR seed (low < 0x0100), return currentCellId verbatim — "no block-local frame → preserve". This mirrors the NO-LANDBLOCK verbatim contract in PhysicsEngine.Resolve and is correct: the cell stays last-known-correct until terrain registers. Indoor seeds are explicitly excluded (blockOrigin is never consumed by the indoor pick path; outdoorPickAllowed=false for indoor seeds). Reproduce + verify via CellMarchLandblockPreservationTests (two new FAILING-before tests: WestEdge and SouthEdge with empty cache, no anchor → lbX/lbY preserved). TeleportFarTownRunawayTests updated: no-anchor path now also preserves (pre-fix it marched south to 0x59; post-fix returns currentCell unchanged). CellTransitFindCellSetTests, Issue112MembershipTests, PhysicsEngineTests: added RegisterTerrain for the streaming-center block (in production it is always resident before outdoor resolves run; tests that used blockOrigin=(0,0,0) as an implicit fallback now register the block explicitly). All 1567 tests pass. Divergence AD-30 added to retail-divergence-register.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
aba882cec6
commit
02f4be72c0
7 changed files with 144 additions and 15 deletions
|
|
@ -742,11 +742,32 @@ public static class CellTransit
|
|||
//
|
||||
// #106: blockOrigin converts the world-frame sphere coords into retail's
|
||||
// block-local frame for the LandDefs lcoord math.
|
||||
//
|
||||
// #145 D (2026-06-22): honor TryGetTerrainOrigin's false return for OUTDOOR
|
||||
// seeds. When the current landblock has not yet been applied (priority-apply
|
||||
// in flight or streaming still warm), blockOrigin=(0,0) is wrong — the pick
|
||||
// treats the world-frame sphere coordinates as if they were block-local and
|
||||
// marches the cell one block per tick until lbX or lbY underflows to 0x00
|
||||
// (the "lbX=0" outbound wire that ACE rejects). "frame not yet authoritative
|
||||
// → preserve verbatim" mirrors the NO-LANDBLOCK contract in PhysicsEngine.Resolve.
|
||||
// Indoor seeds are NOT guarded here because blockOrigin is only consumed by the
|
||||
// outdoor pick path (outdoorPickAllowed=false for indoor seeds); returning early
|
||||
// for indoor seeds would break all interior cell-set builds (regression).
|
||||
// Adaptation (not a direct retail port — retail gets it free via cell-relative
|
||||
// storage); registered as divergence-register row added in this commit.
|
||||
Vector3 blockOrigin;
|
||||
if (carriedBlockOrigin is { } carriedAnchor)
|
||||
{
|
||||
blockOrigin = carriedAnchor;
|
||||
}
|
||||
else
|
||||
cache.CellGraph.TryGetTerrainOrigin(currentCellId, out blockOrigin);
|
||||
{
|
||||
bool terrainResident = cache.CellGraph.TryGetTerrainOrigin(currentCellId, out blockOrigin);
|
||||
// Outdoor seed with no resident terrain: no valid block-local frame → preserve seed verbatim.
|
||||
// Indoor seeds proceed regardless (blockOrigin unused for indoor picks).
|
||||
if (!terrainResident && currentLow < 0x0100u)
|
||||
return currentCellId;
|
||||
}
|
||||
|
||||
// #112 rider: outdoor candidates may win the pick only when retail would
|
||||
// have admitted them — outdoor seeds always; indoor seeds only when a
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue