fix(physics): hold retail cell across inner retries
This commit is contained in:
parent
67d1e9b331
commit
4ca7230b36
4 changed files with 168 additions and 83 deletions
|
|
@ -385,33 +385,97 @@ public sealed class PhysicsEngine
|
|||
float localX = worldX - lb.WorldOffsetX;
|
||||
float localY = worldY - lb.WorldOffsetY;
|
||||
if (localX >= 0f && localX < 192f && localY >= 0f && localY < 192f)
|
||||
{
|
||||
var sample = lb.Terrain.SampleSurfacePolygon(localX, localY);
|
||||
var vertices = new TerrainTriangleVertices(
|
||||
OffsetTerrainVertex(sample.Vertices.V0, lb),
|
||||
OffsetTerrainVertex(sample.Vertices.V1, lb),
|
||||
OffsetTerrainVertex(sample.Vertices.V2, lb));
|
||||
|
||||
var normal = sample.Normal;
|
||||
float d = -Vector3.Dot(normal, vertices[0]);
|
||||
var plane = new System.Numerics.Plane(normal, d);
|
||||
|
||||
float waterDepth = lb.Terrain.SampleWaterDepth(localX, localY);
|
||||
bool isWater = waterDepth >= 0.45f;
|
||||
uint lowCellId = lb.Terrain.ComputeOutdoorCellId(localX, localY);
|
||||
uint fullCellId = (kvp.Key & 0xFFFF0000u) | lowCellId;
|
||||
|
||||
return new TerrainWalkableSample(
|
||||
plane,
|
||||
vertices,
|
||||
waterDepth,
|
||||
isWater,
|
||||
fullCellId);
|
||||
}
|
||||
return BuildTerrainWalkableSample(kvp.Key, lb, localX, localY);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Samples only the fixed outdoor cell supplied to retail
|
||||
/// <c>CTransition::insert_into_cell</c>. The target point may move into a
|
||||
/// neighboring cell during a retry, but retail continues dispatching the
|
||||
/// captured <c>CObjCell*</c> until that inner call returns.
|
||||
/// </summary>
|
||||
internal TerrainWalkableSample? SampleTerrainWalkableInCell(
|
||||
uint cellId,
|
||||
float worldX,
|
||||
float worldY)
|
||||
{
|
||||
uint lowCellId = cellId & 0xFFFFu;
|
||||
if (lowCellId is < 1u or > 0x40u)
|
||||
return null;
|
||||
|
||||
foreach (var kvp in _landblocks)
|
||||
{
|
||||
uint requestedPrefix = cellId & 0xFFFF0000u;
|
||||
if (requestedPrefix != 0u &&
|
||||
(kvp.Key & 0xFFFF0000u) != requestedPrefix)
|
||||
continue;
|
||||
|
||||
LandblockPhysics lb = kvp.Value;
|
||||
float localX = worldX - lb.WorldOffsetX;
|
||||
float localY = worldY - lb.WorldOffsetY;
|
||||
if (requestedPrefix == 0u &&
|
||||
(localX < 0f || localX >= 192f ||
|
||||
localY < 0f || localY >= 192f))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int cellIndex = (int)lowCellId - 1;
|
||||
int cellX = cellIndex / TerrainSurface.CellsPerSide;
|
||||
int cellY = cellIndex % TerrainSurface.CellsPerSide;
|
||||
float minX = cellX * TerrainSurface.CellSize;
|
||||
float minY = cellY * TerrainSurface.CellSize;
|
||||
float maxX = minX + TerrainSurface.CellSize;
|
||||
float maxY = minY + TerrainSurface.CellSize;
|
||||
|
||||
if (localX < minX || localX >= maxX ||
|
||||
localY < minY || localY >= maxY)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return BuildTerrainWalkableSample(
|
||||
kvp.Key,
|
||||
lb,
|
||||
localX,
|
||||
localY);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static TerrainWalkableSample BuildTerrainWalkableSample(
|
||||
uint landblockId,
|
||||
LandblockPhysics landblock,
|
||||
float localX,
|
||||
float localY)
|
||||
{
|
||||
TerrainSurfacePolygon sample = landblock.Terrain.SampleSurfacePolygon(
|
||||
localX,
|
||||
localY);
|
||||
var vertices = new TerrainTriangleVertices(
|
||||
OffsetTerrainVertex(sample.Vertices.V0, landblock),
|
||||
OffsetTerrainVertex(sample.Vertices.V1, landblock),
|
||||
OffsetTerrainVertex(sample.Vertices.V2, landblock));
|
||||
|
||||
Vector3 normal = sample.Normal;
|
||||
float d = -Vector3.Dot(normal, vertices[0]);
|
||||
var plane = new System.Numerics.Plane(normal, d);
|
||||
|
||||
float waterDepth = landblock.Terrain.SampleWaterDepth(localX, localY);
|
||||
bool isWater = waterDepth >= 0.45f;
|
||||
uint lowCellId = landblock.Terrain.ComputeOutdoorCellId(localX, localY);
|
||||
uint fullCellId = (landblockId & 0xFFFF0000u) | lowCellId;
|
||||
|
||||
return new TerrainWalkableSample(
|
||||
plane,
|
||||
vertices,
|
||||
waterDepth,
|
||||
isWater,
|
||||
fullCellId);
|
||||
}
|
||||
|
||||
private static Vector3 OffsetTerrainVertex(Vector3 vertex, LandblockPhysics landblock)
|
||||
=> new(
|
||||
vertex.X + landblock.WorldOffsetX,
|
||||
|
|
@ -466,11 +530,11 @@ public sealed class PhysicsEngine
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// TEST-ONLY outdoor cell re-derive. The single caller is
|
||||
/// <c>Transition.FindEnvCollisions</c>'s cache-null fallback
|
||||
/// TEST-ONLY outdoor cell re-derive. The sole caller is
|
||||
/// <c>Transition.RunCheckOtherCellsAndAdvance</c>'s cache-null fallback
|
||||
/// (PhysicsEngineTests run engines without a <see cref="DataCache"/>,
|
||||
/// so <see cref="CellTransit.FindCellSet"/> is unavailable). Production
|
||||
/// membership flows exclusively through the collide-then-pick advance
|
||||
/// so <see cref="CellTransit.FindCellSet"/> is unavailable). Normal
|
||||
/// production membership flows exclusively through the collide-then-pick advance
|
||||
/// (<c>RunCheckOtherCellsAndAdvance</c> → <c>FindCellSet</c>).
|
||||
///
|
||||
/// <para>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue