feat(D6.2b): send retail-faithful raw forward_speed=1.0 on the wire
The outbound MoveToState now sends the RAW forward_speed 1.0 (omitted by
default-difference packing) instead of the pre-computed runRate, matching what
retail's client sends.
Settled the open question with a live echo-test: acdream sends forward_speed=1.0,
ACE broadcasts back RunForward @ runRate (not 1.0), and a retail observer saw
+Acdream run at full pace. So ACE RECOMPUTES the broadcast run speed from the
character's run skill and auto-upgrades WalkForward+HoldKey.Run -> RunForward for
observers. The earlier PlayerMovementController comment citing ACE
MovementData.cs ("ACE relays the speed, so the wire must send run_rate") was
wrong; corrected.
Changes:
- PlayerMovementController section 6: forward wire command is WalkForward @ 1.0
(+ HoldKey.Run when running); LocalAnimationCommand still carries RunForward for
the local cycle. Backward already 1.0. The MotionStateChanged detection now
keys the walk<->run toggle off HoldKey + LocalAnimationCommand (forward_speed is
constant 1.0); the forward_speed comparison is retained but never fires.
- GameWindow: reverted the D6.2b echo-test one-liner; the wire RawMotionState
takes forward_speed from result (now 1.0).
The wire and the D6.2a local velocity are now both raw-1.0. Threading them onto
one shared RawMotionState (removing section-6's duplicate build) is a
behavior-neutral cleanup follow-up.
Full suite green (3255). Docs: roadmap + pseudocode doc updated with the
echo-test finding.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
4740750649
commit
d34721fa94
4 changed files with 45 additions and 37 deletions
|
|
@ -627,8 +627,16 @@ change must keep both phase plans in sync.
|
||||||
lateral, turn feel unchanged; no crash/rejection). Retired register
|
lateral, turn feel unchanged; no crash/rejection). Retired register
|
||||||
TS-22 + UN-5; added TS-34 (IsCreature guard no-op). `WalkAnimSpeed` unified to
|
TS-22 + UN-5; added TS-34 (IsCreature guard no-op). `WalkAnimSpeed` unified to
|
||||||
the retail-exact 3.11999989f. Pseudocode:
|
the retail-exact 3.11999989f. Pseudocode:
|
||||||
`docs/research/2026-07-01-d6-motion-interp-pseudocode.md`. NEXT D6.2b: the
|
`docs/research/2026-07-01-d6-motion-interp-pseudocode.md`.)*
|
||||||
echo-gated wire `forward_speed=1.0` question.)
|
*(D6.2b, shipped 2026-07-01:* the wire now sends the retail-faithful RAW
|
||||||
|
`forward_speed=1.0` (omitted by default-difference packing) instead of runRate.
|
||||||
|
Echo-test settled the open question: ACE RECOMPUTES the broadcast run speed from
|
||||||
|
run skill and auto-upgrades WalkForward+HoldKey.Run → RunForward — sending 1.0
|
||||||
|
still broadcasts RunForward @ runRate, and a retail observer saw +Acdream run at
|
||||||
|
full pace. The stale `MovementData.cs`-citing "ACE relays" comment was
|
||||||
|
corrected. Wire + velocity are now both raw-1.0; threading them onto one shared
|
||||||
|
RawMotionState (removing section-6's duplicate build) is a no-op-behavior
|
||||||
|
cleanup follow-up.)
|
||||||
- **L.1c — Combat animation wiring.** Combat mode tracking, draw/sheath
|
- **L.1c — Combat animation wiring.** Combat mode tracking, draw/sheath
|
||||||
style transitions, attack swings by stance/power/height, hit reactions,
|
style transitions, attack swings by stance/power/height, hit reactions,
|
||||||
evades/blocks/parries, and death handoff.
|
evades/blocks/parries, and death handoff.
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,13 @@ Integration seams:
|
||||||
AND the local velocity/turn pipeline (`apply_raw_movement` →
|
AND the local velocity/turn pipeline (`apply_raw_movement` →
|
||||||
`get_state_velocity` + turn omega). The separate GameWindow wire-construction
|
`get_state_velocity` + turn omega). The separate GameWindow wire-construction
|
||||||
is retired; `MovementResult` carries the raw state, GameWindow packs it.
|
is retired; `MovementResult` carries the raw state, GameWindow packs it.
|
||||||
2. **`forward_speed = 1.0` on run (decomp-forced).** The raw `forward_speed`
|
2. **`forward_speed = 1.0` on run — CONFIRMED viable (echo-test 2026-07-01).**
|
||||||
|
The echo-test settled it: acdream sends `forward_speed=1.0`, ACE broadcasts
|
||||||
|
back `RunForward @ runRate` (not `1.0`), and a retail observer saw +Acdream run
|
||||||
|
at full pace — so **ACE recomputes the broadcast run speed from run skill**
|
||||||
|
(the `MovementData.cs`-citing "ACE relays" assumption was wrong). The wire now
|
||||||
|
sends the retail-faithful raw `1.0` (D6.2b). Original reasoning below stands:
|
||||||
|
The raw `forward_speed`
|
||||||
must be `1.0` when running, because `apply_run_to_command` multiplies by
|
must be `1.0` when running, because `apply_run_to_command` multiplies by
|
||||||
run-rate — carrying `runRate` in the raw state would double-scale to
|
run-rate — carrying `runRate` in the raw state would double-scale to
|
||||||
`runRate²`. So the wire now sends `forward_speed=1.0` (omitted by
|
`runRate²`. So the wire now sends `forward_speed=1.0` (omitted by
|
||||||
|
|
|
||||||
|
|
@ -1268,31 +1268,26 @@ public sealed class PlayerMovementController
|
||||||
uint? outTurnCmd = null;
|
uint? outTurnCmd = null;
|
||||||
float? outTurnSpeed = null;
|
float? outTurnSpeed = null;
|
||||||
|
|
||||||
// Retail-faithful wire commands. ACE's MovementData constructor only
|
// Retail-faithful wire commands — the wire carries the RAW motion state:
|
||||||
// computes interpState.ForwardSpeed for WalkForward / WalkBackwards
|
|
||||||
// (Network/Motion/MovementData.cs:104-119) — for any other command
|
|
||||||
// the else-branch passes through without setting speed, so observers
|
|
||||||
// dead-reckon at speed=0. The wire therefore must be:
|
|
||||||
// - Forward (walk): WalkForward @ 1.0
|
// - Forward (walk): WalkForward @ 1.0
|
||||||
// - Forward (run): WalkForward @ run_rate + HoldKey.Run
|
// - Forward (run): WalkForward @ 1.0 + HoldKey.Run
|
||||||
// (ACE auto-upgrades to RunForward for observers)
|
|
||||||
// - Backward: WalkBackward @ 1.0
|
// - Backward: WalkBackward @ 1.0
|
||||||
// Our own local animation still wants the actual RunForward cycle
|
// D6.2b (echo-test 2026-07-01): ACE RECOMPUTES the broadcast run speed
|
||||||
// though — that's carried separately in LocalAnimationCommand below.
|
// from the character's run skill and auto-upgrades WalkForward+HoldKey.Run
|
||||||
|
// → RunForward for observers. Sending the raw forward_speed=1.0 (omitted by
|
||||||
|
// default-difference packing) still broadcasts RunForward @ runRate — a
|
||||||
|
// retail observer saw +Acdream run at full pace. The earlier "wire must
|
||||||
|
// send run_rate because ACE relays it" comment (citing MovementData.cs)
|
||||||
|
// was WRONG. Our own local animation still wants the actual RunForward
|
||||||
|
// cycle — carried separately in LocalAnimationCommand below.
|
||||||
uint? localAnimCmd = null;
|
uint? localAnimCmd = null;
|
||||||
if (input.Forward)
|
if (input.Forward)
|
||||||
{
|
{
|
||||||
outForwardCmd = MotionCommand.WalkForward;
|
outForwardCmd = MotionCommand.WalkForward;
|
||||||
if (input.Run && _weenie.InqRunRate(out float runRate))
|
outForwardSpeed = 1.0f; // RAW — ACE recomputes the broadcast speed
|
||||||
{
|
localAnimCmd = (input.Run && _weenie.InqRunRate(out _))
|
||||||
outForwardSpeed = runRate;
|
? MotionCommand.RunForward // local cycle is RunForward
|
||||||
localAnimCmd = MotionCommand.RunForward; // local cycle is RunForward
|
: MotionCommand.WalkForward;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
outForwardSpeed = 1.0f;
|
|
||||||
localAnimCmd = MotionCommand.WalkForward;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (input.Backward)
|
else if (input.Backward)
|
||||||
{
|
{
|
||||||
|
|
@ -1333,20 +1328,15 @@ public sealed class PlayerMovementController
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 7. Detect motion state change ─────────────────────────────────────
|
// ── 7. Detect motion state change ─────────────────────────────────────
|
||||||
// Bug fix: ForwardCommand can stay the same (WalkForward) while ONLY
|
// ForwardCommand can stay WalkForward while only the run-hold bit changes
|
||||||
// ForwardSpeed or the run-hold bit changes. If the user is already
|
// (walk W held, then Shift → run). Since D6.2b the wire forward_speed is
|
||||||
// walking (W held), then presses Shift, the outbound wire still has
|
// always the RAW 1.0 (ACE recomputes the broadcast run speed), so the
|
||||||
// ForwardCommand=WalkForward but outForwardSpeed jumps from 1.0 to
|
// walk↔run toggle is detected via the HoldKey (runHold) and the
|
||||||
// runRate. Without also tracking speed + hold-key here, no new
|
// LocalAnimationCommand change (Walk↔Run cycle), NOT via forward_speed. A
|
||||||
// MoveToState is sent — the server keeps thinking the player walks,
|
// fresh MoveToState on that toggle lets ACE's BroadcastMovement re-pick
|
||||||
// and retail observers render walking animation despite the local
|
// WalkForward vs RunForward (via HoldKey) and recompute the run speed for
|
||||||
// player's RunForward cycle.
|
// observers. The forward_speed comparison below is retained (harmless — it
|
||||||
//
|
// never fires now that forward_speed is constant) for defensiveness.
|
||||||
// Similarly LocalAnimationCommand change (Walk→Run on local cycle)
|
|
||||||
// must force a fresh outbound so ACE's BroadcastMovement re-runs
|
|
||||||
// MovementData(this, moveToState) which only reads ForwardCommand +
|
|
||||||
// ForwardSpeed + HoldKey to pick between WalkForward vs RunForward
|
|
||||||
// for remote observers.
|
|
||||||
bool runHold = input.Run;
|
bool runHold = input.Run;
|
||||||
bool changed = outForwardCmd != _prevForwardCmd
|
bool changed = outForwardCmd != _prevForwardCmd
|
||||||
|| outSidestepCmd != _prevSidestepCmd
|
|| outSidestepCmd != _prevSidestepCmd
|
||||||
|
|
|
||||||
|
|
@ -8287,6 +8287,10 @@ public sealed class GameWindow : IDisposable
|
||||||
// the retail default (0x8000003D) so the packer omits it.
|
// the retail default (0x8000003D) so the packer omits it.
|
||||||
ForwardCommand = result.ForwardCommand ?? AcDream.Core.Physics.RawMotionState.Default.ForwardCommand,
|
ForwardCommand = result.ForwardCommand ?? AcDream.Core.Physics.RawMotionState.Default.ForwardCommand,
|
||||||
ForwardHoldKey = result.ForwardCommand.HasValue ? axisHoldKey : AcDream.Core.Physics.HoldKey.Invalid,
|
ForwardHoldKey = result.ForwardCommand.HasValue ? axisHoldKey : AcDream.Core.Physics.HoldKey.Invalid,
|
||||||
|
// D6.2b: the wire carries the RAW forward_speed (1.0 for run/walk;
|
||||||
|
// the controller now sets outForwardSpeed=1.0). ACE recomputes the
|
||||||
|
// broadcast run speed from run skill (echo-confirmed 2026-07-01), so
|
||||||
|
// this is retail-faithful; 1.0 is omitted by default-difference packing.
|
||||||
ForwardSpeed = result.ForwardSpeed ?? AcDream.Core.Physics.RawMotionState.Default.ForwardSpeed,
|
ForwardSpeed = result.ForwardSpeed ?? AcDream.Core.Physics.RawMotionState.Default.ForwardSpeed,
|
||||||
SidestepCommand = result.SidestepCommand ?? AcDream.Core.Physics.RawMotionState.Default.SidestepCommand,
|
SidestepCommand = result.SidestepCommand ?? AcDream.Core.Physics.RawMotionState.Default.SidestepCommand,
|
||||||
SidestepHoldKey = result.SidestepCommand.HasValue ? axisHoldKey : AcDream.Core.Physics.HoldKey.Invalid,
|
SidestepHoldKey = result.SidestepCommand.HasValue ? axisHoldKey : AcDream.Core.Physics.HoldKey.Invalid,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue