diff --git a/src/AcDream.App/Input/PlayerMovementController.cs b/src/AcDream.App/Input/PlayerMovementController.cs index e151197..b5b7466 100644 --- a/src/AcDream.App/Input/PlayerMovementController.cs +++ b/src/AcDream.App/Input/PlayerMovementController.cs @@ -44,7 +44,14 @@ public sealed class PlayerMovementController public float RunSpeed { get; set; } = 7f; public float TurnSpeed { get; set; } = 1.5f; public float MouseTurnSensitivity { get; set; } = 0.003f; - public float StepUpHeight { get; set; } = 1.0f; + /// + /// Maximum Z increase per movement step before the move is rejected. + /// AC's default StepUpHeight for human characters is ~2 units (from + /// Setup.StepUpHeight). Using 5 for the MVP to be forgiving — prevents + /// walking up vertical walls but allows stairs, ramps, and terrain + /// slopes that the heightmap interpolation can produce. + /// + public float StepUpHeight { get; set; } = 5.0f; public float Yaw { get; set; } public Vector3 Position { get; private set; } diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index af7aedc..223c8d8 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -203,15 +203,14 @@ public sealed class GameWindow : IDisposable float plocalX = playerEntity.Position.X - (plbX - _liveCenterX) * 192f; float plocalY = playerEntity.Position.Y - (plbY - _liveCenterY) * 192f; uint pinitCellId = ((uint)plbX << 24) | ((uint)plbY << 16) | 0x0001u; - // Use the server-sent position directly — the server already - // gave us a valid position at CreateObject time. Running it - // through PhysicsEngine.Resolve was mapping the player into - // an indoor cell (e.g., the foundry at Z=66) when they're - // actually standing on outdoor terrain at Z=93+. The physics - // engine's cell-containment check is too aggressive for the - // initial placement. Once the player starts moving, Resolve - // will keep them on the correct surface. - _playerController.SetPosition(playerEntity.Position, pinitCellId & 0xFFFFu); + // Resolve the initial position through the physics engine to + // get the correct terrain Z. The server-sent Z may be stale + // from a previous ACE relocation. With indoor transitions + // disabled, Resolve will always snap to outdoor terrain Z. + var initResult = _physicsEngine.Resolve( + playerEntity.Position, pinitCellId & 0xFFFFu, + System.Numerics.Vector3.Zero, 100f); // huge step height for initial snap + _playerController.SetPosition(initResult.Position, initResult.CellId); // Derive initial yaw from the entity's server-sent rotation // rather than hardcoding. Extract yaw from the quaternion. var q = playerEntity.Rotation;