acdream/docs/superpowers/specs
Erik d640ed74e1 feat(retail): Phase B.6 — server-driven auto-walk done right
Closes #63, #69, #74, #75. Replaces the chain of Commit-B workarounds
that compensated for ACE's MoveToChain getting cancelled by a leaked
user-MoveToState packet during inbound auto-walk. The fix is
architectural — auto-walk drives the body directly from the
server-supplied path data, no player-input synthesis, no spurious
wire-packet transitions, no grace-period band-aid.

Architectural change (closes #75):
  PlayerMovementController.ApplyAutoWalkOverlay → DriveServerAutoWalk.
  - Steps Yaw toward target at retail-faithful turn rates.
  - Computes desired forward velocity from path runRate.
  - Calls _motion.DoMotion(WalkForward, speed) directly for the
    motion-interpreter state (drives animation cycle).
  - Sets _body.set_local_velocity directly when grounded.
  - Returns true to gate the user-input motion + velocity section
    in Update so user-input flow doesn't overwrite auto-walk
    velocity or motion state.
  Mirrors retail's MovementManager::PerformMovement case 6 (decomp
  0x00524440) which never touches the user-input pipeline during
  server-controlled auto-walk.

Wire-layer guard at GameWindow.cs:6419 retained as a SEMANTIC
statement (`if (result.MotionStateChanged && !IsServerAutoWalking)`):
user-MoveToState packets are for user-driven motion intent. During
server-controlled auto-walk, the motion-state transitions caused by
the animation override (RunForward / WalkForward / TurnLeft /
TurnRight cycles) must not leak as user-cancellation packets. This
is NOT the deleted 500ms grace-period band-aid; it's the wire-layer
expressing the user-vs-server motion split.

Animation plumbed for auto-walk phases (closes #69):
  - Moving forward → WalkForward (speed=1.0) / RunForward (speed=runRate)
  - Turn-first phase → TurnLeft / TurnRight (sign of yawStep)
  - Aligned-but-pre-step / arrival → no override (idle)
Driven via _autoWalkMovingForwardThisFrame + _autoWalkTurnDirectionThisFrame
fields set in DriveServerAutoWalk and read in the MovementResult
construction at the bottom of Update. UpdatePlayerAnimation picks up
the localAnimCmd as the highest-priority animation source.

Walk/run threshold = 1.0m, retail-observed. ACE's wire-default of
15.0f is too generous; ACE's own physics layer uses 1.0f at
MovementParameters.cs:50 (with the 15.0f line commented out) and
Creature.cs:312 notes "default 15 distance seems too far". The
formula matches retail's MovementParameters::get_command at decomp
0x0052aa00: running = (initialDist - distance_to_object) >=
threshold, evaluated ONCE at chain start and held for the rest of
the auto-walk (matches retail "runs all the way / walks all the way"
behaviour). Wire-supplied threshold is ignored.

Pickup gate (IsPickupableTarget) now uses BF_STUCK
(acclient.h:6435, bit 0x4) to discriminate immovable scenery from
real pickup items that share a Misc ItemType. Sign (pwd=0x14 with
BF_STUCK) → blocked; spell component (pwd=0x10, no BF_STUCK) →
allowed. ACE's PutItemInContainer (Player_Inventory.cs:831-836)
responds with WeenieError.Stuck (0x29) on stuck items so the gate
prevents wasted wire packets + a UX dead-end.

R-key dispatch by target type. UseCurrentSelection's top-level
IsUseableTarget gate was wrong (blocked USEABLE_NO=1 items that
ARE pickupable). Reordered:
  1. Creature → SendUse
  2. Pickupable → SendPickUp
  3. Useable → SendUse
  4. Otherwise → "cannot be used" toast
Each handler keeps its own gate. Matches retail's per-action
server-side validation.

AP cadence revert (closes #74). With the MoveToChain race fixed,
the per-frame "send while moving" cadence is no longer load-bearing.
Reverted to retail's two-branch ShouldSendPositionEvent gate
(acclient_2013_pseudo_c.txt:700233-700285):
  Interval NOT elapsed (< 1 sec): send if cell or contact-plane changed.
  Interval elapsed (>= 1 sec):    send if cell or position frame changed.
Adds _lastSentContactPlane field + ApproxPlaneEqual helper +
PlayerMovementController.ContactPlane public accessor. Extended
NotePositionSent(Vector3, uint, Plane, float) — both outbound sites
(MoveToState + AP) pass _playerController.ContactPlane.
Effective rates: 0 Hz idle, ~1 Hz smooth motion, per-event on
cell/plane changes, 0 Hz airborne.

CLAUDE.md updated with no-workarounds rule (commit `da126f9` on
the worktree branch). Saved as feedback memory at
memory/feedback_no_workarounds.md.

Tests: build green; Core.Net 294/294; Core 1073/1081 (baseline,
8 pre-existing Physics failures unchanged). Visual-verified
end-to-end on 2026-05-16 for far/near Use + PickUp on NPCs,
doors, items, spell components, signs (correctly blocked), corpses,
turn-first animation, run/walk thresholds, idle quiet, smooth-
motion 1Hz.

Spec: docs/superpowers/specs/2026-05-16-phase-b6-suppress-movetostate-during-inbound-autowalk-design.md
Plan: docs/superpowers/plans/2026-05-16-phase-b6-suppress-movetostate-during-inbound-autowalk.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 16:14:44 +02:00
..
2026-04-11-foundation-phase-design.md docs: refresh strategic roadmap + Foundation phase design spec 2026-04-11 21:43:33 +02:00
2026-04-12-b3-complete-movement-design.md docs(specs): Phase B.3 Complete — movement and world navigation design 2026-04-12 15:54:12 +02:00
2026-04-12-physics-collision-engine-design.md docs(specs): Phase B.3 — physics collision engine design 2026-04-12 09:42:31 +02:00
2026-04-12-player-movement-design.md docs(specs): Phase B.2 — player movement mode design 2026-04-12 14:05:07 +02:00
2026-04-13-movement-completion-design.md docs: movement completion design spec (B.2/B.3) 2026-04-13 23:01:18 +02:00
2026-05-02-l3-remote-entity-motion-design.md docs(spec): Phase L.3 scope revision — combine L.3.1+L.3.2 2026-05-03 10:03:09 +02:00
2026-05-08-phase-n-worldbuilder-migration-design.md spec(rendering): Phase N WorldBuilder migration design + N.1 scenery 2026-05-08 08:47:23 +02:00
2026-05-08-phase-n1-scenery-via-wb-helpers-design.md spec(rendering): Phase N WorldBuilder migration design + N.1 scenery 2026-05-08 08:47:23 +02:00
2026-05-08-phase-n4-rendering-foundation-design.md spec(N.4): rendering pipeline foundation design 2026-05-08 12:47:49 +02:00
2026-05-08-phase-n5-modern-rendering-design.md phase(N.5): retirement amendment — InstancedMeshRenderer + StaticMeshRenderer + WbFoundationFlag deleted 2026-05-08 22:01:36 +02:00
2026-05-09-phase-a5-two-tier-streaming-design.md docs(A.5 T27): spec + plan amendments for T22.5 + ship 2026-05-10 10:06:26 +02:00
2026-05-09-phase-n5b-terrain-modern-design.md spec(N.5b): design for terrain on the modern rendering path 2026-05-09 08:23:09 +02:00
2026-05-10-issue-53-tier1-cache-design.md docs(post-A.5 #53): Tier 1 retry — mutation audit + cache design spec 2026-05-10 16:50:26 +02:00
2026-05-10-phase-m-network-stack-design.md docs(phase-m): sharpen Phase M into design spec + opcode coverage matrix 2026-05-10 19:22:49 +02:00
2026-05-11-phase-n6-slice1-design.md docs(perf #N6.1): apply final-review fixes — spec, baseline doc, issue #55 2026-05-11 12:51:10 +02:00
2026-05-12-l2g-dynamic-physicsstate-design.md docs(phys L.2g): design spec for dynamic PhysicsState toggling (doors) 2026-05-12 21:00:36 +02:00
2026-05-12-phase-c1.5a-portals-design.md docs(vfx #C.1.5a): ship Phase C.1.5a + file issue #56 for per-part collapse 2026-05-11 16:13:12 +02:00
2026-05-13-l2d-cbuildingobj-collision-design.md docs(phys L.2d): design spec for slice 1 BSP-hit diagnostic + L.2d reframe 2026-05-12 19:01:44 +02:00
2026-05-13-phase-b4b-design.md docs(B.4b): correct file paths — WorldPicker lives in AcDream.Core.Selection 2026-05-13 17:31:49 +02:00
2026-05-13-phase-b4c-design.md docs(B.4c): design spec for door swing animation 2026-05-14 06:26:57 +02:00
2026-05-13-phase-c1.5b-design.md docs(vfx #C.1.5b): design + plan for issue #56 + EnvCell DefaultScript 2026-05-11 23:51:44 +02:00
2026-05-14-phase-b6-design.md docs(B.6): record Slice 1 trace findings — ACE sends mtRun=0.00, no UP echo 2026-05-14 18:45:17 +02:00
2026-05-15-phase-b7-target-indicator-design.md docs(B.7): design spec for Vivid Target Indicator (selection feedback) 2026-05-15 06:46:55 +02:00
2026-05-16-phase-b6-suppress-movetostate-during-inbound-autowalk-design.md feat(retail): Phase B.6 — server-driven auto-walk done right 2026-05-16 16:14:44 +02:00