diag(scenery): #48 ACDREAM_DUMP_SCENERY_Z dump
Per-spawn / per-rendered-mesh log line at scenery hydration: rendered gfx id, sample source (physics vs bilinear), groundZ, BaseLoc.Z, finalZ, mesh vertex Z range, and DIDDegrade slot 0 metadata. One log line lets the user identify a floating tree by world coords and the data picks the hypothesis (BaseLoc.Z addition / sampler drift / DIDDegrade selection). Diagnostic-first per CLAUDE.md before the fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e3d8a44c48
commit
8ee76deefd
1 changed files with 63 additions and 1 deletions
|
|
@ -183,6 +183,15 @@ public sealed class GameWindow : IDisposable
|
|||
private static readonly bool s_retailCloseDegrades =
|
||||
string.Equals(Environment.GetEnvironmentVariable("ACDREAM_RETAIL_CLOSE_DEGRADES"), "1", StringComparison.Ordinal);
|
||||
|
||||
// Issue #48 diagnostic — dump per-scenery-spawn placement evidence
|
||||
// (rendered gfx id, sample source physics-vs-bilinear, ground/baseLoc/finalZ,
|
||||
// mesh vertex Z range, DIDDegrade slot 0). One log line per spawn lets
|
||||
// the user identify a floating tree by its world coordinates and tell
|
||||
// whether the cause is BaseLoc.Z addition (H1), bilinear-fallback drift
|
||||
// (H2), or DIDDegrade selection (H3). Diagnostic-first per CLAUDE.md.
|
||||
private static readonly bool s_dumpSceneryZ =
|
||||
string.Equals(Environment.GetEnvironmentVariable("ACDREAM_DUMP_SCENERY_Z"), "1", StringComparison.Ordinal);
|
||||
|
||||
/// <summary>
|
||||
/// Issue #47 humanoid-setup detector. Matches Aluvian Male
|
||||
/// (<c>0x02000001</c>) and the 34-part heritage sibling setups
|
||||
|
|
@ -4639,10 +4648,63 @@ public sealed class GameWindow : IDisposable
|
|||
// fall back to the local bilinear sample.
|
||||
var worldPx = localX + lbOffset.X;
|
||||
var worldPy = localY + lbOffset.Y;
|
||||
float groundZ = _physicsEngine.SampleTerrainZ(worldPx, worldPy)
|
||||
float? maybePhysicsZ = _physicsEngine.SampleTerrainZ(worldPx, worldPy);
|
||||
float groundZ = maybePhysicsZ
|
||||
?? SampleTerrainZ(lb.Heightmap, _heightTable, localX, localY);
|
||||
float finalZ = groundZ + spawn.LocalPosition.Z;
|
||||
|
||||
// Issue #48 diagnostic. One log line per (spawn, rendered-mesh)
|
||||
// disambiguates H1 (BaseLoc.Z / mesh-zMin per-species), H2
|
||||
// (physics-vs-bilinear sampler drift), and H3 (DIDDegrade slot 0).
|
||||
// User identifies a floating tree visually, finds the matching
|
||||
// line by world coords + gfx id, the data picks the hypothesis.
|
||||
if (s_dumpSceneryZ)
|
||||
{
|
||||
string source = maybePhysicsZ.HasValue ? "physics" : "bilinear";
|
||||
foreach (var mr in meshRefs)
|
||||
{
|
||||
var dgfx = _dats.Get<DatReaderWriter.DBObjs.GfxObj>(mr.GfxObjId);
|
||||
if (dgfx is null) continue;
|
||||
|
||||
float zMin = float.PositiveInfinity, zMax = float.NegativeInfinity;
|
||||
foreach (var v in dgfx.VertexArray.Vertices.Values)
|
||||
{
|
||||
if (v.Origin.Z < zMin) zMin = v.Origin.Z;
|
||||
if (v.Origin.Z > zMax) zMax = v.Origin.Z;
|
||||
}
|
||||
if (float.IsPositiveInfinity(zMin)) { zMin = 0f; zMax = 0f; }
|
||||
|
||||
bool hasDD = dgfx.Flags.HasFlag(DatReaderWriter.Enums.GfxObjFlags.HasDIDDegrade);
|
||||
string ddInfo = string.Empty;
|
||||
if (hasDD && dgfx.DIDDegrade != 0)
|
||||
{
|
||||
var ddi = _dats.Get<DatReaderWriter.DBObjs.GfxObjDegradeInfo>(dgfx.DIDDegrade);
|
||||
if (ddi is not null && ddi.Degrades.Count > 0)
|
||||
{
|
||||
uint slot0Id = (uint)ddi.Degrades[0].Id;
|
||||
float slot0Min = 0f;
|
||||
var slot0Gfx = _dats.Get<DatReaderWriter.DBObjs.GfxObj>(slot0Id);
|
||||
if (slot0Gfx is not null && slot0Gfx.VertexArray.Vertices.Count > 0)
|
||||
{
|
||||
slot0Min = float.PositiveInfinity;
|
||||
foreach (var v in slot0Gfx.VertexArray.Vertices.Values)
|
||||
if (v.Origin.Z < slot0Min) slot0Min = v.Origin.Z;
|
||||
if (float.IsPositiveInfinity(slot0Min)) slot0Min = 0f;
|
||||
}
|
||||
ddInfo = $" deg[0]=0x{slot0Id:X8} deg[0]ZMin={slot0Min:F3}";
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine(
|
||||
$"[scenery-z] lb=0x{lb.LandblockId:X8} root=0x{spawn.ObjectId:X8} gfx=0x{mr.GfxObjId:X8}" +
|
||||
$" source={source}" +
|
||||
$" world=({worldPx:F2},{worldPy:F2}) localXY=({localX:F2},{localY:F2})" +
|
||||
$" groundZ={groundZ:F3} BaseLoc.Z={spawn.LocalPosition.Z:F3} finalZ={finalZ:F3}" +
|
||||
$" zRange=[{zMin:F3}..{zMax:F3}] zSpan={zMax - zMin:F3}" +
|
||||
$" hasDIDDegrade={hasDD}{ddInfo}");
|
||||
}
|
||||
}
|
||||
|
||||
var hydrated = new AcDream.Core.World.WorldEntity
|
||||
{
|
||||
Id = sceneryIdBase + localIndex++,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue