fix: complete retail parity stability pass
This commit is contained in:
parent
d3df4cb20a
commit
f7aa8e0eb7
131 changed files with 7765 additions and 1190 deletions
|
|
@ -3,6 +3,7 @@ using DatReaderWriter;
|
|||
using DatReaderWriter.DBObjs;
|
||||
using DatReaderWriter.Enums;
|
||||
using DatReaderWriter.Options;
|
||||
using DatEnvironment = DatReaderWriter.DBObjs.Environment;
|
||||
using SysEnv = System.Environment;
|
||||
|
||||
string datDir = SysEnv.GetEnvironmentVariable("ACDREAM_DAT_DIR")
|
||||
|
|
@ -16,7 +17,11 @@ if (!Directory.Exists(datDir))
|
|||
}
|
||||
|
||||
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
||||
if (args.Length > 0 && string.Equals(args[0], "buildings", StringComparison.OrdinalIgnoreCase))
|
||||
if (args.Length > 0 && string.Equals(args[0], "cell-winding-catalog", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return AuditCellWindingCatalog(dats);
|
||||
}
|
||||
else if (args.Length > 0 && string.Equals(args[0], "buildings", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
uint landblockId = args.Length > 1 ? ParseHex(args[1]) : 0xA9B40000u;
|
||||
int radius = args.Length > 2 ? int.Parse(args[2], System.Globalization.CultureInfo.InvariantCulture) : 0;
|
||||
|
|
@ -52,6 +57,128 @@ else
|
|||
|
||||
return 0;
|
||||
|
||||
static int AuditCellWindingCatalog(DatCollection dats)
|
||||
{
|
||||
long environments = 0;
|
||||
long cellStructs = 0;
|
||||
long polygons = 0;
|
||||
long triangles = 0;
|
||||
long degenerateTriangles = 0;
|
||||
long alignedToPlane = 0;
|
||||
long opposedToPlane = 0;
|
||||
long ambiguousToNormal = 0;
|
||||
long inconsistentFans = 0;
|
||||
var sideCounts = new Dictionary<CullMode, long>();
|
||||
var invalidSides = new List<string>();
|
||||
var structuralFailures = new List<string>();
|
||||
var windingObservations = new List<string>();
|
||||
|
||||
foreach (uint environmentId in dats.GetAllIdsOfType<DatEnvironment>().OrderBy(id => id))
|
||||
{
|
||||
DatEnvironment? environment = dats.Get<DatEnvironment>(environmentId);
|
||||
if (environment is null)
|
||||
continue;
|
||||
|
||||
environments++;
|
||||
foreach (var (cellStructId, cellStruct) in environment.Cells.OrderBy(pair => pair.Key))
|
||||
{
|
||||
cellStructs++;
|
||||
foreach (var (polygonId, polygon) in cellStruct.Polygons.OrderBy(pair => pair.Key))
|
||||
{
|
||||
if (polygon.VertexIds.Count < 3)
|
||||
continue;
|
||||
|
||||
polygons++;
|
||||
sideCounts[polygon.SidesType] = sideCounts.GetValueOrDefault(polygon.SidesType) + 1;
|
||||
if (polygon.SidesType is not (CullMode.Landblock or CullMode.None or CullMode.Clockwise))
|
||||
{
|
||||
if (invalidSides.Count < 20)
|
||||
invalidSides.Add($"env=0x{environmentId:X8} struct=0x{cellStructId:X4} poly=0x{polygonId:X4} sides={polygon.SidesType}");
|
||||
}
|
||||
|
||||
if (!cellStruct.VertexArray.Vertices.TryGetValue(
|
||||
(ushort)polygon.VertexIds[0],
|
||||
out var anchorVertex))
|
||||
{
|
||||
if (structuralFailures.Count < 20)
|
||||
structuralFailures.Add($"env=0x{environmentId:X8} struct=0x{cellStructId:X4} poly=0x{polygonId:X4} missing anchor");
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3 anchor = anchorVertex.Origin;
|
||||
Vector3 authoredNormal = anchorVertex.Normal;
|
||||
if (authoredNormal.LengthSquared() > 0f)
|
||||
authoredNormal = Vector3.Normalize(authoredNormal);
|
||||
|
||||
int? fanSign = null;
|
||||
for (int point = 2; point < polygon.VertexIds.Count; point++)
|
||||
{
|
||||
triangles++;
|
||||
if (!TryGetOrigin(cellStruct, (ushort)polygon.VertexIds[point - 1], out Vector3 b)
|
||||
|| !TryGetOrigin(cellStruct, (ushort)polygon.VertexIds[point], out Vector3 c))
|
||||
{
|
||||
if (structuralFailures.Count < 20)
|
||||
structuralFailures.Add($"env=0x{environmentId:X8} struct=0x{cellStructId:X4} poly=0x{polygonId:X4} missing fan vertex");
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3 cross = Vector3.Cross(b - anchor, c - anchor);
|
||||
if (cross.LengthSquared() <= 1e-12f || authoredNormal.LengthSquared() <= 0f)
|
||||
{
|
||||
degenerateTriangles++;
|
||||
continue;
|
||||
}
|
||||
|
||||
float dot = Vector3.Dot(Vector3.Normalize(cross), authoredNormal);
|
||||
if (MathF.Abs(dot) < 1e-3f)
|
||||
{
|
||||
ambiguousToNormal++;
|
||||
continue;
|
||||
}
|
||||
|
||||
int sign = dot >= 0f ? 1 : -1;
|
||||
if (fanSign is null)
|
||||
fanSign = sign;
|
||||
else if (fanSign.Value != sign)
|
||||
{
|
||||
inconsistentFans++;
|
||||
if (windingObservations.Count < 20)
|
||||
windingObservations.Add($"env=0x{environmentId:X8} struct=0x{cellStructId:X4} poly=0x{polygonId:X4} fan changes orientation dot={dot:R}");
|
||||
}
|
||||
|
||||
if (sign > 0) alignedToPlane++;
|
||||
else opposedToPlane++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine(
|
||||
$"cell-winding-catalog environments={environments:N0} cellStructs={cellStructs:N0} " +
|
||||
$"polygons={polygons:N0} triangles={triangles:N0} degenerate={degenerateTriangles:N0}");
|
||||
Console.WriteLine(
|
||||
$"orientation alignedToAuthoredNormal={alignedToPlane:N0} " +
|
||||
$"opposedToAuthoredNormal={opposedToPlane:N0} ambiguous={ambiguousToNormal:N0} " +
|
||||
$"inconsistentReliableFans={inconsistentFans:N0}");
|
||||
Console.WriteLine(
|
||||
"sides " + string.Join(", ", sideCounts.OrderBy(pair => (int)pair.Key)
|
||||
.Select(pair => $"{pair.Key}({(int)pair.Key})={pair.Value:N0}")));
|
||||
|
||||
foreach (string failure in invalidSides)
|
||||
Console.WriteLine($"INVALID-SIDES {failure}");
|
||||
foreach (string failure in structuralFailures)
|
||||
Console.WriteLine($"STRUCTURAL-FAIL {failure}");
|
||||
foreach (string observation in windingObservations)
|
||||
Console.WriteLine($"AUTHORED-FAN-OBSERVATION {observation}");
|
||||
|
||||
// Orientation observations describe the authored polygon fan. Retail
|
||||
// submits the same [0,i-1,i] indices, so reproducing them is the parity
|
||||
// contract; only missing vertices or an unknown sides_type are invalid.
|
||||
return invalidSides.Count == 0 && structuralFailures.Count == 0
|
||||
? 0
|
||||
: 1;
|
||||
}
|
||||
|
||||
static uint ParseHex(string text)
|
||||
{
|
||||
text = text.Trim();
|
||||
|
|
|
|||
|
|
@ -74,6 +74,11 @@ foreach (var root in roots)
|
|||
case SoundHook sh:
|
||||
Console.WriteLine($"{head} sound=0x{(uint)sh.Id:X8}");
|
||||
break;
|
||||
case SoundTweakedHook tweaked:
|
||||
Console.WriteLine(
|
||||
$"{head} sound=0x{(uint)tweaked.SoundId:X8} " +
|
||||
$"volume={tweaked.Volume:R} priority={tweaked.Priority:R}");
|
||||
break;
|
||||
case SoundTableHook stb:
|
||||
Console.WriteLine($"{head} soundType={stb.SoundType}");
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue