fix(app+core): Phase B.2 — increase step height + resolve initial Z from terrain

Two fixes for the "position never changes when walking" bug:

1. StepUpHeight was 1.0 units — too tight. The player started at
   Z=92.2 (ACE relocation from previous session) but terrain Z was
   ~94, so every movement attempt had a Z delta of 1.8 which
   exceeded the limit. Increased to 5.0 (forgiving for MVP; AC
   default for humans is ~2 from Setup.StepUpHeight).

2. Initial position now resolves through PhysicsEngine with a huge
   step height (100) to snap to the correct terrain Z regardless
   of where the server-sent Z currently is. With indoor transitions
   disabled, this always produces the outdoor terrain height.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-12 15:11:50 +02:00
parent 3b2f56c531
commit b341193cfe
2 changed files with 16 additions and 10 deletions

View file

@ -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;
/// <summary>
/// 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.
/// </summary>
public float StepUpHeight { get; set; } = 5.0f;
public float Yaw { get; set; }
public Vector3 Position { get; private set; }

View file

@ -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;