P0 Task 6 complete. Captured live retail membership at the 0031<->0170<->0171 doorway via cdb on CPhysicsObj::change_cell (symbol-driven; offsets verified by discover-types.cdb; PDB MATCH). 22 transitions, clean monotonic sequence, NO ping-pong (retail is correct-by-construction). Golden: Conformance/Fixtures/find-cell-list-threshold.log. ROOT-CAUSE FINDING (the central P1 work): retail transitions membership at the PORTAL CROSSING (CEnvCell::find_transit_cells @ 0x52c820 pc:309968 — sphere crosses the doorway polygon plane), while acdream's FindCellList re-picks by POINT-IN-CELL containment at the foot. Retail commits room 0171 while the foot is STILL inside vestibule 0170's BSP (in_0171=0); acdream lags. ALL 22 transitions diverge for this one criterion mismatch — not a per-cell hysteresis or a building-entry-only split. This is master-plan §0 'hysteresis gap' confirmed against the real client. FindCellList_DoorwayThreshold_DivergesFromRetail_PendingP1 (documents-the-bug, GREEN) + ThresholdDivergenceDiagnosticTests (per-transition containment print) pin it; both flip when P1 ports the directed portal crossing. Conformance 59 pass / 1 skip / 0 fail; full Core 1308 pass / 5 fail (baseline) / 1 skip — no new failures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
53 lines
2.4 KiB
C#
53 lines
2.4 KiB
C#
using System.Linq;
|
|
using AcDream.Core.Physics;
|
|
using DatReaderWriter;
|
|
using DatReaderWriter.Options;
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace AcDream.Core.Tests.Conformance;
|
|
|
|
/// <summary>
|
|
/// Diagnostic (always passes): for each captured retail doorway transition, print
|
|
/// what acdream computes — PointInCell(seed), PointInCell(picked), and the
|
|
/// FindCellList result — so the P0→P1 divergence is precisely characterized
|
|
/// (real pick-criterion divergence vs a test/sphere artifact).
|
|
/// </summary>
|
|
public class ThresholdDivergenceDiagnosticTests
|
|
{
|
|
private readonly ITestOutputHelper _out;
|
|
public ThresholdDivergenceDiagnosticTests(ITestOutputHelper output) => _out = output;
|
|
|
|
[Fact]
|
|
public void Diagnose_ThresholdTransitions()
|
|
{
|
|
var datDir = ConformanceDats.ResolveDatDir();
|
|
if (datDir is null) { _out.WriteLine("SKIP: dats unavailable"); return; }
|
|
var fixturePath = System.IO.Path.Combine(ConformanceDats.FixturesDir, "find-cell-list-threshold.log");
|
|
if (!System.IO.File.Exists(fixturePath)) { _out.WriteLine("SKIP: capture pending"); return; }
|
|
|
|
using var dats = new DatCollection(datDir, DatAccessType.Read);
|
|
var cache = new PhysicsDataCache();
|
|
var cells = new System.Collections.Generic.Dictionary<uint, AcDream.Core.World.Cells.EnvCell>();
|
|
for (uint low = 0x016Fu; low <= 0x0175u; low++)
|
|
{
|
|
uint id = ConformanceDats.HoltburgLandblock | low;
|
|
cells[id] = ConformanceDats.LoadEnvCell(dats, cache, id);
|
|
}
|
|
|
|
bool In(uint id, System.Numerics.Vector3 p) =>
|
|
cells.TryGetValue(id, out var c) && c.PointInCell(p);
|
|
|
|
foreach (var pick in RetailTrace.ParseAll(System.IO.File.ReadAllLines(fixturePath)))
|
|
{
|
|
uint ours = CellTransit.FindCellList(cache, pick.Position, 0.4f, pick.SeedCellId);
|
|
_out.WriteLine(
|
|
$"seed=0x{pick.SeedCellId & 0xFFFF:X4} pos=({pick.Position.X:F2},{pick.Position.Y:F2},{pick.Position.Z:F2}) " +
|
|
$"retail=0x{pick.PickedCellId & 0xFFFF:X4} acdream=0x{ours & 0xFFFF:X4} " +
|
|
$"{(ours == pick.PickedCellId ? "MATCH" : "DIVERGE")} | " +
|
|
$"inSeed={(In(pick.SeedCellId, pick.Position) ? 1 : 0)} " +
|
|
$"in0170={(In(0xA9B40170u, pick.Position) ? 1 : 0)} " +
|
|
$"in0171={(In(0xA9B40171u, pick.Position) ? 1 : 0)}");
|
|
}
|
|
}
|
|
}
|