fix(vendor): Slice 6 review corrections — ownership-checked retire, live slider display, drag-proof shop rows, hardened buy reservation
Some checks are pending
Headless portability / portable-headless (ubuntu-latest) (push) Waiting to run
Headless portability / portable-headless (windows-latest) (push) Waiting to run
Headless portability / linux-graphical (push) Waiting to run
Headless portability / linux-vulkan (push) Waiting to run
Some checks are pending
Headless portability / portable-headless (ubuntu-latest) (push) Waiting to run
Headless portability / portable-headless (windows-latest) (push) Waiting to run
Headless portability / linux-graphical (push) Waiting to run
Headless portability / linux-vulkan (push) Waiting to run
All nine findings from the buy-arc review, at root: F1 the materializer's retire pass re-checks ownership (guid->vendorId map; remove only while the live object's ContainerId still equals the recording vendor) — buying a player-sold UNIQUE no longer deletes the item you just purchased; the discriminating reparent-then-refresh test pins it. F2 the cost/name display subscribes to the live split state and shares ONE quantity computation with Buy (retail re-renders per slider tick: RecvNotice_StackSliderChanged 0x004C4500) — the sentence and the charge can no longer disagree. F3 shop rows never mint drag payloads (UiItemSlot.AllowDragSource gates both IsDragSource AND GetDragPayload — the second gate was caught by this pass's own test). F4 sendBuy reports whether anything was sent; a null-session buy cancels the reservation instead of leaking BusyCount forever. F5 the retire loop snapshots, isolates per-guid observer failures, and clears its tracking in finally and Dispose — teardown convergence can no longer wedge. F6 auto-select is retail's unconditional first-filtered-item shape (pc:201180-201184; the survival-check was our invention and the comment claiming otherwise is corrected). F7 non-stack buys clamp to quantity 1 locally (BuySingleItem pc:201669). F8 the Add button is hard-disabled until staging exists. F9 AP-161/162/163 rewritten to the post-fix reality. Clean-room complete solution: 11,378 passed / 4 skipped / 0 failed. The #350 render-ledger overflow observed this session is under separate investigation and is NOT addressed here. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
97cf873870
commit
3c9fc57adb
11 changed files with 670 additions and 116 deletions
|
|
@ -28,6 +28,11 @@ public sealed class ItemInteractionControllerTests
|
|||
public readonly List<(uint Item, uint Amount)> SplitDrops = new();
|
||||
public readonly List<(uint Target, uint Item, uint Amount)> Gives = new();
|
||||
public readonly List<(uint VendorGuid, uint ItemGuid, int Amount, uint AlternateCurrencyId)> Buys = new();
|
||||
// F4 (Slice 6 review): simulates the composition-root sendBuy
|
||||
// delegate's "no live session / not in world" no-op case —
|
||||
// TryBuy must see this as false and release the reservation
|
||||
// rather than mark it dispatched for a request nothing sent.
|
||||
public bool SendBuySucceeds = true;
|
||||
public readonly List<string> Toasts = new();
|
||||
public readonly List<string> SystemMessages = new();
|
||||
public readonly List<CombatMode> CombatModeRequests = new();
|
||||
|
|
@ -97,7 +102,12 @@ public sealed class ItemInteractionControllerTests
|
|||
sendChangeCombatMode: CombatModeRequests.Add,
|
||||
requestUse: requestUse,
|
||||
sendBuy: (vendorGuid, itemGuid, amount, alternateCurrencyId) =>
|
||||
Buys.Add((vendorGuid, itemGuid, amount, alternateCurrencyId)));
|
||||
{
|
||||
if (!SendBuySucceeds)
|
||||
return false;
|
||||
Buys.Add((vendorGuid, itemGuid, amount, alternateCurrencyId));
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public ItemInteractionController Controller { get; }
|
||||
|
|
@ -2267,4 +2277,35 @@ public sealed class ItemInteractionControllerTests
|
|||
|
||||
Assert.Equal(0, h.Controller.BusyCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryBuy_NoSessionToSendOn_ReleasesTheReservation_AndASubsequentBuyWorks()
|
||||
{
|
||||
// F4 (Slice 6 review): the composition-root sendBuy delegate
|
||||
// returns false when there is no live session (or it's not in
|
||||
// world) -- BEFORE this fix, sendBuy was a plain Action, so TryBuy
|
||||
// could not tell "sent" apart from a silent no-op and always
|
||||
// called MarkDispatched(). Since nothing was actually sent, no
|
||||
// UseDone would ever arrive to balance it, leaking BusyCount and
|
||||
// permanently wedging every future Use/Buy behind "You can only
|
||||
// move or use one item at a time."
|
||||
var h = new Harness();
|
||||
h.SendBuySucceeds = false;
|
||||
|
||||
bool result = h.Controller.TryBuy(0x40001000u, 0x50002000u, 1, 0u);
|
||||
|
||||
Assert.False(result);
|
||||
Assert.Empty(h.Buys);
|
||||
// The reservation was cancelled, not dispatched -- the gate is
|
||||
// free again immediately, with no UseDone needed to release it.
|
||||
Assert.Equal(0, h.Controller.BusyCount);
|
||||
|
||||
// A subsequent buy, once a session IS available, proceeds normally.
|
||||
h.SendBuySucceeds = true;
|
||||
bool second = h.Controller.TryBuy(0x40001000u, 0x50002001u, 1, 0u);
|
||||
|
||||
Assert.True(second);
|
||||
Assert.Single(h.Buys);
|
||||
Assert.Equal(1, h.Controller.BusyCount);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue