feat(movement): wire server RunRate into player MotionInterpreter
Parse ForwardSpeed from UpdateMotion (0xF74C) InterpretedMotionState. Feed server-echoed RunRate into the player's MotionInterpreter so get_state_velocity produces the correct speed. Previously hardcoded at 1.0 (4.0 m/s), now matches character's Run skill. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4988ea02c0
commit
c7fa1d36fb
5 changed files with 71 additions and 7 deletions
|
|
@ -115,6 +115,18 @@ public sealed class PlayerMovementController
|
|||
_motion = new MotionInterpreter(_body);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply a server-echoed run rate (ForwardSpeed from UpdateMotion) to the
|
||||
/// player's MotionInterpreter. The server broadcasts the real RunRate
|
||||
/// derived from the character's Run skill; wiring it here ensures
|
||||
/// get_state_velocity produces the correct speed instead of the default 1.0.
|
||||
/// </summary>
|
||||
public void ApplyServerRunRate(float forwardSpeed)
|
||||
{
|
||||
_motion.InterpretedState.ForwardSpeed = forwardSpeed;
|
||||
_motion.apply_current_movement(cancelMoveTo: false, allowJump: false);
|
||||
}
|
||||
|
||||
public void SetPosition(Vector3 pos, uint cellId)
|
||||
{
|
||||
_body.Position = pos;
|
||||
|
|
|
|||
|
|
@ -952,6 +952,18 @@ public sealed class GameWindow : IDisposable
|
|||
if (!newCycleIsGood)
|
||||
return;
|
||||
|
||||
// Wire server-echoed RunRate into the player's MotionInterpreter.
|
||||
// The server broadcasts the character's real Run-skill-derived ForwardSpeed
|
||||
// in UpdateMotion; without this the player would always move at 4.0 m/s
|
||||
// (ForwardSpeed = 1.0 hardcoded in MotionInterpreter defaults).
|
||||
if (_playerController is not null
|
||||
&& update.Guid == _playerServerGuid
|
||||
&& update.MotionState.ForwardSpeed.HasValue
|
||||
&& update.MotionState.ForwardSpeed.Value > 0f)
|
||||
{
|
||||
_playerController.ApplyServerRunRate(update.MotionState.ForwardSpeed.Value);
|
||||
}
|
||||
|
||||
// Sequencer path
|
||||
if (ae.Sequencer is not null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ public static class CreateObject
|
|||
/// Nullified Statue of a Drudge, which is rendered in the wrong pose
|
||||
/// if you only consult the MotionTable's default style.
|
||||
/// </summary>
|
||||
public readonly record struct ServerMotionState(ushort Stance, ushort? ForwardCommand);
|
||||
public readonly record struct ServerMotionState(ushort Stance, ushort? ForwardCommand, float? ForwardSpeed = null);
|
||||
|
||||
/// <summary>
|
||||
/// Server instruction to replace the surface texture at
|
||||
|
|
@ -479,6 +479,7 @@ public static class CreateObject
|
|||
p += 2;
|
||||
|
||||
ushort? forwardCommand = null;
|
||||
float? forwardSpeed = null;
|
||||
|
||||
// 0 = Invalid is the only union variant we care about for static
|
||||
// entities. Walking/turning entities use the other variants but
|
||||
|
|
@ -513,13 +514,21 @@ public static class CreateObject
|
|||
forwardCommand = BinaryPrimitives.ReadUInt16LittleEndian(mv.Slice(p));
|
||||
p += 2;
|
||||
}
|
||||
// Remaining fields (SideStep, Turn, speeds, commands list,
|
||||
// align) are deliberately not parsed — we already have what
|
||||
// the resolver needs and the outer length tells the caller
|
||||
// where MovementData ends.
|
||||
// SidestepCommand (0x4) — skip
|
||||
if ((flags & 0x4u) != 0) { if (mv.Length - p < 2) goto done; p += 2; }
|
||||
// TurnCommand (0x8) — skip
|
||||
if ((flags & 0x8u) != 0) { if (mv.Length - p < 2) goto done; p += 2; }
|
||||
// ForwardSpeed (0x10)
|
||||
if ((flags & 0x10u) != 0)
|
||||
{
|
||||
if (mv.Length - p < 4) goto done;
|
||||
forwardSpeed = BinaryPrimitives.ReadSingleLittleEndian(mv.Slice(p));
|
||||
p += 4;
|
||||
}
|
||||
done:;
|
||||
}
|
||||
|
||||
return new ServerMotionState(currentStyle, forwardCommand);
|
||||
return new ServerMotionState(currentStyle, forwardCommand, forwardSpeed);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ public static class UpdateMotion
|
|||
pos += 2;
|
||||
|
||||
ushort? forwardCommand = null;
|
||||
float? forwardSpeed = null;
|
||||
|
||||
if (movementType == 0)
|
||||
{
|
||||
|
|
@ -130,9 +131,21 @@ public static class UpdateMotion
|
|||
forwardCommand = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(pos));
|
||||
pos += 2;
|
||||
}
|
||||
// SidestepCommand (0x4) — skip
|
||||
if ((flags & 0x4u) != 0) { if (body.Length - pos < 2) goto done; pos += 2; }
|
||||
// TurnCommand (0x8) — skip
|
||||
if ((flags & 0x8u) != 0) { if (body.Length - pos < 2) goto done; pos += 2; }
|
||||
// ForwardSpeed (0x10)
|
||||
if ((flags & 0x10u) != 0)
|
||||
{
|
||||
if (body.Length - pos < 4) goto done;
|
||||
forwardSpeed = BinaryPrimitives.ReadSingleLittleEndian(body.Slice(pos));
|
||||
pos += 4;
|
||||
}
|
||||
done:;
|
||||
}
|
||||
|
||||
return new Parsed(guid, new CreateObject.ServerMotionState(currentStyle, forwardCommand));
|
||||
return new Parsed(guid, new CreateObject.ServerMotionState(currentStyle, forwardCommand, forwardSpeed));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue