fix(B.6+B.7): shrink arrival safety margin; file #66 rotation, #67 door

Margin trim:
  Previous: min(0.5, threshold * 0.4) — for 3 m NPC arrived at 2.5 m
  New:      min(0.2, threshold * 0.2) — for 3 m NPC arrives at 2.8 m
  User feedback: 'compared to retail, it fires too close. In retail
  it fires from a longer range.' Smaller margin matches that — still
  safely inside ACE's strict WithinUseRadius but closer to the boundary.
  Tight pickup radii (0.6 m item) now arrive at 0.48 m (was 0.36 m).

Filed issues:
  #67  Door Use action doesn't complete after auto-walk arrival.
       NPC dialogue fires correctly post-flush-AP+re-send, but
       doors still go silent — need to investigate door-specific
       state requirements in ACE's Door.ActOnUse or our wire
       payload differences.
  #66  Rotation: local player flips back after auto-walk arrival
       (observed from retail observer); NPCs don't turn to face
       the player when used. Both rooted in missing MovementType=8
       TurnToObject handling. Supersedes #65 (which was local-only)
       with a unified rotation-handling phase scope.
This commit is contained in:
Erik 2026-05-15 11:28:06 +02:00
parent 39ff3a5505
commit 64c9793248
2 changed files with 91 additions and 6 deletions

View file

@ -46,6 +46,88 @@ Copy this block when adding a new issue:
# Active issues
## #67 — Door Use action doesn't complete after auto-walk arrival
**Status:** OPEN
**Severity:** MEDIUM (M1-affecting — doors are M1 demo target 2)
**Filed:** 2026-05-15 (B.7 visual verification)
**Component:** net / interaction
**Description:** After B.6's auto-walk + B.7's flush-AP-and-re-send, NPC
dialogue fires correctly on out-of-range Use. But Use on a door from
out-of-range still doesn't open the door — the player walks to the
door, sends the re-send, and nothing happens.
**Suspected causes (need investigation):**
1. Door's `objDist` on the wire might be different from what we
parse, so the local arrival lands outside ACE's actual
door-use radius.
2. ACE's `Door.ActOnUse` may require additional client-side state
(specific stance, motion, facing) that our re-sent Use lacks.
3. The door's ObjectDescriptionFlags `BF_DOOR (0x1000)` may not
be properly captured / forwarded for our picker's per-type
radius logic to fire.
**Acceptance:** F or R-key on a selected door from > 0.6 m runs the
auto-walk, arrives, opens the door (player walks through; B.4c swing
animation plays).
**Files (likely):** `src/AcDream.App/Rendering/GameWindow.cs`
`SendUse`; `src/AcDream.App/Input/PlayerMovementController.cs`
arrival; `references/ACE/Source/ACE.Server/WorldObjects/Door.cs`.
---
## #66 — Local + remote rotation: player flips back, NPCs don't turn
**Status:** OPEN
**Severity:** LOW-MEDIUM (visual feedback — interaction works,
just looks wrong)
**Filed:** 2026-05-15 (B.7 visual verification)
**Component:** motion / rotation
**Description:** Two related visual rotation bugs surfaced together:
1. **Local player flips back.** Observing acdream's `+Acdream` from
retail: when our auto-walk completes and the body has rotated to
face the target, the broadcast position has the new rotation —
then the next frame the player snaps back to whatever the camera
yaw was. Likely cause: after `EndServerAutoWalk`, the synthesised
input stops and `Update`'s next pass applies the user's real
`MouseDeltaX` (which may be 0 but other paths might be
overriding `Yaw`).
2. **NPCs don't turn to face the player.** ACE broadcasts
`MovementType=8 TurnToObject` when an NPC starts a Use response
that requires facing. Our `OnLiveMotionUpdated` handles
MovementType=6 (MoveToObject) but not 8. The NPC's body stays
at whatever heading the spawn / last motion left it.
**Acceptance:**
- After auto-walk arrival, local player's facing toward the target
is preserved (no flip-back observed from a retail client).
- NPCs (Tirenia, guards, vendors) rotate to face the player when
using them.
**Files (likely):**
- `src/AcDream.Core.Net/Messages/UpdateMotion.cs` — extend parser
for MovementType=8 payload (target guid + final-heading flag).
- `src/AcDream.App/Rendering/GameWindow.cs` `OnLiveMotionUpdated`
— route MovementType=8 for the local player to a new
`BeginServerTurnToObject` controller method; route for remote
guids into the remote-dead-reckon state (extending
`RemoteMoveToDriver` or adding a sibling driver).
- `src/AcDream.App/Input/PlayerMovementController.cs` — add the
turn driver that holds Yaw against user-input overrides until
aligned.
**Replaces / supersedes:** #65 (local-player turn-to-face on
close-range Use). This issue covers both directions and is the
broader retail-faithful rotation handling phase.
**Estimated scope:** Medium — ~80120 LOC + tests.
---
## #65 — Local player doesn't turn to face target on close-range Use
**Status:** OPEN

View file

@ -448,15 +448,18 @@ public sealed class PlayerMovementController
// Arrival predicate. CRITICAL: ACE's server-side WithinUseRadius
// is strict (dist <= radius), so arriving exactly at the radius
// boundary fails — ACE rejects the action and replies with
// another MoveToObject. To ensure the re-sent action lands
// INSIDE ACE's radius, we apply a safety margin that walks
// 0.30.5 m past the boundary (capped to 40 % of the threshold
// so tight pickup radii like 0.6 m stay reachable without
// collapsing to zero).
// another MoveToObject. We walk slightly INSIDE the boundary so
// the re-sent action lands safely in-range.
//
// The margin is small — user feedback says retail fires Use
// from longer range, so we minimise the over-walk: 0.2 m at
// typical NPC radii (3 m → arrive at 2.8 m), tapered for tight
// pickup radii (0.6 m → arrive at 0.48 m) so the body stays
// reachable but always inside ACE's strict check.
float arrivalThreshold = _autoWalkMoveTowards
? _autoWalkDistanceToObject
: _autoWalkMinDistance;
float safetyMargin = MathF.Min(0.5f, arrivalThreshold * 0.4f);
float safetyMargin = MathF.Min(0.2f, arrivalThreshold * 0.2f);
float effectiveArrival = MathF.Max(arrivalThreshold - safetyMargin, 0.1f);
bool arrived =
(_autoWalkMoveTowards