fix(physics): #146 — re-base building collision per landblock apply (lost after portal-in)
Static building/house-wall collision worked on a fresh login to a town but was lost after logging in elsewhere and PORTALING in: the foot-sphere clipped straight through walls while server-spawned doors (own collision) still blocked. Root (capture-confirmed, ACDREAM_PROBE_BUILDING bldOrigin): the building shell BSP's WorldTransform is computed from the streaming-relative origin (origin = (lb − _liveCenter)·192) AT CACHE TIME, and CacheBuilding is idempotent (first-wins per cell). A teleport recenters _liveCenter, but the idempotent guard never re-bases the cached transform — so the shell sat at a stale world offset (login Arwic → portal Holtburg: bldOrigin=(-5488,2149), ~5.5 km from the player at (83,24)), and FindBuildingCollisions never penetrated → result=OK everywhere → no block. Terrain doesn't suffer this because AddLandblock overwrites its WorldOffset on every apply. Fix: clear a landblock's cached buildings at the start of each ApplyLoadedTerrain (PhysicsDataCache.RemoveBuildingsForLandblock), then let the existing loop re-populate fresh with the CURRENT origin — the per-apply re-base terrain already gets, while keeping CacheBuilding's per-cell first-wins within each fresh pass (retail CSortCell::add_building). Also adds bldOrigin to the [bldg-channel] probe. Verified on the exact repro (Arwic login → Holtburg portal → walk into wall): bldOrigin now (107.5,36.0) at the wall (was -5488,2149); channel returns Collided → Slid (block + wall-slide). Suites green: Core 1568(+2 skip), App 468(+2 skip), UI 425, Net 317. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5b3e946b8b
commit
49d743f88a
3 changed files with 34 additions and 1 deletions
|
|
@ -455,6 +455,28 @@ public sealed class PhysicsDataCache
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// #146 (2026-06-24): drop every cached building belonging to a landblock so
|
||||
/// the next <see cref="CacheBuilding"/> pass re-bases their STREAMING-RELATIVE
|
||||
/// <c>WorldTransform</c> against the CURRENT <c>_liveCenter</c>. Without this,
|
||||
/// CacheBuilding's per-cell first-wins guard LOCKS the transform at whatever
|
||||
/// frame it was first cached with; a teleport recenter then leaves the shell
|
||||
/// BSP at a stale world offset (~the source↔dest landblock distance), so the
|
||||
/// foot-sphere walks through where the wall visually is and collision is lost
|
||||
/// (login at Arwic → portal to Holtburg → house walls clip; bldOrigin probed
|
||||
/// ~5.5 km off). Terrain avoids this because <c>AddLandblock</c> overwrites its
|
||||
/// WorldOffset every apply; buildings get the equivalent per-apply re-base via
|
||||
/// the caller clearing-then-repopulating (which keeps first-wins within each
|
||||
/// fresh pass — retail <c>CSortCell::add_building</c> semantics preserved).
|
||||
/// </summary>
|
||||
public void RemoveBuildingsForLandblock(uint landblockId)
|
||||
{
|
||||
uint prefix = landblockId & 0xFFFF0000u;
|
||||
foreach (var key in _buildings.Keys)
|
||||
if ((key & 0xFFFF0000u) == prefix)
|
||||
_buildings.TryRemove(key, out _);
|
||||
}
|
||||
|
||||
public BuildingPhysics? GetBuilding(uint landcellId)
|
||||
=> _buildings.TryGetValue(landcellId, out var b) ? b : null;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue