Class ItemStackTransfer
Moves quantity between two stacks in place: a split takes part of one stack into another slot, a merge pours one stack into a matching one. Issue #198.
public static class ItemStackTransfer
- Inheritance
-
ItemStackTransfer
- Inherited Members
Remarks
Both operations conserve quantity and are all-or-nothing. Every refusal happens
before anything is written, and the one write that can still fail afterwards — placing a
freshly split instance into its slot — is undone by putting the amount back on the source.
A failure therefore leaves the original stack exactly as it was; it never destroys the
remainder. ItemStackSplitMergeTests pins that.
Split and merge are designed as a pair. A split can land on an empty slot (a new instance is created) or on a matching stack with room (the amount is poured across), and a merge is what a whole stack dropped onto a matching stack does instead of swapping. Between them a player can move any quantity anywhere, and neither can strand quantity the other cannot recombine.
The boundaries are fixed here, not left to the arithmetic. Splitting zero is refused. Splitting the whole stack, or more than it holds, is refused: taking everything is a move, and the swap that already exists is the operation for it. A destination that is neither empty nor a matching stack with room for the whole amount is refused rather than partly filled, so the server's answer is either "done as asked" or "nothing happened".
Nothing here persists or broadcasts. The server handler owns writing the rows and telling the owner; the client never calls this at all — it learns the outcome from the set-slot messages the server sends, exactly as it does for a grant.
Methods
CanMergeInto(Item, Item)
True when source dropped onto destination should
merge rather than swap.
public static bool CanMergeInto(Item destination, Item source)
Parameters
Returns
Remarks
Agrees with AddToStack(Item) on purpose, including its refusal of a FULL donor: pouring a full stack into a partial one leaves the donor holding exactly what the destination held, which is a swap by another name — so a swap is what happens.
CanSplitOnto(Item, Item, uint)
True when amount split off source could land on
the item in a destination slot, which must be null (empty) or a matching stack with
room for all of it.
public static bool CanSplitOnto(Item occupant, Item source, uint amount)
Parameters
occupantItemWhatever the destination slot holds, or null.
sourceItemThe stack being split.
amountuintHow much is being taken off it.
Returns
IsValidSplitAmount(Item, uint)
True when amount is a quantity that can be split off
source: at least one, and strictly less than the stack holds.
public static bool IsValidSplitAmount(Item source, uint amount)
Parameters
Returns
Remarks
The whole stack is not a valid split amount. Taking everything is a move, and the existing swap is the operation for that; a split that could take everything would be a second way of moving an item, with a second set of rules to keep in step.
TryMerge(IItemContainer, int, IItemContainer, int, out Item, out Item, out bool)
Pours the stack in fromSlot into the matching stack in
toSlot, as much as fits.
public static bool TryMerge(IItemContainer from, int fromSlot, IItemContainer to, int toSlot, out Item source, out Item destination, out bool sourceEmptied)
Parameters
fromIItemContainerContainer holding the donor.
fromSlotintSlot of the donor.
toIItemContainerContainer holding the receiving stack. May be
from.toSlotintSlot of the receiving stack.
sourceItemThe donor.
destinationItemThe receiving stack.
sourceEmptiedboolTrue when the donor was fully absorbed and its slot cleared.
Returns
- bool
True when quantity moved. False leaves both containers untouched.
Remarks
The donor keeps whatever did not fit and stays in its slot; when everything fit the
donor's slot is emptied and sourceEmptied reports it, so the caller
can delete the row. The donor instance is handed back either way and is not destroyed
here — the caller still needs its identity and version for the delete.
TrySplit(IItemContainer, int, IItemContainer, int, uint, out Item, out Item, out bool)
Takes amount off the stack in fromSlot and puts it
in toSlot: into a new instance when that slot is empty, onto the
matching stack already there when it is not.
public static bool TrySplit(IItemContainer from, int fromSlot, IItemContainer to, int toSlot, uint amount, out Item source, out Item destination, out bool destinationCreated)
Parameters
fromIItemContainerContainer holding the stack being split.
fromSlotintSlot of the stack being split.
toIItemContainerContainer receiving the split half. May be
from.toSlotintSlot receiving the split half.
amountuintHow much to take. Must be at least 1 and less than the stack holds.
sourceItemThe stack that was split, now smaller by
amount.destinationItemThe item now in
toSlot: a new instance withID = 0whendestinationCreatedis true, otherwise the stack that was already there.destinationCreatedboolTrue when a new instance was allocated for the split half.
Returns
- bool
True when quantity moved. False leaves both containers untouched.