From 39ff3a550569aa8a342aaded84dad2acc21d748f Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 15 May 2026 11:19:04 +0200 Subject: [PATCH] fix(B.6+B.7): arrival predicate uses safety margin INSIDE ACE's WithinUseRadius MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trace showed local arrival landing at 3.025 m from a target with objDist=3.00. The previous arrival used ArrivalEpsilon=0.05 to EXPAND the threshold (dist <= 3.05), so the body stopped right at the boundary. ACE's server-side WithinUseRadius is strict (dist <= radius), so 3.025 > 3.00 — ACE rejected the re-sent action and looped back to MoveToObject. User had to manually re-press R because auto-arrival kept landing just-outside-range. Fix: walk INSIDE ACE's radius by a safety margin (0.3–0.5 m, capped at 40 % of threshold so tight pickup radii like 0.6 m stay reachable). arrivalThreshold = wire's distanceToObject or minDistance safetyMargin = min(0.5, arrivalThreshold * 0.4) effectiveArrival = max(arrivalThreshold - safetyMargin, 0.1) Examples: objDist=3.00 (NPC) → walk to ≤2.50 m (ACE happy at 3.0) objDist=2.00 (door) → walk to ≤1.50 m objDist=0.60 (item) → walk to ≤0.36 m objDist=0.50 (small) → walk to ≤0.30 m Flee case (moveTowards=false) keeps its original predicate with +ArrivalEpsilon — that's the boundary check semantics for fleeing to a min-distance, not a max-distance use radius. --- src/AcDream.App/Input/PlayerMovementController.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/AcDream.App/Input/PlayerMovementController.cs b/src/AcDream.App/Input/PlayerMovementController.cs index 71f3239..74c6a44 100644 --- a/src/AcDream.App/Input/PlayerMovementController.cs +++ b/src/AcDream.App/Input/PlayerMovementController.cs @@ -445,15 +445,24 @@ public sealed class PlayerMovementController float dy = _autoWalkDestination.Y - pos.Y; float dist = MathF.Sqrt(dx * dx + dy * dy); - // Arrival predicate (RemoteMoveToDriver convention; matches retail). + // 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.3–0.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). float arrivalThreshold = _autoWalkMoveTowards ? _autoWalkDistanceToObject : _autoWalkMinDistance; + float safetyMargin = MathF.Min(0.5f, arrivalThreshold * 0.4f); + float effectiveArrival = MathF.Max(arrivalThreshold - safetyMargin, 0.1f); bool arrived = (_autoWalkMoveTowards - && dist <= arrivalThreshold + RemoteMoveToDriver.ArrivalEpsilon) + && dist <= effectiveArrival) || (!_autoWalkMoveTowards - && dist >= arrivalThreshold - RemoteMoveToDriver.ArrivalEpsilon); + && dist >= arrivalThreshold + RemoteMoveToDriver.ArrivalEpsilon); if (arrived) { EndServerAutoWalk("arrived");