fix(anim): remote-entity stop detection from position deltas
Root cause found from ACE source:
- Player_Tick.cs:368 — "the client will never send a 'client released
forward' MoveToState in this scenario unfortunately"
- Server therefore can't broadcast a MotionCommand.Ready UpdateMotion
when a remote player stops moving.
- Retail observer infers stopped state from position deltas going to
zero, not from an explicit motion message.
Also found + fixed the UpdateMotion parser's 2-byte offset bug: ACE's
Align() pads based on absolute stream length (length=15 → 1 pad byte),
not relative-to-block. Previous parser assumed 3 pad bytes after the
MovementData header, which mis-aligned every subsequent field by 2.
After fix, stance/command/speed decode correctly for both server-
controlled NPCs (full stance 0x003D + cmd transitions) and remote
players (stance=0 meaning "no change" + per-axis commands).
OnLiveMotionUpdated rewrite: use SetCycle directly for sequencer
entities instead of routing through GetIdleCycle (which ignored
command when stance was 0). Preserve current style/motion when the
server omits a field ("no change" semantics). Reconstruct full
MotionCommand high byte from current motion or SubState mask.
Remote stop-detection: new _remoteLastMove dict tracks per-entity last
meaningful position + time. OnLivePositionUpdated updates only on
moves > 0.05m so the timestamp captures last actual movement.
TickAnimations checks every entity in a locomotion cycle; if their
last-move time is >400ms stale, swap sequencer to Ready. Excludes
player's own entity (driven by local input, not server observation).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b092a6090d
commit
53f0110b89
2 changed files with 191 additions and 35 deletions
|
|
@ -86,13 +86,23 @@ public static class UpdateMotion
|
|||
pos += 2;
|
||||
|
||||
// MovementData header: u16 movementSequence, u16 serverControlSequence,
|
||||
// u8 isAutonomous, then align to 4. The header bytes total 6 (2+2+1+1 pad),
|
||||
// because 2+2+1 = 5, and aligning to 4 from offset 5 needs 3 pad bytes...
|
||||
// Actually, ACE's writer.Align() pads the CURRENT BaseStream position
|
||||
// after writing the byte, so after u16 + u16 + u8 we're at 5 bytes into
|
||||
// MovementData; alignment rounds up to 8. So the header slot is 8 bytes.
|
||||
if (body.Length - pos < 8) return null;
|
||||
pos += 8;
|
||||
// u8 isAutonomous, then Align().
|
||||
//
|
||||
// ACE's Align() (Network/Extensions.cs:55) uses
|
||||
// CalculatePadMultiple(BaseStream.Length, 4) — i.e. it pads based on
|
||||
// the ABSOLUTE stream length, not a relative offset within the
|
||||
// MovementData block.
|
||||
//
|
||||
// At this point the absolute stream has: opcode (4) + guid (4) +
|
||||
// objectInstance (2) + movSeq (2) + srvSeq (2) + isAut (1) = 15.
|
||||
// Align(4) rounds 15 → 16, so ONE pad byte is written.
|
||||
// MovementData header = 2+2+1+1 = 6 bytes.
|
||||
//
|
||||
// Previous version mistakenly reserved 8 bytes here, which shifted
|
||||
// every subsequent field by 2 and made every remote-char UpdateMotion
|
||||
// decode as garbage (stance read from the packed-flags dword).
|
||||
if (body.Length - pos < 6) return null;
|
||||
pos += 6;
|
||||
|
||||
// movementType u8, motionFlags u8, currentStyle u16
|
||||
if (body.Length - pos < 4) return null;
|
||||
|
|
@ -101,6 +111,15 @@ public static class UpdateMotion
|
|||
ushort currentStyle = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(pos));
|
||||
pos += 2;
|
||||
|
||||
if (Environment.GetEnvironmentVariable("ACDREAM_DUMP_MOTION") == "1")
|
||||
{
|
||||
int preHex = Math.Min(body.Length, 32);
|
||||
var hex = new System.Text.StringBuilder();
|
||||
for (int i = 0; i < preHex; i++) hex.Append($"{body[i]:X2} ");
|
||||
System.Console.WriteLine(
|
||||
$" UM raw: mt=0x{movementType:X2} mf=0x{_motionFlags:X2} cs=0x{currentStyle:X4} | {hex}");
|
||||
}
|
||||
|
||||
ushort? forwardCommand = null;
|
||||
float? forwardSpeed = null;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue