fix(anim): Phase L.1c seed move-to locomotion
Retail MoveToManager::BeginMoveForward calls MovementParameters::get_command (0x0052AA00) and then _DoMotion/adjust_motion, so a server-controlled MoveTo begins visible forward locomotion before the next UpdatePosition echo. Seed RunForward for MoveTo packets that omit ForwardCommand, while preserving active locomotion and letting position velocity refine walk/run/stop.
This commit is contained in:
parent
7656fe0970
commit
4dd8d4b46e
3 changed files with 36 additions and 7 deletions
|
|
@ -2273,16 +2273,30 @@ public sealed class GameWindow : IDisposable
|
||||||
// command == null → retail stop signal → Ready
|
// command == null → retail stop signal → Ready
|
||||||
// command.Value == 0 → explicit 0 (rare) → Ready
|
// command.Value == 0 → explicit 0 (rare) → Ready
|
||||||
// otherwise → resolve class byte and use full cmd
|
// otherwise → resolve class byte and use full cmd
|
||||||
|
float speedMod = update.MotionState.ForwardSpeed ?? 1f;
|
||||||
uint fullMotion;
|
uint fullMotion;
|
||||||
if ((!command.HasValue || command.Value == 0)
|
if ((!command.HasValue || command.Value == 0)
|
||||||
&& update.MotionState.IsServerControlledMoveTo)
|
&& update.MotionState.IsServerControlledMoveTo)
|
||||||
{
|
{
|
||||||
// MoveTo packets preserve the current cycle until velocity
|
|
||||||
// chooses the visible walk/run/ready state.
|
|
||||||
uint current = ae.Sequencer.CurrentMotion;
|
uint current = ae.Sequencer.CurrentMotion;
|
||||||
fullMotion = (current & 0xFF000000u) != 0
|
if (IsRemoteLocomotion(current))
|
||||||
? current
|
{
|
||||||
: AcDream.Core.Physics.MotionCommand.Ready;
|
// MoveTo packets preserve an active locomotion cycle;
|
||||||
|
// position velocity will refine the speed.
|
||||||
|
fullMotion = current;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Retail MoveToManager::BeginMoveForward calls
|
||||||
|
// MovementParameters::get_command (0x0052AA00), then
|
||||||
|
// _DoMotion -> adjust_motion. With default CanRun and
|
||||||
|
// enough distance, WalkForward + HoldKey_Run becomes
|
||||||
|
// RunForward immediately, before the next position echo.
|
||||||
|
var seed = AcDream.Core.Physics.ServerControlledLocomotion
|
||||||
|
.PlanMoveToStart();
|
||||||
|
fullMotion = seed.Motion;
|
||||||
|
speedMod = seed.SpeedMod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!command.HasValue || command.Value == 0)
|
else if (!command.HasValue || command.Value == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -2313,8 +2327,6 @@ public sealed class GameWindow : IDisposable
|
||||||
// apply_run_to_command). Treating zero as "unspecified / 1.0"
|
// apply_run_to_command). Treating zero as "unspecified / 1.0"
|
||||||
// produces "slow walk that never stops" — exactly what the
|
// produces "slow walk that never stops" — exactly what the
|
||||||
// stop bug looked like.
|
// stop bug looked like.
|
||||||
float speedMod = update.MotionState.ForwardSpeed ?? 1f;
|
|
||||||
|
|
||||||
if (Environment.GetEnvironmentVariable("ACDREAM_DUMP_MOTION") == "1"
|
if (Environment.GetEnvironmentVariable("ACDREAM_DUMP_MOTION") == "1"
|
||||||
&& update.Guid != _playerServerGuid)
|
&& update.Guid != _playerServerGuid)
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,13 @@ public static class ServerControlledLocomotion
|
||||||
public const float MinSpeedMod = 0.25f;
|
public const float MinSpeedMod = 0.25f;
|
||||||
public const float MaxSpeedMod = 3.00f;
|
public const float MaxSpeedMod = 3.00f;
|
||||||
|
|
||||||
|
// Retail MoveToManager::BeginMoveForward -> MovementParameters::get_command
|
||||||
|
// (0x0052AA00) seeds forward motion before the next position update.
|
||||||
|
public static LocomotionCycle PlanMoveToStart()
|
||||||
|
{
|
||||||
|
return new LocomotionCycle(MotionCommand.RunForward, 1f, true);
|
||||||
|
}
|
||||||
|
|
||||||
public static LocomotionCycle PlanFromVelocity(Vector3 worldVelocity)
|
public static LocomotionCycle PlanFromVelocity(Vector3 worldVelocity)
|
||||||
{
|
{
|
||||||
float horizontalSpeed = MathF.Sqrt(
|
float horizontalSpeed = MathF.Sqrt(
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,16 @@ namespace AcDream.Core.Tests.Physics;
|
||||||
|
|
||||||
public sealed class ServerControlledLocomotionTests
|
public sealed class ServerControlledLocomotionTests
|
||||||
{
|
{
|
||||||
|
[Fact]
|
||||||
|
public void PlanMoveToStart_SeedsImmediateRunCycle()
|
||||||
|
{
|
||||||
|
var plan = ServerControlledLocomotion.PlanMoveToStart();
|
||||||
|
|
||||||
|
Assert.True(plan.IsMoving);
|
||||||
|
Assert.Equal(MotionCommand.RunForward, plan.Motion);
|
||||||
|
Assert.Equal(1.0f, plan.SpeedMod);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void PlanFromVelocity_StopsBelowRetailNoiseThreshold()
|
public void PlanFromVelocity_StopsBelowRetailNoiseThreshold()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue