fix(physics): Phase 2 — pass foot-sphere center to ResolveCellId
Visual test of Phase 2 portal traversal showed walls still didn't block from inside buildings. Diagnosis: ResolveCellId was being called with sp.CheckPos (entity reference, at the feet — world Z=terrain) instead of sp.GlobalSphere[0].Origin (foot sphere center, ~0.5m above terrain). Combined with the +0.02f Z-bump on cached cell origins (for render z-fight prevention), the test position landed at cell-local Z=-0.02 — just below the cell floor — and PointInsideCellBsp correctly reported "outside" for every cell. CheckBuildingTransit never added candidates; player CellId stayed outdoor; indoor cell-BSP collision branch never fired; walls didn't block. Retail's check_building_transit uses sphere.Center (the sphere CENTER, not the entity reference) per the pseudocode at docs/research/acclient_indoor_transitions_pseudocode.md:222-238. Three call sites updated (PhysicsEngine x2 inside ResolveWithTransition; TransitionTypes inside Transition.FindEnvCollisions). Also adds a [check-bldg] diagnostic line to CheckBuildingTransit (gated on the existing ACDREAM_PROBE_INDOOR_BSP flag) so future verification captures show per-portal inside/outside results without needing another diagnostic flag. Spec: docs/superpowers/specs/2026-05-19-indoor-portal-cell-tracking-design.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
702b30a63e
commit
3ffe1e44f6
3 changed files with 22 additions and 5 deletions
|
|
@ -186,11 +186,28 @@ public static class CellTransit
|
||||||
foreach (var portal in building.Portals)
|
foreach (var portal in building.Portals)
|
||||||
{
|
{
|
||||||
var otherCell = cache.GetCellStruct(portal.OtherCellId);
|
var otherCell = cache.GetCellStruct(portal.OtherCellId);
|
||||||
if (otherCell?.CellBSP?.Root is null) continue;
|
if (otherCell?.CellBSP?.Root is null)
|
||||||
|
{
|
||||||
|
if (PhysicsDiagnostics.ProbeIndoorBspEnabled)
|
||||||
|
{
|
||||||
|
string reason = otherCell is null ? "cell not cached" : "CellBSP null";
|
||||||
|
Console.WriteLine(System.FormattableString.Invariant(
|
||||||
|
$"[check-bldg] portal->0x{portal.OtherCellId:X8} skipped: {reason}"));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Sphere center in the OTHER cell's local space.
|
// Sphere center in the OTHER cell's local space.
|
||||||
var localCenter = Vector3.Transform(worldSphereCenter, otherCell.InverseWorldTransform);
|
var localCenter = Vector3.Transform(worldSphereCenter, otherCell.InverseWorldTransform);
|
||||||
if (BSPQuery.PointInsideCellBsp(otherCell.CellBSP.Root, localCenter))
|
bool inside = BSPQuery.PointInsideCellBsp(otherCell.CellBSP.Root, localCenter);
|
||||||
|
|
||||||
|
if (PhysicsDiagnostics.ProbeIndoorBspEnabled)
|
||||||
|
{
|
||||||
|
Console.WriteLine(System.FormattableString.Invariant(
|
||||||
|
$"[check-bldg] portal->0x{portal.OtherCellId:X8} wpos=({worldSphereCenter.X:F3},{worldSphereCenter.Y:F3},{worldSphereCenter.Z:F3}) lpos=({localCenter.X:F3},{localCenter.Y:F3},{localCenter.Z:F3}) inside={inside}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inside)
|
||||||
{
|
{
|
||||||
candidates.Add(portal.OtherCellId);
|
candidates.Add(portal.OtherCellId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -769,7 +769,7 @@ public sealed class PhysicsEngine
|
||||||
|
|
||||||
return new ResolveResult(
|
return new ResolveResult(
|
||||||
sp.CheckPos,
|
sp.CheckPos,
|
||||||
ResolveCellId(sp.CheckPos, sphereRadius, sp.CheckCellId),
|
ResolveCellId(sp.GlobalSphere[0].Origin, sphereRadius, sp.CheckCellId),
|
||||||
onGround,
|
onGround,
|
||||||
collisionNormalValid,
|
collisionNormalValid,
|
||||||
collisionNormal);
|
collisionNormal);
|
||||||
|
|
@ -787,7 +787,7 @@ public sealed class PhysicsEngine
|
||||||
uint partialCellId = sp.CheckCellId != 0 ? sp.CheckCellId : cellId;
|
uint partialCellId = sp.CheckCellId != 0 ? sp.CheckCellId : cellId;
|
||||||
return new ResolveResult(
|
return new ResolveResult(
|
||||||
sp.CheckPos,
|
sp.CheckPos,
|
||||||
ResolveCellId(sp.CheckPos, sphereRadius, partialCellId),
|
ResolveCellId(sp.GlobalSphere[0].Origin, sphereRadius, partialCellId),
|
||||||
partialOnGround,
|
partialOnGround,
|
||||||
collisionNormalValid,
|
collisionNormalValid,
|
||||||
collisionNormal);
|
collisionNormal);
|
||||||
|
|
|
||||||
|
|
@ -1181,7 +1181,7 @@ public sealed class Transition
|
||||||
Vector3 footCenter = sp.GlobalSphere[0].Origin;
|
Vector3 footCenter = sp.GlobalSphere[0].Origin;
|
||||||
float sphereRadius = sp.GlobalSphere[0].Radius;
|
float sphereRadius = sp.GlobalSphere[0].Radius;
|
||||||
|
|
||||||
uint resolvedOutdoorCellId = engine.ResolveCellId(sp.CheckPos, sphereRadius, sp.CheckCellId);
|
uint resolvedOutdoorCellId = engine.ResolveCellId(sp.GlobalSphere[0].Origin, sphereRadius, sp.CheckCellId);
|
||||||
if (resolvedOutdoorCellId != sp.CheckCellId)
|
if (resolvedOutdoorCellId != sp.CheckCellId)
|
||||||
sp.SetCheckPos(sp.CheckPos, resolvedOutdoorCellId);
|
sp.SetCheckPos(sp.CheckPos, resolvedOutdoorCellId);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue