+ ItemStack src_item = list_from->getItem(from_i);
+ src_item.count = count;
+ ItemStack from_stack_was = list_from->getItem(from_i);
+ ItemStack to_stack_was = list_to->getItem(to_i);
+
+ /*
+ Perform actual move
+
+ If something is wrong (source item is empty, destination is the
+ same as source), nothing happens
+ */
+ list_from->moveItem(from_i, list_to, to_i, count);
+
+ // If source is infinite, reset it's stack
+ if(src_can_take_count == -1){
+ // If destination stack is of different type and there are leftover
+ // items, attempt to put the leftover items to a different place in the
+ // destination inventory.
+ // The client-side GUI will try to guess if this happens.
+ if(from_stack_was.name != to_stack_was.name){
+ for(u32 i=0; i<list_to->getSize(); i++){
+ if(list_to->getItem(i).empty()){
+ list_to->changeItem(i, to_stack_was);
+ break;
+ }
+ }
+ }
+ list_from->deleteItem(from_i);
+ list_from->addItem(from_i, from_stack_was);
+ }
+ // If destination is infinite, reset it's stack and take count from source
+ if(dst_can_put_count == -1){
+ list_to->deleteItem(to_i);
+ list_to->addItem(to_i, to_stack_was);
+ list_from->deleteItem(from_i);
+ list_from->addItem(from_i, from_stack_was);
+ list_from->takeItem(from_i, count);
+ }
+
+ infostream<<"IMoveAction::apply(): moved"
+ <<" count="<<count
+ <<" from inv=\""<<from_inv.dump()<<"\""
+ <<" list=\""<<from_list<<"\""
+ <<" i="<<from_i
+ <<" to inv=\""<<to_inv.dump()<<"\""
+ <<" list=\""<<to_list<<"\""
+ <<" i="<<to_i
+ <<std::endl;
+
+ /*
+ Record rollback information
+ */
+ if(!ignore_rollback && gamedef->rollback())
+ {
+ IRollbackReportSink *rollback = gamedef->rollback();
+
+ // If source is not infinite, record item take
+ if(src_can_take_count != -1){
+ RollbackAction action;
+ std::string loc;
+ {
+ std::ostringstream os(std::ios::binary);
+ from_inv.serialize(os);
+ loc = os.str();
+ }
+ action.setModifyInventoryStack(loc, from_list, from_i, false,
+ src_item.getItemString());
+ rollback->reportAction(action);
+ }
+ // If destination is not infinite, record item put
+ if(dst_can_put_count != -1){
+ RollbackAction action;
+ std::string loc;
+ {
+ std::ostringstream os(std::ios::binary);
+ to_inv.serialize(os);
+ loc = os.str();
+ }
+ action.setModifyInventoryStack(loc, to_list, to_i, true,
+ src_item.getItemString());
+ rollback->reportAction(action);
+ }
+ }
+
+ /*
+ Report move to endpoints
+ */
+
+ /* Detached inventories */
+
+ // Both endpoints are same detached
+ if(from_inv.type == InventoryLocation::DETACHED &&
+ to_inv.type == InventoryLocation::DETACHED &&
+ from_inv.name == to_inv.name)
+ {
+ PLAYER_TO_SA(player)->detached_inventory_OnMove(
+ from_inv.name, from_list, from_i,
+ to_list, to_i, count, player);
+ }
+ else
+ {
+ // Destination is detached
+ if(to_inv.type == InventoryLocation::DETACHED)
+ {
+ PLAYER_TO_SA(player)->detached_inventory_OnPut(
+ to_inv.name, to_list, to_i, src_item, player);
+ }
+ // Source is detached
+ if(from_inv.type == InventoryLocation::DETACHED)
+ {
+ PLAYER_TO_SA(player)->detached_inventory_OnTake(
+ from_inv.name, from_list, from_i, src_item, player);
+ }
+ }
+
+ /* Node metadata inventories */
+
+ // Both endpoints are same nodemeta
+ if(from_inv.type == InventoryLocation::NODEMETA &&
+ to_inv.type == InventoryLocation::NODEMETA &&
+ from_inv.p == to_inv.p)
+ {
+ PLAYER_TO_SA(player)->nodemeta_inventory_OnMove(
+ from_inv.p, from_list, from_i,
+ to_list, to_i, count, player);
+ }
+ else{
+ // Destination is nodemeta
+ if(to_inv.type == InventoryLocation::NODEMETA)
+ {
+ PLAYER_TO_SA(player)->nodemeta_inventory_OnPut(
+ to_inv.p, to_list, to_i, src_item, player);
+ }
+ // Source is nodemeta
+ else if(from_inv.type == InventoryLocation::NODEMETA)
+ {
+ PLAYER_TO_SA(player)->nodemeta_inventory_OnTake(
+ from_inv.p, from_list, from_i, src_item, player);
+ }
+ }
+