acdream/docs/research/2026-07-04-171-pickup-prompt.md
Erik d413ac2a29 docs(#171): file the group-melee interpenetration issue + R5-V3 handoff/pickup
User report during the #170 gate: pack-melee monsters partly inside each
other with slightly stale facings vs retail on the same ACE. Investigation
(report-only) pinned two code-grounded causes, both already-tracked R5-V3
scope, fix APPROVED by the user:

1. TS-39 — sticky melee is a no-op: ACE arms melee chases with Sticky
   (Monster_Navigation.cs:416); retail's arrival hands off to
   PositionManager::StickTo -> StickyManager::adjust_offset (0x00555430,
   per-tick 0.3m edge gap + facing tracking); acdream's StickTo/Unstick
   seams are unbound so attackers freeze at stale arrival poses.
2. Arrival radii are zero: getOwnRadius () => 0f (the R5-V3 pin) and
   RouteServerMoveTo never sets MovementStruct.Radius/Height — retail/ACE
   arrive edge-to-edge with setup-derived radii (ACE PhysicsObj.MoveToObject
   reads the TARGET's PartArray radius/height).

Ruled out: the between-snap collision sweep (remotes run full
ResolveWithTransition; CollisionExemption keeps creatures collidable).
Caveat recorded: ACE has no server-side monster avoidance — acceptance is
retail PARITY, not zero overlap.

ISSUES #171 filed; handoff docs/research/2026-07-04-171-sticky-melee-handoff.md
+ pickup docs/research/2026-07-04-171-pickup-prompt.md; memory index updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 22:38:58 +02:00

52 lines
3.2 KiB
Markdown

# Pickup prompt — #171 sticky melee / R5-V3 (paste into a fresh session)
Read `docs/research/2026-07-04-171-sticky-melee-handoff.md` first — it is the
SSOT for this task (root causes, retail anchors, approved scope, gotchas).
Then implement R5-V3.
**Context:** #170 (chase slide) is CLOSED — gate passed at `4cad626f`; do not
reopen that machinery. During its gate the user observed #171: in a pack
melee, monsters sit partly inside each other with slightly stale facings vs
retail on the same ACE. Investigated + **fix approved by the user 2026-07-04**.
**The two causes (both R5-V3 scope, already register-tracked):**
1. Sticky melee is a no-op (TS-39): ACE arms melee chases with `Sticky`;
retail's arrival hands off to `PositionManager::StickTo`
`StickyManager::adjust_offset` (0x00555430, per-tick 0.3 m gap + facing
tracking). Our `MoveToManager.StickTo`/`Unstick` seams are unbound —
attackers freeze at stale arrival poses.
2. Arrival radii are zero: `getOwnRadius: () => 0f` (the R5-V3 pin in
`EnsureRemoteMotionBindings`) + `RouteServerMoveTo` never sets
`MovementStruct.Radius/Height` — retail/ACE arrive edge-to-edge with
setup-derived radii (ACE `PhysicsObj.MoveToObject` reads the TARGET's
PartArray radius/height).
**Do, in order:**
1. Grep the named decomp for `StickyManager::` + `PositionManager::` bodies
(adjust_offset 0x00555430; per-tick anchors already pinned:
`PositionManager::adjust_offset` @0x00512d0e inside UpdatePositionInternal,
`PositionManager::UseTime` @0x005159b3 in UpdateObjectInternal).
Pseudocode, then port verbatim; cross-check
`references/ACE/Source/ACE.Server/Physics/Managers/{StickyManager,PositionManager}.cs`.
Groundwork already in tree: `MoveToMath.CylinderDistanceNoZ` /
`GlobalToLocalVec` / `NormalizeCheckSmall`; `ConstraintManager` (R5-V1) is
the port-style reference. Do NOT arm ConstraintManager (#167 separate).
2. Bind `StickTo`/`UnStick` in `EnsureRemoteMotionBindings` AND the player
wiring; wire PositionManager into the tick at the retail-matching points.
3. Thread real cylsphere radii (own from the entity's Setup; target resolved
at `RouteServerMoveTo`'s MoveToObject branch). Sweep remote + player.
4. Same-commit register bookkeeping: retire TS-39, update the radius pin.
5. Extend `RemoteChaseEndToEndHarnessTests` with a sticky scenario (arrive →
target strafes → follower tracks gap + facing; UnStick on next
PerformMovement). Harness bodies MUST mirror the live RemoteMotion
construction (InWorld=true, RemoteWeenie — see RemoteChaseDrainBisectTests).
6. `dotnet build` + full `dotnet test` green → commit → launch for the user's
visual gate: pack melee side-by-side vs retail, strafe around the pack;
attackers should reshuffle + keep facing like retail. Acceptance is retail
PARITY — some overlap is ACE-server-side and shows on retail too.
**Gotchas:** revert-prone remote-motion area — verbatim port, no redesign;
per-entity probes must print the guid (memory
`feedback_probe_identity_attribution`); PowerShell Tee logs are UTF-16
(`tr -d '\000'` before grep); the user manages client lifecycle (graceful
close); both clients hit the same local ACE (127.0.0.1:9000).