diff --git a/src/AcDream.App/Input/PlayerMovementController.cs b/src/AcDream.App/Input/PlayerMovementController.cs index 8084231..2a832d0 100644 --- a/src/AcDream.App/Input/PlayerMovementController.cs +++ b/src/AcDream.App/Input/PlayerMovementController.cs @@ -97,11 +97,25 @@ public sealed class PlayerMovementController /// /// Maximum Z increase per movement step before the move is rejected. - /// AC's default StepUpHeight for human characters is ~2 units. - /// Using 5 for the MVP to be forgiving — prevents walking up vertical - /// walls but allows stairs, ramps, and terrain slopes. + /// Retail's step_up_height for human characters is ~0.4 m (hip- + /// level). Setting this too high lets the player teleport up small + /// buildings via the step-up scan finding any walkable polygon within + /// reach (Bug 3 in L.2.3 testing — walking into a steep slope mounted + /// the building's flat top instead of sliding off the slope). + /// Authoritative source is the player's Setup.StepUpHeight set + /// in GameWindow.cs at world-entry time. /// - public float StepUpHeight { get; set; } = 5.0f; + public float StepUpHeight { get; set; } = 0.4f; + + /// + /// L.2.3a (2026-04-29): how far below the foot the step-down probe + /// reaches when transitioning between surfaces. Retail's + /// step_down_height for human characters is ~0.4 m. With the + /// previous 4 cm hardcoded value, walking off the top of a stair onto + /// the ground 25 cm below produced a one-frame contact-plane gap — the + /// animation system briefly flickered to falling. + /// + public float StepDownHeight { get; set; } = 0.4f; /// /// Current portal-space state. Set to PortalSpace when the server sends @@ -411,7 +425,7 @@ public sealed class PlayerMovementController sphereRadius: 0.48f, // human player radius from Setup sphereHeight: 1.2f, // human player height from Setup stepUpHeight: StepUpHeight, - stepDownHeight: 0.04f, // retail default + stepDownHeight: StepDownHeight, // L.2.3a: from Setup.StepDownHeight isOnGround: _body.OnWalkable, body: _body, // persist ContactPlane across frames for slope tracking // Commit C 2026-04-29 — local player is always IsPlayer. diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index ba3c978..d5ee444 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -5755,8 +5755,8 @@ public sealed class GameWindow : IDisposable preIntegratePos, postIntegratePos, rm.CellId, sphereRadius: 0.48f, sphereHeight: 1.2f, - stepUpHeight: 2.0f, // retail default for unknown remotes - stepDownHeight: 0.04f, // PhysicsGlobals.DefaultStepHeight + stepUpHeight: 0.4f, // L.2.3a: retail human-scale, was 2.0f + stepDownHeight: 0.4f, // L.2.3a: retail human-scale, was 0.04f // K-fix9 (2026-04-26): mirror the K-fix7 gate — // airborne remotes must NOT pre-seed the // ContactPlane, otherwise AdjustOffset's snap-to-plane @@ -7016,7 +7016,13 @@ public sealed class GameWindow : IDisposable _playerController.SetCharacterSkills(_lastSeenRunSkill, _lastSeenJumpSkill); Console.WriteLine($"live: {loggingTag} — applied server skills run={_lastSeenRunSkill} jump={_lastSeenJumpSkill}"); } - // Read the real step height from the player's Setup dat. + // Read the real step heights from the player's Setup dat. + // L.2.3a (2026-04-29): retail's Setup.StepUpHeight for humans is + // ~0.4 m, NOT 2 m. With 2 m fallback the step-up scan reached + // small-building roofs and teleported the player onto them. Same + // for StepDownHeight — was hardcoded 0.04 m, causing stair-top + // contact-plane gaps. Both now come from Setup with retail-realistic + // 0.4 m fallbacks. if (_dats is not null && (playerEntity.SourceGfxObjOrSetupId & 0xFF000000u) == 0x02000000u) { var playerSetup = _dats.Get(playerEntity.SourceGfxObjOrSetupId); @@ -7024,11 +7030,15 @@ public sealed class GameWindow : IDisposable _physicsDataCache.CacheSetup(playerEntity.SourceGfxObjOrSetupId, playerSetup); _playerController.StepUpHeight = (playerSetup is not null && playerSetup.StepUpHeight > 0f) ? playerSetup.StepUpHeight - : 2f; + : 0.4f; + _playerController.StepDownHeight = (playerSetup is not null && playerSetup.StepDownHeight > 0f) + ? playerSetup.StepDownHeight + : 0.4f; } else { - _playerController.StepUpHeight = 2f; + _playerController.StepUpHeight = 0.4f; + _playerController.StepDownHeight = 0.4f; } int plbX = _liveCenterX + (int)MathF.Floor(playerEntity.Position.X / 192f); int plbY = _liveCenterY + (int)MathF.Floor(playerEntity.Position.Y / 192f);