fix(physics): enforce retail step-down support radius (#273)

This commit is contained in:
Erik 2026-07-31 12:10:03 +02:00
parent 4dd40ad8fe
commit c24bc571cf
9 changed files with 2117 additions and 24 deletions

View file

@ -323,9 +323,9 @@ static (int RegistryBuildings, int ShellEntities) DumpLandblockBuildings(LandBlo
{
uint lbPrefix = landblockId & 0xFFFF0000u;
uint stabIdBase = 0xC0000000u
| (((landblockId >> 24) & 0xFFu) << 16)
| (((landblockId >> 16) & 0xFFu) << 8);
uint nextEntityId = stabIdBase + 1u;
| (((landblockId >> 24) & 0xFFu) << 20)
| (((landblockId >> 16) & 0xFFu) << 12);
uint nextEntityId = stabIdBase;
int supportedObjects = 0;
foreach (var obj in info.Objects)
@ -333,7 +333,13 @@ static (int RegistryBuildings, int ShellEntities) DumpLandblockBuildings(LandBlo
if (!IsSupported(obj.Id))
continue;
supportedObjects++;
nextEntityId++;
uint entityId = nextEntityId++;
Console.WriteLine(
$"objectOrdinal={supportedObjects} entity=0x{entityId:X8} "
+ $"model=0x{obj.Id:X8} "
+ $"pos=({obj.Frame.Origin.X:R},{obj.Frame.Origin.Y:R},{obj.Frame.Origin.Z:R}) "
+ $"quat=({obj.Frame.Orientation.W:R},{obj.Frame.Orientation.X:R},"
+ $"{obj.Frame.Orientation.Y:R},{obj.Frame.Orientation.Z:R})");
}
Console.WriteLine(
@ -365,7 +371,9 @@ static (int RegistryBuildings, int ShellEntities) DumpLandblockBuildings(LandBlo
Console.WriteLine(
$"buildingOrdinal={zeroBased + 1} registryId={registryText} shellEntity=0x{shellEntityId:X8} " +
$"model=0x{building.ModelId:X8} pos=({building.Frame.Origin.X:F2},{building.Frame.Origin.Y:F2},{building.Frame.Origin.Z:F2}) " +
$"model=0x{building.ModelId:X8} pos=({building.Frame.Origin.X:R},{building.Frame.Origin.Y:R},{building.Frame.Origin.Z:R}) " +
$"quat=({building.Frame.Orientation.W:R},{building.Frame.Orientation.X:R}," +
$"{building.Frame.Orientation.Y:R},{building.Frame.Orientation.Z:R}) " +
$"portalCells={portalText}");
}
@ -436,6 +444,25 @@ static void DumpGfxObj(DatCollection dats, uint gfxObjId)
Console.WriteLine(
$"classify: walls={walls} (outwardFacing={outwardWalls} inwardFacing={inwardWalls}) " +
$"floors={floors} ceilings={ceilings} slopes={slopes}");
Console.WriteLine("physics polygons:");
foreach (var (polyId, poly) in g.PhysicsPolygons.OrderBy(p => p.Key))
{
Vector3 polyMin = new(float.MaxValue);
Vector3 polyMax = new(float.MinValue);
foreach (ushort vertexId in poly.VertexIds.Select(id => (ushort)id))
{
if (!g.VertexArray.Vertices.TryGetValue(vertexId, out var vertex))
continue;
polyMin = Vector3.Min(polyMin, vertex.Origin);
polyMax = Vector3.Max(polyMax, vertex.Origin);
}
Vector3 normal = ComputeNormalG(g, poly);
Console.WriteLine(
$" poly=0x{polyId:X4} n=({normal.X:F3},{normal.Y:F3},{normal.Z:F3}) "
+ $"min=({polyMin.X:F3},{polyMin.Y:F3},{polyMin.Z:F3}) "
+ $"max=({polyMax.X:F3},{polyMax.Y:F3},{polyMax.Z:F3}) "
+ $"sides={poly.SidesType} stip={poly.Stippling}");
}
Console.WriteLine();
}

View file

@ -45,6 +45,26 @@ if (!dats.TryGet<Setup>(setupId, out var setup) || setup is null)
Console.WriteLine($"=== Setup 0x{setupId:X8} ===");
Console.WriteLine($"Flags = 0x{(uint)setup.Flags:X8}");
Console.WriteLine($"Radius/Height = {setup.Radius:F3} / {setup.Height:F3}");
Console.WriteLine($"StepUp/StepDown = {setup.StepUpHeight:F3} / {setup.StepDownHeight:F3}");
Console.WriteLine($"Spheres = {setup.Spheres.Count}");
for (int i = 0; i < setup.Spheres.Count; i++)
{
Sphere sphere = setup.Spheres[i];
Console.WriteLine(
$" sphere[{i}] origin=({sphere.Origin.X:R},{sphere.Origin.Y:R},{sphere.Origin.Z:R}) "
+ $"radius={sphere.Radius:R} "
+ $"radiusBits=0x{BitConverter.SingleToUInt32Bits(sphere.Radius):X8}");
}
Console.WriteLine($"CylSpheres = {setup.CylSpheres.Count}");
for (int i = 0; i < setup.CylSpheres.Count; i++)
{
CylSphere cylinder = setup.CylSpheres[i];
Console.WriteLine(
$" cyl[{i}] origin=({cylinder.Origin.X:R},{cylinder.Origin.Y:R},{cylinder.Origin.Z:R}) "
+ $"radius={cylinder.Radius:R} height={cylinder.Height:R} "
+ $"radiusBits=0x{BitConverter.SingleToUInt32Bits(cylinder.Radius):X8}");
}
Console.WriteLine($"Parts = {setup.Parts.Count}");
for (int i = 0; i < setup.Parts.Count; i++)
{
@ -78,7 +98,10 @@ foreach (uint gfxId in setup.Parts.Select(p => (uint)p).Distinct())
Console.WriteLine(
$" gfx=0x{gfxId:X8} verts={count} "
+ $"x[{minX:F2},{maxX:F2}] y[{minY:F2},{maxY:F2}] z[{minZ:F2},{maxZ:F2}] "
+ $"sortCenter=({gfx.SortCenter.X:F2},{gfx.SortCenter.Y:F2},{gfx.SortCenter.Z:F2})");
+ $"sortCenter=({gfx.SortCenter.X:F2},{gfx.SortCenter.Y:F2},{gfx.SortCenter.Z:F2}) "
+ $"flags=0x{(uint)gfx.Flags:X8} "
+ $"physicsBsp={(gfx.PhysicsBSP?.Root is null ? "none" : "present")} "
+ $"physicsPolygons={gfx.PhysicsPolygons.Count}");
}
Console.WriteLine($"DefaultAnimation = 0x{(uint)setup.DefaultAnimation:X8}");