From 6f05c298cf08c2af02441e63b8fac62d9e5b11ec Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 12 Apr 2026 21:06:42 +0200 Subject: [PATCH] =?UTF-8?q?fix(app+core):=20Phase=20B.3=20=E2=80=94=20stre?= =?UTF-8?q?aming=20follows=20player,=20AC=20jump=20physics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three fixes for user-reported movement bugs: 1. Character disappears far from spawn: streaming observer now computed from _playerController.Position when player mode is active, instead of _lastLivePlayerLandblockId which only updates from server echoes (never for autonomous moves). The 5x5 streaming window now follows the player as they walk. 2. Jump physics from ACE: JumpImpulse=5.0 and GravityAccel=9.8 matching AC's formula: velocity_z = sqrt(height * 19.6) where height = BurdenMod * (JumpSkill / (JumpSkill + 1300) * 22.2 + 0.05) For a new char (skill=100, burden=50%): height≈1.31, vz≈5.07. 3. Gravity reduced from 20 to 9.8 (AC's F_GRAVITY constant). Co-Authored-By: Claude Opus 4.6 (1M context) --- src/AcDream.App/Input/PlayerMovementController.cs | 10 ++++++++-- src/AcDream.App/Rendering/GameWindow.cs | 15 +++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/AcDream.App/Input/PlayerMovementController.cs b/src/AcDream.App/Input/PlayerMovementController.cs index 469a74f..faa0b7f 100644 --- a/src/AcDream.App/Input/PlayerMovementController.cs +++ b/src/AcDream.App/Input/PlayerMovementController.cs @@ -64,8 +64,14 @@ public sealed class PlayerMovementController public float VerticalVelocity { get; private set; } public bool IsAirborne { get; private set; } - public float JumpImpulse { get; set; } = 3.5f; // placeholder; retail scales by Jump skill - public float GravityAccel { get; set; } = 20f; + /// + /// Jump velocity Z. AC formula: sqrt(height * 19.6) where + /// height = BurdenMod * (JumpSkill / (JumpSkill + 1300) * 22.2 + 0.05) * power. + /// For a typical new char (skill=100, burden=50%, power=1.0) ≈ 5.07. + /// + public float JumpImpulse { get; set; } = 5.0f; + /// AC's gravity constant (F_GRAVITY = 9.8 m/s²). + public float GravityAccel { get; set; } = 9.8f; public float AirControlFactor { get; set; } = 0.2f; /// diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index 833e93c..8bc256f 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -1562,11 +1562,22 @@ public sealed class GameWindow : IDisposable int observerCx = _liveCenterX; int observerCy = _liveCenterY; - if (_liveSession is not null + if (_playerMode && _playerController is not null) + { + // Player mode: follow the physics-resolved player position. + // The player walks via the local physics engine; the server + // doesn't echo back our autonomous moves, so _lastLivePlayer* + // stays at the login position. Compute the landblock from the + // controller's current world-space position instead. + var pp = _playerController.Position; + observerCx = _liveCenterX + (int)System.Math.Floor(pp.X / 192f); + observerCy = _liveCenterY + (int)System.Math.Floor(pp.Y / 192f); + } + else if (_liveSession is not null && _liveSession.CurrentState == AcDream.Core.Net.WorldSession.State.InWorld && _lastLivePlayerLandblockId is { } lid) { - // Live mode: follow the server's last-known player position. + // Live mode (fly camera): follow the server's last-known player position. observerCx = (int)((lid >> 24) & 0xFFu); observerCy = (int)((lid >> 16) & 0xFFu); }