User observation (acdream observing a retail player's server MoveTo): walk-distance approaches correct; run-distance plays the run cycle AND moves toward the target in slow motion. Root cause, raw-verified (apply_run_to_command 0x00527be0, raw 305062-305076): retail's rate chain is weenie ? (InqRunRate() ?: my_run_rate) : 1.0 Every placed retail object HAS a weenie; a REMOTE's weenie fails InqRunRate (no local skill data) and the chain lands on my_run_rate - the exact field retail's mt-6/7 unpack writes with the wire's MoveToRunRate (M13; observed 4.50). Our port had the branch verbatim but remote interps carried NO weenie at all, taking the else-1.0 branch retail reserves for weenie-less detached objects: observer-side run dispatches went out at speed 1.0, so the run cycle's pace AND get_state_velocity's chase speed both crawled. Walk was unaffected - walk speed is never rate-scaled (the discriminating symptom). Fix: RemoteWeenie (Core) - the minimal stand-in for retail's per-object ACCWeenieObject: InqRunRate fails (-> my_run_rate), InqJumpVelocity fails, IsThePlayer default false (also ends the fragile "null weenie counts as the player" reading of the A3 dual dispatch for remotes), IsCreature default true (doors carry it too; their force-asserted Contact keeps the creature ground-gate moot - documented on the class). RemoteMotion's interp now constructs with it. Tests: RemoteWeenieRunRateTests pins both branches against the raw - RemoteWeenie + MyRunRate=4.5 promotes WalkForward->RunForward @ 4.5; weenie-less keeps the verbatim degenerate 1.0. Full suite green: 3,963. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
52 lines
1.8 KiB
C#
52 lines
1.8 KiB
C#
using AcDream.Core.Physics;
|
|
using Xunit;
|
|
|
|
namespace AcDream.Core.Tests.Physics;
|
|
|
|
/// <summary>
|
|
/// R4-V5 #160 fix: retail's apply_run_to_command (0x00527be0) run-rate
|
|
/// chain is <c>weenie ? (InqRunRate() ?: my_run_rate) : 1.0</c>. Remote
|
|
/// weenies FAIL InqRunRate, landing on my_run_rate — the field the mt-6/7
|
|
/// unpack writes with the wire's MoveToRunRate (M13). These pin that a
|
|
/// RemoteWeenie-equipped interp scales the run promotion by MyRunRate
|
|
/// (observer-side movetos ran in slow motion when the interp had no
|
|
/// weenie and took the degenerate 1.0 branch).
|
|
/// </summary>
|
|
public class RemoteWeenieRunRateTests
|
|
{
|
|
[Fact]
|
|
public void ApplyRunToCommand_RemoteWeenie_ScalesByWireRunRate()
|
|
{
|
|
var interp = new MotionInterpreter(new PhysicsBody())
|
|
{
|
|
WeenieObj = new RemoteWeenie(),
|
|
MyRunRate = 4.5f, // the mt-6 wire write (unpack @300603)
|
|
};
|
|
|
|
uint motion = MotionCommand.WalkForward;
|
|
float speed = 1.0f;
|
|
interp.apply_run_to_command(ref motion, ref speed);
|
|
|
|
Assert.Equal(MotionCommand.RunForward, motion);
|
|
Assert.Equal(4.5f, speed, 3);
|
|
}
|
|
|
|
[Fact]
|
|
public void ApplyRunToCommand_NoWeenie_KeepsRetailDegenerateBranch()
|
|
{
|
|
// Verbatim retail: a weenie-LESS (detached-class) object scales by
|
|
// 1.0 (raw 305062-305076 `else x87_r7 = 1f`). Production bodies all
|
|
// carry a weenie (player: PlayerWeenie; remotes: RemoteWeenie).
|
|
var interp = new MotionInterpreter(new PhysicsBody())
|
|
{
|
|
MyRunRate = 4.5f,
|
|
};
|
|
|
|
uint motion = MotionCommand.WalkForward;
|
|
float speed = 1.0f;
|
|
interp.apply_run_to_command(ref motion, ref speed);
|
|
|
|
Assert.Equal(MotionCommand.RunForward, motion);
|
|
Assert.Equal(1.0f, speed, 3);
|
|
}
|
|
}
|