fix(client): restore retail interaction parity
All checks were successful
CI / linux-portable (push) Successful in 3m27s
CI / windows-gate (push) Successful in 6m42s
CI / release (push) Successful in 2m12s

Harden keyboard and camera routing, inventory and vendor interactions, chat/emotes, relog portal flow, and paperdoll rendering. Add retail research, connected gate coverage, and release-gate validation.
This commit is contained in:
Erik 2026-08-26 20:45:11 +02:00
parent 0c699240e0
commit f6fe0f2a4f
151 changed files with 10162 additions and 1211 deletions

View file

@ -110,7 +110,11 @@ public readonly record struct MovementResult(
// MovementManager's complete RawMotionState into MoveToStatePack. An
// absent style bit unpacks as NonCombat, so the canonical raw style must
// travel with every input-boundary snapshot sent to ACE.
uint CurrentStyle = 0x8000003Du);
uint CurrentStyle = 0x8000003Du,
// Retail SendMovementEvent snapshots the COMPLETE RawMotionState
// synchronously. Command-originated motions use this one-shot override so
// the action FIFO/state survives the render-tick input projection.
RawMotionState? RawMotionStateOverride = null);
/// <summary>
/// Portal-space state for the player movement controller.
@ -530,6 +534,25 @@ public sealed class PlayerMovementController
/// </summary>
public JumpChargeSnapshot JumpCharge
=> new(_jumpCharging, _jumpCharging ? _jumpExtent : 0f);
/// <summary>
/// Retail <c>CommandInterpreter::IsStandingStill</c>: the exact motion-
/// interpreter predicate consumed by Escape before it reaches selection
/// or the Gameplay Options fallback.
/// </summary>
internal bool IsStandingStill => _motion.IsStandingStill();
/// <summary>
/// Retail <c>ClientCombatSystem::FinishJump</c> (0x0056A9B0): end an
/// in-progress jump power build without executing the jump and clear the
/// standing-long-jump arm on the motion interpreter.
/// </summary>
internal void FinishJump()
{
_jumpCharging = false;
_jumpExtent = 0f;
_motion.StandingLongJump = false;
}
// Matching v11.4186 x86 resolves GetPowerBarLevel's collapsed x87
// operands: ATTACK_POWERUP_TIME=1.0 s, DUAL_WIELD_POWERUP_TIME=0.8 s.
// Jump uses the same shared powerbar function, so its normal fill rate is
@ -656,6 +679,8 @@ public sealed class PlayerMovementController
private readonly AcDream.Core.Physics.Motion.MotionDeltaFrame
_positionManagerDeltaScratch = new();
private bool _externalMovementEventPending;
private RawMotionState? _externalRawMotionStatePending;
private uint _localActionStamp;
// ── R4-V5: the verbatim retail MoveToManager replaces B.6 auto-walk ──
// The B.6 DriveServerAutoWalk overlay (synthesized turn-first phase,
@ -1441,6 +1466,34 @@ public sealed class PlayerMovementController
return true;
}
/// <summary>
/// Retail <c>ACCmdInterp::SetMotion</c> (<c>0x0058B310</c>) with
/// start=true: submit one raw command through the local physics-object
/// boundary and publish the resulting movement edge on the next turn.
/// </summary>
internal bool RequestCommandMotion(uint motion)
{
EnsurePublishedForRuntimeOperation();
TakeControlFromServer();
var parameters =
new AcDream.Core.Physics.Motion.MovementParameters
{
Autonomous = true,
ActionStamp = _localActionStamp,
};
if (DoMotionAtPhysicsObjectBoundary(motion, parameters)
!= WeenieError.None)
{
return false;
}
if ((motion & 0x10000000u) != 0u)
_localActionStamp++;
_externalRawMotionStatePending = new RawMotionState(_motion.RawState);
_externalMovementEventPending = true;
return true;
}
public void SetCharacterSkills(int runSkill, int jumpSkill)
{
EnsureConfigurationMutable();
@ -2452,6 +2505,9 @@ public sealed class PlayerMovementController
bool externallyRequestedMovementEvent =
_externalMovementEventPending;
_externalMovementEventPending = false;
RawMotionState? externalRawMotionState =
_externalRawMotionStatePending;
_externalRawMotionStatePending = null;
bool motionEdgeFired = false;
bool movementEventRequested =
externallyRequestedMovementEvent;
@ -3189,7 +3245,8 @@ public sealed class PlayerMovementController
SidestepUsesRunHold: _activeInputSidestepUsesRunHold
&& outSidestepCmd.HasValue,
IsMouseLookMovementEvent: mouseMovementEventDue,
CurrentStyle: _motion.RawState.CurrentStyle);
CurrentStyle: _motion.RawState.CurrentStyle,
RawMotionStateOverride: externalRawMotionState);
}
/// <summary>