fix(physics): pass cell world-transform to indoor BSP collision
Indoor cell BSP queries at TransitionTypes.cs:1442 were calling BSPQuery.FindCollisions with Quaternion.Identity + defaulted Vector3.Zero worldOrigin. Inside the BSP, Path 3 (step_sphere_down) and Path 4 (land-on-surface) use those params to build the world-space ContactPlane. Result: planes written with D ~ 0 instead of the cell's world floor Z (e.g. -94.02 for Holtburg cottages). 320 corrupt CP writes per Holtburg session per the [cp-write] probe. Fix: decompose cellPhysics.WorldTransform once at the call site, pass the rotation as localToWorld and the translation as worldOrigin. Mirrors the existing correct pattern at :1808 (FindObjCollisions, passes obj.Rotation + obj.Position). Retail oracle: BSPTREE::find_collisions (acclient_2013_pseudo_c.txt:323924) calls Plane::localtoglobal at :323921 before set_contact_plane. Our TransformNormal + TransformVertices + BuildWorldPlane chain is the equivalent — it just needs the right rotation + origin. Spec: docs/superpowers/specs/2026-05-20-indoor-bsp-worldorigin-fix-design.md. Plan: docs/superpowers/plans/2026-05-20-indoor-bsp-worldorigin-fix.md. Evidence: launch-cp-probe.log capture 2026-05-20, [cp-write] probe. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
39d4e6512b
commit
de8ffde4ca
1 changed files with 35 additions and 2 deletions
|
|
@ -1439,6 +1439,38 @@ public sealed class Transition
|
|||
|
||||
// Use the full 6-path BSP dispatcher for retail-faithful collision.
|
||||
// Use pre-resolved polygons (vertices+planes computed at cache time).
|
||||
//
|
||||
// 2026-05-20 (Bug B fix): pass the cell's world rotation +
|
||||
// translation so the BSP's internal find_walkable /
|
||||
// step_sphere_down / Path-4 land write world-space ContactPlanes
|
||||
// (NOT cell-local). The prior call passed Quaternion.Identity
|
||||
// and defaulted worldOrigin = Vector3.Zero — which corrupted
|
||||
// every Path 3 + Path 4 CP write inside an indoor cell with
|
||||
// D ≈ 0 instead of D = -world_floor_Z. Mirrors the existing
|
||||
// correct pattern at the FindObjCollisions call site (~line
|
||||
// 1808: passes obj.Rotation + worldOrigin: obj.Position).
|
||||
//
|
||||
// Retail oracle: BSPTREE::find_collisions (decomp
|
||||
// acclient_2013_pseudo_c.txt:323924) calls Plane::localtoglobal
|
||||
// (:323921) before set_contact_plane. Our TransformNormal +
|
||||
// TransformVertices + BuildWorldPlane chain is the equivalent
|
||||
// — it just needs the right rotation + origin.
|
||||
Quaternion cellRotation;
|
||||
Vector3 cellOrigin;
|
||||
if (!Matrix4x4.Decompose(cellPhysics.WorldTransform, out _, out cellRotation, out cellOrigin))
|
||||
{
|
||||
// Matrix has shear or other non-decomposable parts. EnvCell
|
||||
// WorldTransform is always rigid rotation + translation per
|
||||
// the dat format, so this branch should never fire. Log a
|
||||
// warning + fall back to identity rotation + .Translation
|
||||
// so we degrade to "translation-only" instead of the prior
|
||||
// "both broken".
|
||||
Console.WriteLine(System.FormattableString.Invariant(
|
||||
$"[indoor-bsp] WARN cellPhysics.WorldTransform did not decompose cleanly for cell 0x{sp.CheckCellId:X8} — falling back to identity rotation"));
|
||||
cellRotation = Quaternion.Identity;
|
||||
cellOrigin = cellPhysics.WorldTransform.Translation;
|
||||
}
|
||||
|
||||
var cellState = BSPQuery.FindCollisions(
|
||||
cellPhysics.BSP.Root,
|
||||
cellPhysics.Resolved,
|
||||
|
|
@ -1448,8 +1480,9 @@ public sealed class Transition
|
|||
localCurrCenter,
|
||||
Vector3.UnitZ, // local space Z is up
|
||||
1.0f, // scale = 1.0 for cell geometry
|
||||
Quaternion.Identity,
|
||||
engine); // engine needed for Path 5 step-up
|
||||
cellRotation,
|
||||
engine, // engine needed for Path 5 step-up
|
||||
worldOrigin: cellOrigin);
|
||||
|
||||
if (PhysicsDiagnostics.ProbeIndoorBspEnabled)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue