fix(physics): #31 update outdoor cell id during transition movement

This commit is contained in:
Erik 2026-04-29 22:00:30 +02:00
parent 3be0c8b7c7
commit 9fea9b13ad
5 changed files with 109 additions and 29 deletions

View file

@ -162,6 +162,38 @@ public sealed class PhysicsEngine
return null;
}
/// <summary>
/// Resolve the outdoor cell id that owns a world-space position.
/// Indoor ids are preserved because EnvCell ownership still comes from
/// portal/cell BSP state; outdoor ids are derived from the registered
/// landblock that currently contains the point.
/// </summary>
internal uint ResolveOutdoorCellId(Vector3 worldPos, uint fallbackCellId)
{
if (fallbackCellId == 0)
return 0;
uint fallbackLow = fallbackCellId & 0xFFFFu;
if (fallbackLow >= 0x0100u)
return fallbackCellId;
foreach (var kvp in _landblocks)
{
var lb = kvp.Value;
float localX = worldPos.X - lb.WorldOffsetX;
float localY = worldPos.Y - lb.WorldOffsetY;
if (localX >= 0f && localX < 192f && localY >= 0f && localY < 192f)
{
uint lowCellId = lb.Terrain.ComputeOutdoorCellId(localX, localY);
return (fallbackCellId & 0xFFFF0000u) == 0
? lowCellId
: (kvp.Key & 0xFFFF0000u) | lowCellId;
}
}
return fallbackCellId;
}
/// <summary>
/// Resolve an entity's movement from <paramref name="currentPos"/> by
/// applying <paramref name="delta"/> (XY only) and computing the correct Z
@ -471,7 +503,10 @@ public sealed class PhysicsEngine
bool onGround = ci.ContactPlaneValid
|| transition.ObjectInfo.State.HasFlag(ObjectInfoState.OnWalkable);
return new ResolveResult(sp.CheckPos, sp.CheckCellId, onGround);
return new ResolveResult(
sp.CheckPos,
ResolveOutdoorCellId(sp.CheckPos, sp.CheckCellId),
onGround);
}
// Transition failed (e.g., stuck in corner, too many steps).
@ -483,6 +518,10 @@ public sealed class PhysicsEngine
|| transition.ObjectInfo.State.HasFlag(ObjectInfoState.OnWalkable)
|| isOnGround;
return new ResolveResult(sp.CheckPos, sp.CheckCellId != 0 ? sp.CheckCellId : cellId, partialOnGround);
uint partialCellId = sp.CheckCellId != 0 ? sp.CheckCellId : cellId;
return new ResolveResult(
sp.CheckPos,
ResolveOutdoorCellId(sp.CheckPos, partialCellId),
partialOnGround);
}
}

View file

@ -705,6 +705,10 @@ public sealed class Transition
var sp = SpherePath;
var ci = CollisionInfo;
uint resolvedOutdoorCellId = engine.ResolveOutdoorCellId(sp.CheckPos, sp.CheckCellId);
if (resolvedOutdoorCellId != sp.CheckCellId)
sp.SetCheckPos(sp.CheckPos, resolvedOutdoorCellId);
Vector3 footCenter = sp.GlobalSphere[0].Origin;
float sphereRadius = sp.GlobalSphere[0].Radius;