fix(B.6+B.7): re-send action on local arrival; scale indicator box by entity Scale

User report: 'It still however just approach it and does not use it.'
Root cause: local auto-walk arrives at the target visually, but ACE's
server-side MoveToChain may have timed out before our position was
recognised as in-range (we don't echo authoritative position back to
ACE during the walk yet). The action never fires.

Fix (re-send on arrival):
  * PlayerMovementController.AutoWalkArrived event fires once when
    EndServerAutoWalk(reason='arrived') is called.
  * GameWindow tracks _pendingPostArrivalAction = (guid, isPickup)
    on each SendUse / SendPickUp.
  * OnAutoWalkArrivedReSendAction (subscribed at EnterPlayerModeNow)
    re-sends the action with isRetryAfterArrival=true. The retry
    flag prevents the re-sent action from itself setting a new
    pending action — breaks any potential re-fire loop.
  * The re-sent action is close-range from the local body's
    perspective, so ACE's CreateMoveToChain hits the WithinUseRadius
    shortcut (Player_Move.cs:66) and completes immediately —
    dialogue opens, item picks up.

User report: 'items dropped on the ground now have a smaller triangle
box, perhaps too small. Also now other stuff like signs also have a
very small triangle box, should not have it should scale to the size
of the object.'

Fix (scale-aware indicator height):
  * TargetIndicatorPanel.TargetInfo now carries entity Scale.
  * EntityHeightFor multiplies the per-type base by Scale so an
    upscaled NPC / sign / lifestone gets a proportionally larger box.
  * Per-type table refined:
      Creature                    : 1.8 m * scale
      Door/Lifestone/Portal       : 2.4 m * scale
      Small carry items (weapon/armor/clothing/jewelry/food/money/
        misc/missile-weapon/container/gem/spellcomp/writable/key/
        caster — most pickup-able): 0.8 m * scale  (up from 0.5 m)
      Everything else (signs / scenery interactables / untyped):
        1.5 m * scale  (up from 0.5 m default)

Deferred to follow-up: exact mesh-AABB-derived box (need to read
each entity's actual rendered bounds at registration time).
This commit is contained in:
Erik 2026-05-15 07:45:27 +02:00
parent 5f83766de5
commit 2dc28bb61f
3 changed files with 132 additions and 15 deletions

View file

@ -790,6 +790,15 @@ public sealed class GameWindow : IDisposable
private readonly Dictionary<uint, AcDream.Core.Net.WorldSession.EntitySpawn> _lastSpawnByGuid = new();
// Current selection: written by Q-cycle (combat) and LMB click (interact); cleared on entity despawn.
private uint? _selectedGuid;
// B.6+B.7 (2026-05-15): pending action that triggered an auto-walk.
// When the local body arrives at the auto-walk target,
// OnAutoWalkArrivedReSendAction re-sends the action close-range so
// ACE completes it via WithinUseRadius even if its server-side
// MoveToChain already timed out. Cleared before each re-send to
// prevent infinite loops (the re-sent action's auto-walk would
// arrive immediately at the same position, infinite re-fire).
private (uint Guid, bool IsPickup)? _pendingPostArrivalAction;
private readonly record struct LiveEntityInfo(
string? Name,
AcDream.Core.Items.ItemType ItemType);
@ -1177,7 +1186,7 @@ public sealed class GameWindow : IDisposable
&& spawn.ObjectDescriptionFlags is { } odf)
pwdBits = odf;
return new AcDream.App.UI.TargetIndicatorPanel.TargetInfo(
entity.Position, rawItemType, pwdBits);
entity.Position, rawItemType, pwdBits, entity.Scale);
},
cameraProvider: () =>
{
@ -9096,7 +9105,7 @@ public sealed class GameWindow : IDisposable
else SendUse(sel);
}
private void SendUse(uint guid)
private void SendUse(uint guid, bool isRetryAfterArrival = false)
{
if (_liveSession is null
|| _liveSession.CurrentState != AcDream.Core.Net.WorldSession.State.InWorld)
@ -9114,9 +9123,13 @@ public sealed class GameWindow : IDisposable
Console.WriteLine(System.FormattableString.Invariant(
$"[autowalk-out] op=use target=0x{guid:X8} name=\"{label}\" seq={seq}"));
}
// Remember this action so OnAutoWalkArrivedReSendAction can
// re-fire it close-range. Skip when this IS the re-send.
if (!isRetryAfterArrival)
_pendingPostArrivalAction = (guid, false);
}
private void SendPickUp(uint itemGuid)
private void SendPickUp(uint itemGuid, bool isRetryAfterArrival = false)
{
if (_liveSession is null
|| _liveSession.CurrentState != AcDream.Core.Net.WorldSession.State.InWorld)
@ -9149,6 +9162,32 @@ public sealed class GameWindow : IDisposable
Console.WriteLine(System.FormattableString.Invariant(
$"[autowalk-out] op=pickup target=0x{itemGuid:X8} name=\"{label}\" seq={seq}"));
}
// Remember this action so OnAutoWalkArrivedReSendAction can
// re-fire it close-range. Skip when this IS the re-send.
if (!isRetryAfterArrival)
_pendingPostArrivalAction = (itemGuid, true);
}
/// <summary>
/// B.6+B.7 (2026-05-15). Fires when <see cref="PlayerMovementController.AutoWalkArrived"/>
/// signals natural arrival at an auto-walk target. Re-sends the
/// Use/PickUp action that started the walk so ACE completes it via
/// the WithinUseRadius shortcut even if its server-side MoveToChain
/// already gave up.
/// </summary>
private void OnAutoWalkArrivedReSendAction()
{
if (_pendingPostArrivalAction is not (uint guid, bool isPickup) pending)
return;
// Clear FIRST to break any retry loop — if ACE somehow re-sends
// MoveToObject for the close-range action, we don't want
// arrival to fire a third action.
_pendingPostArrivalAction = null;
if (AcDream.Core.Physics.PhysicsDiagnostics.ProbeAutoWalkEnabled)
Console.WriteLine(System.FormattableString.Invariant(
$"[autowalk-arrived-resend] guid=0x{guid:X8} isPickup={isPickup}"));
if (isPickup) SendPickUp(guid, isRetryAfterArrival: true);
else SendUse(guid, isRetryAfterArrival: true);
}
private uint? SelectClosestCombatTarget(bool showToast)
@ -9320,6 +9359,17 @@ public sealed class GameWindow : IDisposable
}
_playerController = new AcDream.App.Input.PlayerMovementController(_physicsEngine);
// B.6+B.7 (2026-05-15): re-send the Use/PickUp action on local
// auto-walk arrival. ACE's server-side MoveToChain may have
// already timed out by the time the local body arrives (we
// walk locally but don't send tracking position updates to
// ACE during the walk yet, so ACE's WithinUseRadius check may
// never have passed). Resending close-range hits ACE's
// CreateMoveToChain WithinUseRadius shortcut (Player_Move.cs:66)
// and completes the action immediately.
_playerController.AutoWalkArrived += OnAutoWalkArrivedReSendAction;
// K-fix7 (2026-04-26): if PlayerDescription already arrived, the
// server's Run / Jump skill values are cached here — push them
// into the freshly-constructed controller so the runRate /