fix(items): dispatch carried use without world approach
This commit is contained in:
parent
f71f947475
commit
19e8863f4e
7 changed files with 99 additions and 18 deletions
|
|
@ -19,10 +19,14 @@ status hand follows canonical selection/object notices, ghosts empty and
|
||||||
explicitly unusable selections, and routes enabled weapons, direct-use items,
|
explicitly unusable selections, and routes enabled weapons, direct-use items,
|
||||||
and use-on-target tools through the existing interaction transaction and
|
and use-on-target tools through the existing interaction transaction and
|
||||||
cursor owners. Its connected state gate passed. A named-retail correction now
|
cursor owners. Its connected state gate passed. A named-retail correction now
|
||||||
treats reset/absent useability zero as usable, allowing Blackmoor's Favor to
|
treats reset/absent useability zero as usable. The connected gate then exposed
|
||||||
send ordinary Use, while shared AutoWear reports the exact overlapping worn
|
the delivery defect beneath that classifier: carried Use had been routed
|
||||||
item that must be removed. That correction awaits its connected gate; the
|
through the world-object approach query and silently cancelled because
|
||||||
magnifying-glass Assess command follows in the same slice.
|
inventory objects have no spatial entity. Owned direct-use now sends
|
||||||
|
immediately, while the registered AD-27 approach seam remains world-only;
|
||||||
|
shared AutoWear reports the exact overlapping worn item that must be removed.
|
||||||
|
That correction awaits its connected gate; the magnifying-glass Assess command
|
||||||
|
follows in the same slice.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,11 @@ Slice 1's 18-cell favorite-spell overflow bar is user-accepted. Slice 2 is
|
||||||
active: the status hand's selected-object availability and existing
|
active: the status hand's selected-object availability and existing
|
||||||
Use/AutoWield/use-on-target command routing passed their connected gate.
|
Use/AutoWield/use-on-target command routing passed their connected gate.
|
||||||
The follow-up retail correction for zero-valued direct-use items and named
|
The follow-up retail correction for zero-valued direct-use items and named
|
||||||
AutoWear blockers is code-complete and awaiting its connected gate before the
|
AutoWear blockers is code-complete. Its first connected gate exposed and
|
||||||
|
corrected the lower delivery boundary: carried direct-use had been sent through
|
||||||
|
the world approach query even though inventory objects have no spatial entity.
|
||||||
|
Owned Use now sends immediately; world Use alone retains the registered AD-27
|
||||||
|
approach seam. The combined correction awaits its connected gate before the
|
||||||
Assess half continues.
|
Assess half continues.
|
||||||
|
|
||||||
Carried:
|
Carried:
|
||||||
|
|
|
||||||
|
|
@ -70,11 +70,14 @@ AP-122. The 14-test Core interaction focus, 49-test toolbar focus, Release
|
||||||
solution build, 3,474 App tests / 3 skips, and 7,848 complete-solution tests /
|
solution build, 3,474 App tests / 3 skips, and 7,848 complete-solution tests /
|
||||||
5 skips pass.
|
5 skips pass.
|
||||||
|
|
||||||
The connected selection-state gate passed. Its follow-up exposed two deeper
|
The connected selection-state gate passed. Its follow-up exposed three deeper
|
||||||
shared-policy defects, now corrected from named retail plus the matching
|
shared-policy/delivery defects, now corrected from named retail plus the
|
||||||
binary. `ItemUses::IsUseable @ 0x004FCCC0` tests only `USEABLE_NO`; reset/absent
|
matching binary. `ItemUses::IsUseable @ 0x004FCCC0` tests only `USEABLE_NO`;
|
||||||
value zero is usable, so Blackmoor's Favor and other zero-valued direct-use
|
reset/absent value zero is usable. `ItemHolder::UseObject @ 0x00588A80` sends a
|
||||||
items now emit the ordinary Use request. AutoWear now applies
|
carried direct-use item immediately; acdream had incorrectly routed that
|
||||||
|
packet through a world approach lookup, where Blackmoor's Favor has no spatial
|
||||||
|
entity and was silently cancelled. Owned Use now bypasses that query while
|
||||||
|
world-object Use retains the registered AD-27 approach seam. AutoWear applies
|
||||||
`CPlayerSystem::AutoWearIsLegal @ 0x0055EF40` through the same double-click and
|
`CPlayerSystem::AutoWearIsLegal @ 0x0055EF40` through the same double-click and
|
||||||
toolbar-hand path, resolves the overlapping worn object from the
|
toolbar-hand path, resolves the overlapping worn object from the
|
||||||
retail-ordered equipment projection, and emits the exact system line
|
retail-ordered equipment projection, and emits the exact system line
|
||||||
|
|
@ -82,7 +85,10 @@ retail-ordered equipment projection, and emits the exact system line
|
||||||
[`../research/2026-07-23-retail-item-use-and-autowear-pseudocode.md`](../research/2026-07-23-retail-item-use-and-autowear-pseudocode.md).
|
[`../research/2026-07-23-retail-item-use-and-autowear-pseudocode.md`](../research/2026-07-23-retail-item-use-and-autowear-pseudocode.md).
|
||||||
The focused 25-test Core and 85-test App sets pass, as do the warning-free
|
The focused 25-test Core and 85-test App sets pass, as do the warning-free
|
||||||
Release solution build, 3,476 App tests / 3 skips, and 7,857 complete-solution
|
Release solution build, 3,476 App tests / 3 skips, and 7,857 complete-solution
|
||||||
tests / 5 skips.
|
tests / 5 skips. The carried-use delivery correction adds an end-to-end App
|
||||||
|
pin from Favor activation through wire dispatch and authoritative UseDone busy
|
||||||
|
release. The Release build retains the 17 tracked test-project warnings;
|
||||||
|
3,477 App tests / 3 skips and 7,858 complete-solution tests / 5 skips pass.
|
||||||
|
|
||||||
## Slice 1 — spell-bar overflow arrows
|
## Slice 1 — spell-bar overflow arrows
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ Date: 2026-07-23
|
||||||
- `PublicWeenieDesc::UnPack @ 0x005AD470`
|
- `PublicWeenieDesc::UnPack @ 0x005AD470`
|
||||||
- `ItemHolder::DetermineUseResult @ 0x00588460`
|
- `ItemHolder::DetermineUseResult @ 0x00588460`
|
||||||
- `ItemHolder::UseObject @ 0x00588A80`
|
- `ItemHolder::UseObject @ 0x00588A80`
|
||||||
|
- `CPlayerSystem::UsingItem @ 0x00562F70`
|
||||||
- `CPlayerSystem::AutoWearIsLegal @ 0x0055EF40`
|
- `CPlayerSystem::AutoWearIsLegal @ 0x0055EF40`
|
||||||
- `CPlayerSystem::AutoWear @ 0x005601C0`
|
- `CPlayerSystem::AutoWear @ 0x005601C0`
|
||||||
- `ACCWeenieObject::GetObjectAtLocation @ 0x0058CE00`
|
- `ACCWeenieObject::GetObjectAtLocation @ 0x0058CE00`
|
||||||
|
|
@ -52,6 +53,14 @@ when the optional useability word is present. Consequently an absent wire word
|
||||||
and an explicitly packed zero both have retail `USEABLE_UNDEF` value zero and
|
and an explicitly packed zero both have retail `USEABLE_UNDEF` value zero and
|
||||||
both pass `IsUseable`.
|
both pass `IsUseable`.
|
||||||
|
|
||||||
|
For a direct-use item, `ItemHolder::UseObject` then sends
|
||||||
|
`CM_Inventory::Event_UseEvent`, increments the UI busy count, and calls
|
||||||
|
`CPlayerSystem::UsingItem`. That latter presentation function handles local
|
||||||
|
pickup/wield/container state; it does not require a carried source to have a
|
||||||
|
world position. Therefore an owned inventory object must cross the wire
|
||||||
|
directly. Only world objects participate in acdream's registered AD-27 local
|
||||||
|
approach compatibility seam.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
AutoWearIsLegal(itemId, out alreadyWorn, silent):
|
AutoWearIsLegal(itemId, out alreadyWorn, silent):
|
||||||
alreadyWorn = false
|
alreadyWorn = false
|
||||||
|
|
@ -101,8 +110,12 @@ AutoWear(itemId, out alreadyWorn, silent):
|
||||||
rule. Toolbar enablement, item activation, and world interaction consume it.
|
rule. Toolbar enablement, item activation, and world interaction consume it.
|
||||||
- `ItemInteractionController` remains the shared double-click and toolbar-hand
|
- `ItemInteractionController` remains the shared double-click and toolbar-hand
|
||||||
path. A zero-valued carried gem such as Blackmoor's Favor therefore emits the
|
path. A zero-valued carried gem such as Blackmoor's Favor therefore emits the
|
||||||
ordinary Use request; ACE remains authoritative for its spell and
|
ordinary Use request directly from its inventory identity; it is never sent
|
||||||
consumption outcome.
|
through the world-approach query. ACE remains authoritative for its spell
|
||||||
|
and consumption outcome.
|
||||||
|
- `SelectionInteractionController` keeps the AD-27 turn/approach seam only for
|
||||||
|
non-owned spatial objects. Owned self, equipped, and nested-container sources
|
||||||
|
have no live world pose and send immediately.
|
||||||
- `AutoWieldController` remains the shared inventory/paperdoll equip owner. It
|
- `AutoWieldController` remains the shared inventory/paperdoll equip owner. It
|
||||||
resolves AutoWear blockers from `ClientObjectTable`'s retail-ordered
|
resolves AutoWear blockers from `ClientObjectTable`'s retail-ordered
|
||||||
equipment projection and emits the retail literal through system chat.
|
equipment projection and emits the retail literal through system chat.
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,16 @@ BeginAcceptedUse(object):
|
||||||
RequestUse(object, reservation)
|
RequestUse(object, reservation)
|
||||||
|
|
||||||
RequestUse(object, reservation):
|
RequestUse(object, reservation):
|
||||||
if session/identity/approach is invalid:
|
if session is invalid:
|
||||||
|
reservation.CancelBeforeDispatch()
|
||||||
|
return
|
||||||
|
|
||||||
|
if object is carried or equipped by the player:
|
||||||
|
send Use immediately
|
||||||
|
transfer reservation to UseDone
|
||||||
|
return
|
||||||
|
|
||||||
|
if world identity/approach is invalid:
|
||||||
reservation.CancelBeforeDispatch()
|
reservation.CancelBeforeDispatch()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,18 @@ internal sealed class SelectionInteractionController
|
||||||
reservation?.CancelBeforeDispatch();
|
reservation?.CancelBeforeDispatch();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ItemHolder::UseObject @ 0x00588A80 sends Event_UseEvent for an
|
||||||
|
// accepted carried-item activation before CPlayerSystem::UsingItem.
|
||||||
|
// A carried source has no world pose to approach: routing it through
|
||||||
|
// TryGetApproach drops the packet because inventory objects are not
|
||||||
|
// live spatial entities.
|
||||||
|
if (_items.IsOwnedByPlayer(serverGuid))
|
||||||
|
{
|
||||||
|
SendUseNow(serverGuid, reservation);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_query.IsUseable(serverGuid)
|
if (!_query.IsUseable(serverGuid)
|
||||||
|| !_query.TryGetApproach(serverGuid, out InteractionApproach approach))
|
|| !_query.TryGetApproach(serverGuid, out InteractionApproach approach))
|
||||||
{
|
{
|
||||||
|
|
@ -240,15 +252,21 @@ internal sealed class SelectionInteractionController
|
||||||
}
|
}
|
||||||
|
|
||||||
_movement.BeginApproach(approach);
|
_movement.BeginApproach(approach);
|
||||||
|
SendUseNow(serverGuid, reservation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendUseNow(
|
||||||
|
uint serverGuid,
|
||||||
|
ItemUseRequestReservation? reservation)
|
||||||
|
{
|
||||||
if (_transport.TrySendUse(serverGuid, out uint sequence))
|
if (_transport.TrySendUse(serverGuid, out uint sequence))
|
||||||
{
|
{
|
||||||
reservation?.MarkDispatched();
|
reservation?.MarkDispatched();
|
||||||
Console.WriteLine($"[B.4b] use guid=0x{serverGuid:X8} seq={sequence}");
|
Console.WriteLine($"[B.4b] use guid=0x{serverGuid:X8} seq={sequence}");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
reservation?.CancelBeforeDispatch();
|
||||||
reservation?.CancelBeforeDispatch();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendPickup(uint itemGuid, uint destinationContainerId, int placement)
|
public void SendPickup(uint itemGuid, uint destinationContainerId, int placement)
|
||||||
|
|
|
||||||
|
|
@ -361,6 +361,33 @@ public sealed class SelectionInteractionControllerTests
|
||||||
Assert.Equal(new[] { Target }, h.Transport.Uses);
|
Assert.Equal(new[] { Target }, h.Transport.Uses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CarriedDirectUseBypassesWorldApproachAndWaitsForUseDone()
|
||||||
|
{
|
||||||
|
const uint favor = 0x8000_0606u;
|
||||||
|
var h = new Harness();
|
||||||
|
h.Query.Useable = false;
|
||||||
|
h.Objects.AddOrUpdate(new ClientObject
|
||||||
|
{
|
||||||
|
ObjectId = favor,
|
||||||
|
Name = "Blackmoor's Favor",
|
||||||
|
Type = ItemType.Gem,
|
||||||
|
Useability = ItemUseability.Undef,
|
||||||
|
});
|
||||||
|
Assert.True(h.Objects.MoveItem(favor, Player, newSlot: 1));
|
||||||
|
|
||||||
|
Assert.True(h.Items.ActivateItem(favor));
|
||||||
|
|
||||||
|
Assert.Empty(h.Movement.Approaches);
|
||||||
|
Assert.Equal(new[] { favor }, h.Transport.Uses);
|
||||||
|
Assert.Equal(1, h.Items.BusyCount);
|
||||||
|
|
||||||
|
h.Items.CompleteUse(0u);
|
||||||
|
|
||||||
|
Assert.Equal(0, h.Items.BusyCount);
|
||||||
|
Assert.True(h.Items.CanMakeInventoryRequest);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void HiddenOrStaleIncarnationCancelsDeferredAction()
|
public void HiddenOrStaleIncarnationCancelsDeferredAction()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue