Skip to content
Browse files

Fix inventory swapping not calling all callbacks (#9923)

"Predicts" whether something will be swapped for allow callbacks, then calls callbacks a second time with swapped properties.

Co-authored-by: SmallJoker <>
  • Loading branch information
appgurueu and SmallJoker committed Sep 4, 2020
1 parent 4ba5046 commit 050964bed6005f8d816ddf362b9fc8675581d190
Showing with 210 additions and 139 deletions.
  1. +25 −0 doc/lua_api.txt
  2. +4 −5 src/inventory.cpp
  3. +169 −134 src/inventorymanager.cpp
  4. +12 −0 src/inventorymanager.h
@@ -5888,6 +5888,31 @@ An `InvRef` is a reference to an inventory.
* returns `{type="undefined"}` in case location is not known

### Callbacks

Detached & nodemeta inventories provide the following callbacks for move actions:

#### Before

The `allow_*` callbacks return how many items can be moved.

* `allow_move`/`allow_metadata_inventory_move`: Moving items in the inventory
* `allow_take`/`allow_metadata_inventory_take`: Taking items from the inventory
* `allow_put`/`allow_metadata_inventory_put`: Putting items to the inventory

#### After

The `on_*` callbacks are called after the items have been placed in the inventories.

* `on_move`/`on_metadata_inventory_move`: Moving items in the inventory
* `on_take`/`on_metadata_inventory_take`: Taking items from the inventory
* `on_put`/`on_metadata_inventory_put`: Putting items to the inventory

#### Swapping

When a player tries to put an item to a place where another item is, the items are *swapped*.
This means that all callbacks will be called twice (once for each action).


@@ -732,26 +732,25 @@ void InventoryList::moveItemSomewhere(u32 i, InventoryList *dest, u32 count)
u32 InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i,
u32 count, bool swap_if_needed, bool *did_swap)
if(this == dest && i == dest_i)
if (this == dest && i == dest_i)
return count;

// Take item from source list
ItemStack item1;
if(count == 0)
if (count == 0)
item1 = changeItem(i, ItemStack());
item1 = takeItem(i, count);

if (item1.empty())
return 0;

// Try to add the item to destination list
u32 oldcount = item1.count;
item1 = dest->addItem(dest_i, item1);

// If something is returned, the item was not fully added
if (!item1.empty()) {
// If olditem is returned, nothing was added.
bool nothing_added = (item1.count == oldcount);

0 comments on commit 050964b

Please sign in to comment.
You can’t perform that action at this time.