diff --git a/src/AcDream.App/Input/PlayerMovementController.cs b/src/AcDream.App/Input/PlayerMovementController.cs index ad82849..dab9138 100644 --- a/src/AcDream.App/Input/PlayerMovementController.cs +++ b/src/AcDream.App/Input/PlayerMovementController.cs @@ -1114,7 +1114,7 @@ public sealed class PlayerMovementController // L.4-diag (2026-04-30): trace position transitions so we can see // whether the body is actually moving frame-to-frame on the steep // roof, or whether it's frozen at the impact point. - if (Environment.GetEnvironmentVariable("ACDREAM_DUMP_STEEP_ROOF") == "1" + if (AcDream.Core.Physics.PhysicsDiagnostics.DumpSteepRoofEnabled && resolveResult.CollisionNormalValid) { Console.WriteLine( @@ -1196,7 +1196,7 @@ public sealed class PlayerMovementController : (!prevOnWalkable && !nowOnWalkable); // L.4-diag (2026-04-30): per-frame bounce trace for steep-roof bug. - bool diagSteep = Environment.GetEnvironmentVariable("ACDREAM_DUMP_STEEP_ROOF") == "1"; + bool diagSteep = AcDream.Core.Physics.PhysicsDiagnostics.DumpSteepRoofEnabled; if (diagSteep && resolveResult.CollisionNormalValid) { var n0 = resolveResult.CollisionNormal; diff --git a/src/AcDream.Core/Physics/PhysicsDiagnostics.cs b/src/AcDream.Core/Physics/PhysicsDiagnostics.cs index 540cac0..a8649a0 100644 --- a/src/AcDream.Core/Physics/PhysicsDiagnostics.cs +++ b/src/AcDream.Core/Physics/PhysicsDiagnostics.cs @@ -141,4 +141,29 @@ public static class PhysicsDiagnostics /// public static bool ProbeUseabilityFallbackEnabled { get; set; } = Environment.GetEnvironmentVariable("ACDREAM_PROBE_USEABILITY_FALLBACK") == "1"; + + /// + /// L.4-diag (2026-04-30) → promoted into + /// 2026-05-16 per CLAUDE.md "Code Structure Rules" §5 (diagnostic owner + /// classes, not per-call-site env reads). Gates the [steep-roof] + /// trace family that fires from four sites during the rooftop-bounce + /// investigation: + /// + /// PhysicsEngine.ResolveWithTransition — + /// [steep-roof] KILL-VELOCITY-APPLIED when retail-faithful + /// kill_velocity zeroes the body's velocity on steep-slope + /// impact. + /// TransitionTypes (FindEnvCollisions + /// post-step) — per-frame plane-normal trace on the active + /// . + /// PlayerMovementController — two sites + /// emitting [steep-roof] + the per-frame bounce trace when + /// the post-collision velocity disagrees with retail. + /// + /// Initial state from ACDREAM_DUMP_STEEP_ROOF=1. Runtime-toggleable + /// via the property setter; not yet wired to a DebugPanel checkbox (open + /// follow-up if a debugging session calls for it). + /// + public static bool DumpSteepRoofEnabled { get; set; } = + Environment.GetEnvironmentVariable("ACDREAM_DUMP_STEEP_ROOF") == "1"; } diff --git a/src/AcDream.Core/Physics/PhysicsEngine.cs b/src/AcDream.Core/Physics/PhysicsEngine.cs index 4bfcb3e..a5bdf92 100644 --- a/src/AcDream.Core/Physics/PhysicsEngine.cs +++ b/src/AcDream.Core/Physics/PhysicsEngine.cs @@ -634,7 +634,7 @@ public sealed class PhysicsEngine // acclient_2013_pseudo_c.txt:272567 (validate_transition) if (transition.ObjectInfo.VelocityKilled) { - if (Environment.GetEnvironmentVariable("ACDREAM_DUMP_STEEP_ROOF") == "1") + if (PhysicsDiagnostics.DumpSteepRoofEnabled) Console.WriteLine($"[steep-roof] KILL-VELOCITY-APPLIED Vbefore=({body.Velocity.X:F2},{body.Velocity.Y:F2},{body.Velocity.Z:F2}) → 0,0,0"); body.Velocity = Vector3.Zero; } diff --git a/src/AcDream.Core/Physics/TransitionTypes.cs b/src/AcDream.Core/Physics/TransitionTypes.cs index d5077b8..9fa7ba2 100644 --- a/src/AcDream.Core/Physics/TransitionTypes.cs +++ b/src/AcDream.Core/Physics/TransitionTypes.cs @@ -715,7 +715,7 @@ public sealed class Transition ci.ContactPlaneValid = false; ci.ContactPlaneIsWater = false; - bool diagSteep = Environment.GetEnvironmentVariable("ACDREAM_DUMP_STEEP_ROOF") == "1"; + bool diagSteep = PhysicsDiagnostics.DumpSteepRoofEnabled; if (diagSteep) { Console.WriteLine(