diff --git a/src/AcDream.App/Rendering/Walk/RetailFrameWalk.cs b/src/AcDream.App/Rendering/Walk/RetailFrameWalk.cs index 94213e52..8ee37b49 100644 --- a/src/AcDream.App/Rendering/Walk/RetailFrameWalk.cs +++ b/src/AcDream.App/Rendering/Walk/RetailFrameWalk.cs @@ -50,6 +50,11 @@ public sealed class RetailFrameWalk public WalkPView InteriorPView => _interiorPView; public WalkPView OutdoorPView => _outdoorPView; + /// Retail global alwaysDrawObjects (.data default 1 + /// @0x00820ed4): cell contents draw for every cell of an in-view block + /// regardless of per-cell visibility. + public bool AlwaysDrawObjects = true; + /// The per-frame root (SmartBox::RenderNormalMode). /// may be null only when the camera is /// outdoors. @@ -115,10 +120,15 @@ public sealed class RetailFrameWalk for (int k = 0; k < cellCount; k++) { int cellIndex = block.DrawArray[k]; - // DrawSortCell runs for in-view cells (alwaysDrawObjects - // default 0); terrain (DrawLandCell) emits no walk event. - if (block.CellInView[cellIndex] == WalkBoundingType.Outside) + // RenderDeviceD3D::DrawBlock @0x005a19d9: DrawSortCell runs + // when alwaysDrawObjects != 0 (retail .data default 1 + // @0x00820ed4) OR the cell IsInView; terrain (DrawLandCell) + // emits no walk event. + if (!AlwaysDrawObjects + && block.CellInView[cellIndex] == WalkBoundingType.Outside) + { continue; + } if (block.CellBuildings[cellIndex] is WalkBuilding building) DrawBuilding(building, activeViews, ctx, sink); } diff --git a/tests/AcDream.App.Tests/Rendering/Walk/WalkLookInGateSweepTests.cs b/tests/AcDream.App.Tests/Rendering/Walk/WalkLookInGateSweepTests.cs index 2cc18a8b..f8cbf2b6 100644 --- a/tests/AcDream.App.Tests/Rendering/Walk/WalkLookInGateSweepTests.cs +++ b/tests/AcDream.App.Tests/Rendering/Walk/WalkLookInGateSweepTests.cs @@ -24,14 +24,11 @@ public sealed class WalkLookInGateSweepTests public void Emit(in WalkEvent walkEvent) => Events.Add(walkEvent); } - [Fact(Skip = "FW1 adjudication driver (2026-08-30 final state): with the " - + "exact get_degrade rule (slack 100, ideal thresholds, sort-center " - + "distance) the level-0 set is correct — the residual divergence is " - + "the per-portal side/clip gate: my arms punch {0017,001e,0026,0036}, " - + "retail punched exactly {001a,0022} — a near-complement suggesting " - + "one more polarity at the building-portal gate. Next instrument: " - + "per-portal dump for 001a (retail punches) vs 001e (retail doesn't): " - + "side values, plane orientation, eye side, clip result per arm.")] + [Fact(Skip = "FW1 near-win state (2026-08-30): with +Y-forward, alwaysDrawObjects, " + + "the exact degrade rule and side mode 1, the street fixture matches retail " + + "EXCEPT look-in flood depth (mine D[16e]/D[164]; retail D[16e,16a,16c]/" + + "D[164,162,167,169]) - adjudicate the interior flood propagation next " + + "(the doorway-still fixture tests it in isolation).")] public void Sweep_the_lookin_gate_decodes_against_the_street_fixture() { string? datDir = CornerFloodReplayTests.ResolveDatDir(); diff --git a/tests/AcDream.App.Tests/Rendering/Walk/WalkTraceReplay.cs b/tests/AcDream.App.Tests/Rendering/Walk/WalkTraceReplay.cs index 0b7f3300..30763590 100644 --- a/tests/AcDream.App.Tests/Rendering/Walk/WalkTraceReplay.cs +++ b/tests/AcDream.App.Tests/Rendering/Walk/WalkTraceReplay.cs @@ -53,14 +53,16 @@ public sealed class WalkTraceReplayContext : IWalkFrameContext, IRetailFrameWalk _cells = cells; WorldViewpoint = pose.Origin; var rotation = new Quaternion(pose.Q1, pose.Q2, pose.Q3, pose.Q0); - // Convention pinned against the moving fixtures (2026-08-30 sweep: - // storage w,x,y,z; the facing direction is the rotated +X axis — - // mean 20.8° vs motion headings, every alternative ≥52°). The - // consistent right-handed triple is then right = −rot(+Y), - // forward = rot(+X), up = rot(+Z). - Vector3 forward = Vector3.Transform(Vector3.UnitX, rotation); + // Basis convention RE-pinned 2026-08-30 (second pass): storage + // w,x,y,z; forward = rotated +Y — the retail Frame convention. The + // motion sweep briefly favored +X, but the walkabout camera was + // mouse-turned off the run direction; the terrace-edge fixture's + // EXTERNAL ground truth (the ledge faces the F518 vista, east) + // decodes east ONLY under +Y-forward, and +Y makes the street + // fixture's punch on/off-screen pattern match retail 4-for-4. + Vector3 forward = Vector3.Transform(Vector3.UnitY, rotation); Vector3 up = Vector3.Transform(Vector3.UnitZ, rotation); - Vector3 right = -Vector3.Transform(Vector3.UnitY, rotation); + Vector3 right = Vector3.Transform(Vector3.UnitX, rotation); // The exact retail frustum: tan(halfFovY) = ty/vdst, aspect = tx/ty. float fovY = 2f * MathF.Atan(RetailTy / RetailVdst); diff --git a/tests/AcDream.App.Tests/Rendering/Walk/WalkWorldDatAdapter.cs b/tests/AcDream.App.Tests/Rendering/Walk/WalkWorldDatAdapter.cs index 469b349c..88b46fe3 100644 --- a/tests/AcDream.App.Tests/Rendering/Walk/WalkWorldDatAdapter.cs +++ b/tests/AcDream.App.Tests/Rendering/Walk/WalkWorldDatAdapter.cs @@ -242,7 +242,9 @@ public static class WalkWorldDatAdapter /// Adjudication toggle: the BuildingPortal side-flag decode. /// 0 = (Flags & 0x2), 1 = inverted 0x2, 2 = (Flags & 0x1), /// 3 = inverted 0x1. - public static int BuildingSideMode; + public static int BuildingSideMode = 1; // data-pinned 2026-08-30: building + // portal_side = the INVERSE of the cell decode's 0x2 bit (the sweep's + // winning arm - punches land at retail's exact buildings/cells with it). private static int DecodeBuildingSide(ushort flags) => BuildingSideMode switch {