feat(headless): complete deterministic bot command parity
This commit is contained in:
parent
7e8acb74dd
commit
38e83640d9
37 changed files with 2805 additions and 295 deletions
|
|
@ -411,6 +411,7 @@ public sealed class PlayerMovementController
|
|||
_animationRootMotionScratch = new();
|
||||
private readonly AcDream.Core.Physics.Motion.MotionDeltaFrame
|
||||
_positionManagerDeltaScratch = new();
|
||||
private bool _externalMovementEventPending;
|
||||
|
||||
// ── R4-V5: the verbatim retail MoveToManager replaces B.6 auto-walk ──
|
||||
// The B.6 DriveServerAutoWalk overlay (synthesized turn-first phase,
|
||||
|
|
@ -856,6 +857,35 @@ public sealed class PlayerMovementController
|
|||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a command-originated retail posture through the same
|
||||
/// CPhysicsObj movement boundary used by keyboard input. The next admitted
|
||||
/// object turn emits the resulting raw movement state exactly once.
|
||||
/// </summary>
|
||||
public bool RequestPosture(uint motion)
|
||||
{
|
||||
if (motion is not (
|
||||
MotionCommand.Ready
|
||||
or MotionCommand.Crouch
|
||||
or MotionCommand.Sitting
|
||||
or MotionCommand.Sleeping))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TakeControlFromServer();
|
||||
var parameters =
|
||||
new AcDream.Core.Physics.Motion.MovementParameters();
|
||||
if (DoMotionAtPhysicsObjectBoundary(motion, parameters)
|
||||
!= WeenieError.None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_externalMovementEventPending = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetCharacterSkills(int runSkill, int jumpSkill)
|
||||
{
|
||||
_weenie.SetSkills(runSkill, jumpSkill);
|
||||
|
|
@ -1455,8 +1485,12 @@ public sealed class PlayerMovementController
|
|||
_motion.set_hold_run(input.Run, interrupt: false);
|
||||
}
|
||||
|
||||
bool externallyRequestedMovementEvent =
|
||||
_externalMovementEventPending;
|
||||
_externalMovementEventPending = false;
|
||||
bool motionEdgeFired = false;
|
||||
bool movementEventRequested = false;
|
||||
bool movementEventRequested =
|
||||
externallyRequestedMovementEvent;
|
||||
{
|
||||
bool userInputEdge = input.Run != _prevRunHeld
|
||||
|| input.Forward != _prevForwardHeld
|
||||
|
|
@ -1511,7 +1545,7 @@ public sealed class PlayerMovementController
|
|||
// an immediate SendMovementEvent. Mouse-origin turn updates below
|
||||
// deliberately do not: CameraSet reports them on its separate
|
||||
// half-second cadence.
|
||||
movementEventRequested = motionEdgeFired;
|
||||
movementEventRequested |= motionEdgeFired;
|
||||
|
||||
// Turn channel. Retail CameraSet::Rotate (0x00458310) feeds mouse
|
||||
// input through CommandInterpreter::MovePlayer as TurnLeft /
|
||||
|
|
@ -1937,6 +1971,14 @@ public sealed class PlayerMovementController
|
|||
outForwardCmd = MotionCommand.WalkBackward;
|
||||
outForwardSpeed = 1.0f;
|
||||
}
|
||||
else if (_motion.RawState.ForwardCommand is (
|
||||
MotionCommand.Crouch
|
||||
or MotionCommand.Sitting
|
||||
or MotionCommand.Sleeping))
|
||||
{
|
||||
outForwardCmd = _motion.RawState.ForwardCommand;
|
||||
outForwardSpeed = _motion.RawState.ForwardSpeed;
|
||||
}
|
||||
|
||||
// Source the outbound axis from the canonical input-owned raw channel.
|
||||
// CameraInstantMouseLook maps keyboard TurnLeft/TurnRight into this
|
||||
|
|
@ -1979,7 +2021,8 @@ public sealed class PlayerMovementController
|
|||
|| outTurnCmd != _prevTurnCmd
|
||||
|| !FloatsEqual(outForwardSpeed, _prevForwardSpeed)
|
||||
|| runHold != _prevRunHold
|
||||
|| motionEdgeFired;
|
||||
|| motionEdgeFired
|
||||
|| externallyRequestedMovementEvent;
|
||||
|
||||
bool mouseMovementEventDue = _mouseMovementEventPending
|
||||
|| (_mouseMovementEventCandidate
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue