Retail MovementManager::PerformMovement (0x00524440) reads MoveTo speed and runRate from the packet, MovementParameters::UnPackNet (0x0052AC50) defines the layout, and CMotionInterp::apply_run_to_command (0x00527BE0) multiplies RunForward by runRate. Parse those fields for UpdateMotion/CreateObject, seed server-controlled MoveTo locomotion with the retail speed multiplier, and avoid overriding active monster MoveTo with sparse UpdatePosition-derived velocity.
88 lines
2.6 KiB
C#
88 lines
2.6 KiB
C#
using System.Numerics;
|
|
using AcDream.Core.Physics;
|
|
using Xunit;
|
|
|
|
namespace AcDream.Core.Tests.Physics;
|
|
|
|
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]
|
|
public void PlanMoveToStart_AppliesRetailRunRate()
|
|
{
|
|
var plan = ServerControlledLocomotion.PlanMoveToStart(
|
|
moveToSpeed: 1.25f,
|
|
runRate: 1.5f,
|
|
canRun: true);
|
|
|
|
Assert.True(plan.IsMoving);
|
|
Assert.Equal(MotionCommand.RunForward, plan.Motion);
|
|
Assert.Equal(1.875f, plan.SpeedMod);
|
|
}
|
|
|
|
[Fact]
|
|
public void PlanMoveToStart_UsesWalkWhenRunDisallowed()
|
|
{
|
|
var plan = ServerControlledLocomotion.PlanMoveToStart(
|
|
moveToSpeed: 0.75f,
|
|
runRate: 2.0f,
|
|
canRun: false);
|
|
|
|
Assert.True(plan.IsMoving);
|
|
Assert.Equal(MotionCommand.WalkForward, plan.Motion);
|
|
Assert.Equal(0.75f, plan.SpeedMod);
|
|
}
|
|
|
|
[Fact]
|
|
public void PlanFromVelocity_StopsBelowRetailNoiseThreshold()
|
|
{
|
|
var plan = ServerControlledLocomotion.PlanFromVelocity(
|
|
new Vector3(0.10f, 0.12f, 3.0f));
|
|
|
|
Assert.False(plan.IsMoving);
|
|
Assert.Equal(MotionCommand.Ready, plan.Motion);
|
|
Assert.Equal(1.0f, plan.SpeedMod);
|
|
}
|
|
|
|
[Fact]
|
|
public void PlanFromVelocity_WalksForSlowServerControlledMotion()
|
|
{
|
|
var plan = ServerControlledLocomotion.PlanFromVelocity(
|
|
new Vector3(0.0f, 0.80f, 0.0f));
|
|
|
|
Assert.True(plan.IsMoving);
|
|
Assert.Equal(MotionCommand.WalkForward, plan.Motion);
|
|
Assert.InRange(plan.SpeedMod, 0.25f, 0.27f);
|
|
}
|
|
|
|
[Fact]
|
|
public void PlanFromVelocity_RunsAtRetailRunScale()
|
|
{
|
|
var plan = ServerControlledLocomotion.PlanFromVelocity(
|
|
new Vector3(0.0f, MotionInterpreter.RunAnimSpeed, 0.0f));
|
|
|
|
Assert.True(plan.IsMoving);
|
|
Assert.Equal(MotionCommand.RunForward, plan.Motion);
|
|
Assert.Equal(1.0f, plan.SpeedMod, precision: 4);
|
|
}
|
|
|
|
[Fact]
|
|
public void PlanFromVelocity_ClampsVeryFastSnapshots()
|
|
{
|
|
var plan = ServerControlledLocomotion.PlanFromVelocity(
|
|
new Vector3(0.0f, 30.0f, 0.0f));
|
|
|
|
Assert.True(plan.IsMoving);
|
|
Assert.Equal(MotionCommand.RunForward, plan.Motion);
|
|
Assert.Equal(ServerControlledLocomotion.MaxSpeedMod, plan.SpeedMod);
|
|
}
|
|
}
|