using System.Globalization; using System.Text.RegularExpressions; namespace AcDream.App.Tests.Rendering.Walk; /// /// S3 chunk 1 (§11.2 B2): small, read-only parsers for the OH capture /// family's two companion logs — the PARTS log /// (tools/walk-oracle/oh/oh-capture-parts.cdb.template: PD/DM) and /// the ALPHA-DEPTH log /// (tools/walk-oracle/oh/oh-capture-alpha-depth.cdb.template: AM/FL/ /// PM/PC), both dumped from the SAME docs/research/2026-09-01-overhaul/ /// oh-capture/ directory as the walk log /// already parses. These are records only — no validator, no canonical /// JSONL, no new tool ([[feedback-evidence-infrastructure-sink]]) — a later /// chunk/S4 names the first real consumer and pins specific values then. /// public static class WalkOraclePartsTrace { /// Parses a PARTS log (<pose>.parts.log). Same /// F/P framing and truncated-last-frame drop rule as /// — the harness detaches at the /// frame marker, so the final "F n" never records its own PD/DM lines. public static IReadOnlyList Parse(IEnumerable lines) { var frames = new List(); List? partDraws = null; List? meshDraws = null; int currentNumber = 0; foreach (string line in lines) { Match frameMatch = FramePattern.Match(line); if (frameMatch.Success) { if (partDraws is not null) { frames.Add(new WalkOraclePartsFrame(currentNumber, partDraws, meshDraws!)); } currentNumber = int.Parse( frameMatch.Groups[1].Value, CultureInfo.InvariantCulture); partDraws = new List(); meshDraws = new List(); continue; } if (partDraws is null) continue; Match pd = PartDrawPattern.Match(line); if (pd.Success) { partDraws.Add(new WalkOraclePartDraw( ParseHex(pd.Groups[1].Value), ParseHex(pd.Groups[2].Value), pd.Groups[3].Value != "0", ParseHex(pd.Groups[4].Value))); continue; } Match dm = MeshDrawPattern.Match(line); if (dm.Success) { meshDraws!.Add(new WalkOracleMeshDraw( ParseHex(dm.Groups[1].Value), ParseHex(dm.Groups[2].Value), dm.Groups[3].Value != "0", int.Parse(dm.Groups[4].Value, CultureInfo.InvariantCulture), ParseHex(dm.Groups[5].Value))); continue; } // Anything else (the "P …" pose line included — parts fixtures // carry no pose consumer today) is ignored, matching // WalkOracleTrace's own "cdb chrome" tolerance. } return frames; } public static IReadOnlyList Load(string root, string fixtureName) => Parse(File.ReadLines(FixturePath(root, fixtureName, ".parts.log"))); private static string FixturePath(string root, string fixtureName, string suffix) { string repoRoot = WalkOracleTraceRepoRoot.Find(); return Path.Combine( repoRoot, Path.Combine(root.Split('/')), fixtureName + suffix); } private static uint ParseHex(string hex) => uint.Parse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture); private static readonly Regex FramePattern = new(@"^F (\d+)\s*$", RegexOptions.Compiled); // PD gfx= did= force=<0|1> cell= private static readonly Regex PartDrawPattern = new( @"^PD gfx=([0-9a-f]{8}) did=([0-9a-f]{8}) force=(\d) cell=([0-9a-f]{8})\s*$", RegexOptions.Compiled); // DM gfx= did= force=<0|1> bound=<0|1|2> cell= private static readonly Regex MeshDrawPattern = new( @"^DM gfx=([0-9a-f]{8}) did=([0-9a-f]{8}) force=(\d) bound=(\d) cell=([0-9a-f]{8})\s*$", RegexOptions.Compiled); } /// One CPhysicsPart::Draw @0x0050D7A0 entry (PD line). public sealed record WalkOraclePartDraw(uint Gfx, uint DataId, bool Force, uint Cell); /// One RenderDeviceD3D::DrawMeshInternal @0x0059F360 entry /// (DM line). is retail's BoundingType (0=OUTSIDE, /// 1=PARTIALLY_INSIDE, 2=ENTIRELY_INSIDE). public sealed record WalkOracleMeshDraw(uint Gfx, uint DataId, bool Force, int Bound, uint Cell); public sealed record WalkOraclePartsFrame( int Number, IReadOnlyList PartDraws, IReadOnlyList MeshDraws); /// /// S3 chunk 1 (§11.2 B2): parses an ALPHA-DEPTH log /// (<pose>.alphadepth.log). Same F/P framing and /// truncated-last-frame drop rule as . /// public static class WalkOracleAlphaDepthTrace { public static IReadOnlyList Parse(IEnumerable lines) { var frames = new List(); List? meshAdds = null; List? flushes = null; List? portalPolyDraws = null; List? drawCellsSamples = null; int currentNumber = 0; foreach (string line in lines) { Match frameMatch = FramePattern.Match(line); if (frameMatch.Success) { if (meshAdds is not null) { frames.Add(new WalkOracleAlphaDepthFrame( currentNumber, meshAdds, flushes!, portalPolyDraws!, drawCellsSamples!)); } currentNumber = int.Parse( frameMatch.Groups[1].Value, CultureInfo.InvariantCulture); meshAdds = new List(); flushes = new List(); portalPolyDraws = new List(); drawCellsSamples = new List(); continue; } if (meshAdds is null) continue; Match am = MeshAddPattern.Match(line); if (am.Success) { meshAdds.Add(new WalkOracleAlphaMeshAdd( ParseHex(am.Groups[1].Value), int.Parse(am.Groups[2].Value, CultureInfo.InvariantCulture), ParseHex(am.Groups[3].Value), am.Groups[4].Value != "0", am.Groups[5].Value != "0", int.Parse(am.Groups[6].Value, CultureInfo.InvariantCulture))); continue; } Match fl = FlushPattern.Match(line); if (fl.Success) { flushes!.Add(new WalkOracleAlphaFlush( ParseHex(fl.Groups[1].Value), ParseHex(fl.Groups[2].Value))); continue; } Match pm = PortalPolyPattern.Match(line); if (pm.Success) { portalPolyDraws!.Add(new WalkOraclePortalPolyDraw( ParseHex(pm.Groups[1].Value), int.Parse(pm.Groups[2].Value, CultureInfo.InvariantCulture), int.Parse(pm.Groups[3].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture))); continue; } Match pc = DrawCellsSamplePattern.Match(line); if (pc.Success) { drawCellsSamples!.Add(new WalkOracleDrawCellsSample( int.Parse(pc.Groups[1].Value, CultureInfo.InvariantCulture), int.Parse(pc.Groups[2].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture), pc.Groups[3].Value != "0")); continue; } } return frames; } public static IReadOnlyList Load(string root, string fixtureName) => Parse(File.ReadLines(Path.Combine( WalkOracleTraceRepoRoot.Find(), Path.Combine(root.Split('/')), fixtureName + ".alphadepth.log"))); private static uint ParseHex(string hex) => uint.Parse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture); private static readonly Regex FramePattern = new(@"^F (\d+)\s*$", RegexOptions.Compiled); // AM mesh= surf= csurf= new=<0|1> clip=<0|1> listSel= private static readonly Regex MeshAddPattern = new( @"^AM mesh=([0-9a-f]{8}) surf=(\d+) csurf=([0-9a-f]{8}) new=(\d) clip=(\d) listSel=(\d+)\s*$", RegexOptions.Compiled); // FL thresh= ret= private static readonly Regex FlushPattern = new( @"^FL thresh=([0-9a-f]{8}) ret=([0-9a-f]{8})\s*$", RegexOptions.Compiled); // PM poly= mode= counterBefore= private static readonly Regex PortalPolyPattern = new( @"^PM poly=([0-9a-f]{8}) mode=(\d) counterBefore=([0-9a-f]{4})\s*$", RegexOptions.Compiled); // PC ov= counter= fc=<0|1> private static readonly Regex DrawCellsSamplePattern = new( @"^PC ov=(\d+) counter=([0-9a-f]{4}) fc=(\d)\s*$", RegexOptions.Compiled); } /// One D3DPolyRender::AddMeshToAlphaList @0x0059C230 entry /// (AM line). 0 selects the ALPHA list, /// nonzero the CLIP list. public sealed record WalkOracleAlphaMeshAdd( uint Mesh, int Surface, uint ClipSurface, bool New, bool Clip, int ListSelector); /// One D3DPolyRender::FlushAlphaList @0x0059D2E0 entry (FL /// line). is the raw IEEE-754 bits of the /// threshold float argument. public sealed record WalkOracleAlphaFlush(uint ThresholdBits, uint ReturnAddress); /// One D3DPolyRender::DrawPortalPolyInternal @0x0059BC90 /// entry (PM line). 0 = true-depth/exit-seal, /// nonzero = far-Z/building punch. public sealed record WalkOraclePortalPolyDraw(uint Poly, int Mode, int CounterBefore); /// One PView::DrawCells @0x005A4840 entry, sampled for the /// persistent portalsDrawnCount depth-lifecycle state machine (PC /// line) — same breakpoint address as the walk log's DC line, but this is a /// SEPARATE capture that does not also record the cell roster. public sealed record WalkOracleDrawCellsSample(int OutsideViewCount, int Counter, bool ForceClear); public sealed record WalkOracleAlphaDepthFrame( int Number, IReadOnlyList MeshAdds, IReadOnlyList Flushes, IReadOnlyList PortalPolyDraws, IReadOnlyList DrawCellsSamples); /// Shared repo-root finder — the SAME walk-up-to-AcDream.slnx /// logic already has privately; factored out /// so the parts/alpha-depth parsers don't duplicate it a second and third /// time. internal static class WalkOracleTraceRepoRoot { internal static string Find() { DirectoryInfo? dir = new(AppContext.BaseDirectory); while (dir is not null) { if (File.Exists(Path.Combine(dir.FullName, "AcDream.slnx"))) return dir.FullName; dir = dir.Parent; } throw new InvalidOperationException( "AcDream.slnx not found above the test base directory; walk-oracle fixtures unavailable."); } }