fix(ui): port retail partial stack transfers
Route the selected stack quantity through retail GetObjectSplitSize semantics, send exact split-to-container and split-to-ground actions, and keep the original object in place until the server publishes the newly guided stack. Cover selection scoping, wire bytes, container placement, and world drops with conformance tests. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
6005c51c4d
commit
ea72c395c9
14 changed files with 280 additions and 19 deletions
|
|
@ -794,6 +794,44 @@ UseWithTarget (0x0035): u32 sourceObjectId, u32 targetObjectId
|
|||
|
||||
## 8. `AttemptPlaceIn3D` pseudocode
|
||||
|
||||
### 8.1 Shared selected-stack amount
|
||||
|
||||
```text
|
||||
GetObjectSplitSize(item): // 0x00586F00
|
||||
if item.id == selectedID:
|
||||
return GenItemHolder.splitSize
|
||||
if item.stackSize != 0:
|
||||
return item.stackSize
|
||||
return 1
|
||||
```
|
||||
|
||||
The quantity field is therefore global UI state, but it applies only to the
|
||||
currently selected object. Dragging any other stack uses that object's full
|
||||
quantity.
|
||||
|
||||
### 8.2 Container move versus container split
|
||||
|
||||
After the legality, capacity, and auto-merge branches choose a destination,
|
||||
retail makes this exact decision:
|
||||
|
||||
```text
|
||||
AttemptToPlaceInContainer(itemId, containerId, ..., placement): // 0x00588140
|
||||
...legality and destination selection...
|
||||
if splitSize >= maxSplitSize:
|
||||
item.UIAttemptPutInContainer(containerId, placement)
|
||||
return true
|
||||
item.UIAttemptSplitToContainer(containerId, placement, splitSize)
|
||||
return true
|
||||
|
||||
UIAttemptSplitToContainer(item, containerId, placement, amount): // 0x0058D7D0
|
||||
Event_StackableSplitToContainer(item.id, containerId, placement, amount)
|
||||
```
|
||||
|
||||
The partial path sends GameAction `0x0055` with
|
||||
`(stackGuid, containerGuid, placement, amount)`. It does not move the original
|
||||
client object into the destination: the server reduces that source stack and
|
||||
creates a distinct destination object with a new guid.
|
||||
|
||||
```text
|
||||
AttemptPlaceIn3D(itemId, targetId, allowGroundFallback): // 0x00588600
|
||||
if player not ready for inventory request: return false
|
||||
|
|
@ -873,6 +911,11 @@ The vendor-drop test is now pinned. Matching-executable disassembly at
|
|||
`0x00000200 = BF_VENDOR`. It is an object-trait test, distinct from
|
||||
`ClientUISystem.vendorID`.
|
||||
|
||||
`UIAttemptSplitTo3D @ 0x0058D850` dispatches
|
||||
`CM_Inventory::Event_StackableSplitTo3D @ 0x006ABFC0`, GameAction `0x0056`
|
||||
with `(stackGuid, amount)`. Like the container split, the source object remains
|
||||
in place until authoritative server updates arrive.
|
||||
|
||||
---
|
||||
|
||||
## 9. Target-mode click ordering
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue