feat(player): use server-authoritative Run + Jump skill values from PlayerDescription

Before this commit, PlayerWeenie used hardcoded ACDREAM_RUN_SKILL
(default 200) and ACDREAM_JUMP_SKILL (default 300) regardless of
the actual character skill. PlayerDescription's skill table HAS
been parsed since Phase H, but the values weren't plumbed into
PlayerMovementController, so a high-Jump character still got the
3-4m default arc instead of their real 5m+ arc, and a low-Jump
character got too much.

GameEventWiring.WireAll gains an optional `onSkillsUpdated`
callback. The PlayerDescription handler scans the parsed skill
table for SkillId 24 (Run) and SkillId 22 (Jump) — ACE Skill enum
ordinals from references/ACE/.../Enum/Skill.cs:11-37 — and fires
the callback with `init + ranks` for each (the holtburger-named
"init" field is the attribute-derived initial component, ranks
is XP-bought additions; closest sane approximation of ACE's
CreatureSkill.Current short of porting Aug + Multiplier + Vitae
chains).

GameWindow stores the most recent values in _lastSeenRunSkill /
_lastSeenJumpSkill and pushes them into the controller at two
points:
  * Immediately if _playerController already exists (PD arriving
    mid-session, e.g. after a relog).
  * Inside EnterPlayerModeNow when constructing a fresh
    controller (the auto-entry path: PD always arrives at login
    before auto-entry fires, so this is the normal path).

Both sites also log "applied server skills run=X jump=Y" so live
testing can confirm the right values reached the formula.

Console output (ACDREAM_DUMP_VITALS=1) gains a "vitals: PD-skills
run=X jump=Y" line on every PlayerDescription with skill data.

Tests stay 1222 green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-26 17:22:59 +02:00
parent 5145938d06
commit 1fce21034a
2 changed files with 83 additions and 2 deletions

View file

@ -383,6 +383,17 @@ public sealed class GameWindow : IDisposable
private uint? _playerCurrentAnimCommand;
private float _playerCurrentAnimSpeed = 1f;
private uint? _playerMotionTableId; // server-sent MotionTable override for the player's character
// K-fix7 (2026-04-26): server-authoritative Run + Jump skill values
// received from PlayerDescription. -1 = "not yet received, fall back
// to the controller's default (env-var or hardcoded 200/300)".
// Captured by the GameEventWiring.WireAll callback the moment PD
// arrives; pushed into _playerController via SetCharacterSkills both
// immediately (if the controller already exists from auto-entry) and
// again at every EnterPlayerModeNow so a player who Tab-toggles in
// and out keeps the right skills.
private int _lastSeenRunSkill = -1;
private int _lastSeenJumpSkill = -1;
// K.1b: this field is RESERVED — written when entering / leaving player
// mode and previously fed mouse-X into MovementInput.MouseDeltaX. Now
// never consumed by MovementInput (mouse never drives character yaw —
@ -1198,7 +1209,28 @@ public sealed class GameWindow : IDisposable
// the corresponding client-side state without further glue.
AcDream.Core.Net.GameEventWiring.WireAll(
_liveSession.GameEvents, Items, Combat, SpellBook, Chat, LocalPlayer,
TurbineChat);
TurbineChat,
onSkillsUpdated: (runSkill, jumpSkill) =>
{
// K-fix7 (2026-04-26): cache the latest server-sent
// Run / Jump skill values so the next
// EnterPlayerModeNow can hand them to the new
// PlayerMovementController. Push immediately too,
// so a PD that arrives WHILE player mode is active
// (re-equip / log-in mid-session) updates the live
// controller. -1 from the wiring means "skill not
// present in this PD" — keep the previous cached
// value rather than overwriting with -1.
if (runSkill >= 0) _lastSeenRunSkill = runSkill;
if (jumpSkill >= 0) _lastSeenJumpSkill = jumpSkill;
if (_playerController is not null
&& _lastSeenRunSkill >= 0 && _lastSeenJumpSkill >= 0)
{
_playerController.SetCharacterSkills(
_lastSeenRunSkill, _lastSeenJumpSkill);
Console.WriteLine($"player: applied server skills run={_lastSeenRunSkill} jump={_lastSeenJumpSkill}");
}
});
// Phase I.7: subscribe to CombatState events and emit
// retail-faithful "You hit X for Y damage" chat lines into
@ -5504,6 +5536,17 @@ public sealed class GameWindow : IDisposable
}
_playerController = new AcDream.App.Input.PlayerMovementController(_physicsEngine);
// K-fix7 (2026-04-26): if PlayerDescription already arrived, the
// server's Run / Jump skill values are cached here — push them
// into the freshly-constructed controller so the runRate /
// jump-arc formulas use real character data instead of the
// hardcoded ACDREAM_*_SKILL defaults. PD always arrives at
// login before auto-entry fires, so this branch normally hits.
if (_lastSeenRunSkill >= 0 && _lastSeenJumpSkill >= 0)
{
_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.
if (_dats is not null && (playerEntity.SourceGfxObjOrSetupId & 0xFF000000u) == 0x02000000u)
{