Commit a9d2ad7
committed
feat(container): add C_Container.SortBags and SortBankBags
Two phases, because every item move is a server round trip and the second
phase reads slot contents the first changed. Phase one packs partial
stacks; phase two runs on the next Bag::UpdateDelayed, plans the whole
layout, and fires the swaps as one batch, tracking each item's live
position rather than re-reading a layout it is mutating.
The ordering is ours, since retail computes it in code we cannot read and
its categories have no counterpart here: hearthstone, gear by descending
quality, consumables, reagents, trade goods, quest items, everything else
by quality, junk last and filled from the far end. Then class, subclass,
name, fuller stacks first - a real tuple comparator, so there is no
zero-padding to overflow and no placeholder name to wedge an unnamed item
among real ones. An item whose data has not arrived is pinned in place
with its slot withheld, rather than ranked by guesswork.
Neither phase may touch the Lua stack, since phase two runs from a bag
update callback. Hence Lua-free ContainersFrom / AutoStoreFrom /
MoveCountFrom, with the Lua-taking forms reduced to resolving the source
pointer and delegating, plus a direct invMgr walk instead of ResolveBag.
Five things had to be found the hard way, every one of them the client's
local state disagreeing with the server's:
- Never plan a swap between two stacks of the same item. Player::SwapItem
tries a MERGE before it considers swapping and returns if that
succeeds, collapsing two slots into one or redistributing counts and
leaving both in place. Neither is a swap, so a single collision
invalidated the bookkeeping for every move after it in the batch. One
collision in a 55-item bag turned one pass into three.
- Entry marked "unplaced" with destBag = -1, safe while bag IDs were 0..4
and wrong the moment the main bank joined as bagID -1: every item bound
for the main bank read as unplaced and had its move dropped, so nothing
could move into the main bank at all. The sentinel is destSlot now,
which cannot collide because slots are 1-based.
- FUN_INVENTORY_SWAP's last argument gates a pre-send confirmation check.
With 0, a Bind-on-Equip item the character could wear is stashed behind
the bind dialog and NO PACKET IS SENT - silently, since the builder
returns void. Now passes 1, which is what the engine itself does when
re-issuing a swap after the dialog is accepted, and is correct here
because both endpoints are always bag content slots where nothing binds.
- CMSG_AUTOSTORE_BAG_ITEM cannot merge across bags. Its destination byte
can only be INVENTORY_SLOT_BAG_0 (255) for the player, and server-side
that is the specific-container branch: keyring and backpack only. The
search-every-bag path is NULL_BAG (0), which the builder cannot emit.
Both sets now use one explicit two-pointer merge that addresses both
endpoints and works everywhere. It costs a packet per transfer rather
than per emptied source, which is the price of being correct.
- The merge loop must choose split-versus-swap from its own model, not
the item's live stack count. The batch goes out in one frame with no
replies, so descriptors still hold pre-batch counts; a move the model
knew was the last of a stack went out as a split, and the server
rejects a split that would empty its source.
Consolidation packs fully rather than stopping once a slot is freed: 9
and 2 with a cap of 10 become 10 and 1. It settles in one pass and sends
nothing on the next call, because a packed group has every stack full
except the last, so the first step walks straight to the end.
Bank specifics: ViewForBag gains the main bank (bagID -1, inside the
player's own invMgr) and bank bags (5..10, each with its own), which can
themselves be specialty bags. Bank bags resolve only once the bank window
has been opened, which is the right gate rather than an accident - the
server refuses bank moves without it, so a bank sort with the bank closed
finds no cells and does nothing instead of dispatching a batch that would
be rejected wholesale.
_classicapi_SortBagsStats() and _classicapi_SortBagsBags() report the last
pass and the per-bag view. Both earned their keep: the stats ruled out our
side of the swap divergence by showing a complete plan fully dispatched
with zero local failures, and the per-bag dump ended the sentinel hunt by
eliminating the entire area three successive guesses had been aimed at.1 parent db88fca commit a9d2ad7
6 files changed
Lines changed: 991 additions & 25 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
65 | | - | |
| 65 | + | |
66 | 66 | | |
67 | 67 | | |
68 | 68 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
| 91 | + | |
| 92 | + | |
91 | 93 | | |
92 | 94 | | |
93 | 95 | | |
| |||
2362 | 2364 | | |
2363 | 2365 | | |
2364 | 2366 | | |
| 2367 | + | |
| 2368 | + | |
| 2369 | + | |
| 2370 | + | |
| 2371 | + | |
| 2372 | + | |
| 2373 | + | |
| 2374 | + | |
| 2375 | + | |
| 2376 | + | |
| 2377 | + | |
| 2378 | + | |
| 2379 | + | |
| 2380 | + | |
| 2381 | + | |
| 2382 | + | |
| 2383 | + | |
| 2384 | + | |
| 2385 | + | |
| 2386 | + | |
| 2387 | + | |
| 2388 | + | |
| 2389 | + | |
| 2390 | + | |
| 2391 | + | |
| 2392 | + | |
| 2393 | + | |
| 2394 | + | |
| 2395 | + | |
| 2396 | + | |
| 2397 | + | |
| 2398 | + | |
| 2399 | + | |
| 2400 | + | |
| 2401 | + | |
| 2402 | + | |
| 2403 | + | |
| 2404 | + | |
| 2405 | + | |
| 2406 | + | |
| 2407 | + | |
| 2408 | + | |
| 2409 | + | |
| 2410 | + | |
| 2411 | + | |
| 2412 | + | |
| 2413 | + | |
| 2414 | + | |
| 2415 | + | |
| 2416 | + | |
| 2417 | + | |
| 2418 | + | |
| 2419 | + | |
| 2420 | + | |
| 2421 | + | |
| 2422 | + | |
| 2423 | + | |
| 2424 | + | |
| 2425 | + | |
| 2426 | + | |
| 2427 | + | |
| 2428 | + | |
| 2429 | + | |
2365 | 2430 | | |
2366 | 2431 | | |
2367 | 2432 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
812 | 812 | | |
813 | 813 | | |
814 | 814 | | |
815 | | - | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
816 | 837 | | |
817 | 838 | | |
818 | 839 | | |
| |||
0 commit comments