diff --git a/.gitignore b/.gitignore index cd6ee3e32..b0b69edf4 100644 --- a/.gitignore +++ b/.gitignore @@ -85,3 +85,6 @@ build/android/path.cfg build/android/and_env build/android/AndroidManifest.xml timestamp + +## Backup files +*backup.tar.gz diff --git a/builtin/game/register.lua b/builtin/game/register.lua index f330491a2..df473ccbe 100644 --- a/builtin/game/register.lua +++ b/builtin/game/register.lua @@ -510,7 +510,15 @@ core.registered_craft_predicts, core.register_craft_predict = make_registration( core.registered_on_protection_violation, core.register_on_protection_violation = make_registration() core.registered_on_item_eats, core.register_on_item_eat = make_registration() core.registered_on_punchplayers, core.register_on_punchplayer = make_registration() - +core.registered_on_player_inventory_remove_item, core.register_on_player_inventory_remove_item = make_registration() +core.registered_on_player_inventory_change_item, core.register_on_player_inventory_change_item = make_registration() +core.registered_on_player_inventory_add_item, core.register_on_player_inventory_add_item = make_registration() +core.registered_on_nodemeta_inventory_remove_item, core.register_on_nodemeta_inventory_remove_item = make_registration() +core.registered_on_nodemeta_inventory_change_item, core.register_on_nodemeta_inventory_change_item = make_registration() +core.registered_on_nodemeta_inventory_add_item, core.register_on_nodemeta_inventory_add_item = make_registration() +core.registered_on_detached_inventory_remove_item, core.register_on_detached_inventory_remove_item = make_registration() +core.registered_on_detached_inventory_change_item, core.register_on_detached_inventory_change_item = make_registration() +core.registered_on_detached_inventory_add_item, core.register_on_detached_inventory_add_item = make_registration() -- -- Compatibility for on_mapgen_init() -- diff --git a/src/content_nodemeta.cpp b/src/content_nodemeta.cpp index 7f4264d8e..c9da2c36d 100644 --- a/src/content_nodemeta.cpp +++ b/src/content_nodemeta.cpp @@ -145,7 +145,7 @@ static bool content_nodemeta_deserialize_legacy_meta( void content_nodemeta_deserialize_legacy(std::istream &is, NodeMetadataList *meta, NodeTimerList *timers, - IItemDefManager *item_def_mgr) + IItemDefManager *item_def_mgr, v3s16 relative_mapblock_pos) { meta->clear(); timers->clear(); @@ -181,7 +181,7 @@ void content_nodemeta_deserialize_legacy(std::istream &is, continue; } - NodeMetadata *data = new NodeMetadata(item_def_mgr); + NodeMetadata *data = new NodeMetadata(item_def_mgr, relative_mapblock_pos + p); bool need_timer = content_nodemeta_deserialize_legacy_meta(is, data); meta->set(p, data); diff --git a/src/content_nodemeta.h b/src/content_nodemeta.h index ebc01d9a8..a65eddfee 100644 --- a/src/content_nodemeta.h +++ b/src/content_nodemeta.h @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define CONTENT_NODEMETA_HEADER #include +#include "irr_v3d.h" // For v3s16 class NodeMetadataList; class NodeTimerList; @@ -32,7 +33,7 @@ class IItemDefManager; void content_nodemeta_deserialize_legacy(std::istream &is, NodeMetadataList *meta, NodeTimerList *timers, - IItemDefManager *item_def_mgr); + IItemDefManager *item_def_mgr, v3s16 relative_mapblock_pos); void content_nodemeta_serialize_legacy(std::ostream &os, NodeMetadataList *meta); diff --git a/src/game.cpp b/src/game.cpp index d513517b7..b90360f0f 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2143,7 +2143,8 @@ bool Game::createClient(const std::string &playername, sky = new Sky(smgr->getRootSceneNode(), smgr, -1, texture_src); skybox = NULL; // This is used/set later on in the main run loop - local_inventory = new Inventory(itemdef_manager); + LocalPlayer *player = client->getEnv().getLocalPlayer(); + local_inventory = new Inventory(itemdef_manager, player); if (!(sky && local_inventory)) { *error_message = "Memory allocation error (sky or local inventory)"; @@ -2172,7 +2173,6 @@ bool Game::createClient(const std::string &playername, str += L"]"; device->setWindowCaption(str.c_str()); - LocalPlayer *player = client->getEnv().getLocalPlayer(); player->hurt_tilt_timer = 0; player->hurt_tilt_strength = 0; diff --git a/src/inventory.cpp b/src/inventory.cpp index fce8575e7..47ddfef14 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nameidmapping.h" // For loading legacy MaterialItems #include "util/serialize.h" #include "util/string.h" +#include "script/scripting_game.h" /* ItemStack @@ -432,12 +433,13 @@ ItemStack ItemStack::peekItem(u32 peekcount) const Inventory */ -InventoryList::InventoryList(std::string name, u32 size, IItemDefManager *itemdef) +InventoryList::InventoryList(std::string name, u32 size, IItemDefManager *itemdef, InventoryChangeReceiver *rec) { m_name = name; m_size = size; m_width = 0; m_itemdef = itemdef; + m_rec=rec; clearItems(); //m_dirty = false; } @@ -562,6 +564,7 @@ InventoryList & InventoryList::operator = (const InventoryList &other) m_width = other.m_width; m_name = other.m_name; m_itemdef = other.m_itemdef; + m_rec = other.m_rec; //setDirty(true); return *this; @@ -630,30 +633,31 @@ ItemStack& InventoryList::getItem(u32 i) return m_items[i]; } -ItemStack InventoryList::changeItem(u32 i, const ItemStack &newitem) +ItemStack InventoryList::changeItem(GameScripting *script_interface, u32 i, const ItemStack &new_item) { if(i >= m_items.size()) - return newitem; - - ItemStack olditem = m_items[i]; - m_items[i] = newitem; + return new_item; + ItemStack old_item = m_items[i]; + m_items[i] = new_item; + m_rec->on_change_item(script_interface, this, i, old_item, new_item); //setDirty(true); - return olditem; + return old_item; } -void InventoryList::deleteItem(u32 i) +void InventoryList::deleteItem(GameScripting *script_interface, u32 i) { assert(i < m_items.size()); // Pre-condition + m_rec->on_remove_item(script_interface, this, m_items[i]); m_items[i].clear(); } -ItemStack InventoryList::addItem(const ItemStack &newitem_) +ItemStack InventoryList::addItem(GameScripting *script_interface, const ItemStack &new_item_) { - ItemStack newitem = newitem_; - - if(newitem.empty()) - return newitem; + ItemStack new_item = new_item_; + if(new_item.empty()){ + return new_item; + } /* First try to find if it could be added to some existing items */ @@ -663,9 +667,9 @@ ItemStack InventoryList::addItem(const ItemStack &newitem_) if(m_items[i].empty()) continue; // Try adding - newitem = addItem(i, newitem); - if(newitem.empty()) - return newitem; // All was eaten + new_item = addItem(script_interface, i, new_item); + if(new_item.empty()) + return new_item; // All was eaten } /* @@ -677,22 +681,28 @@ ItemStack InventoryList::addItem(const ItemStack &newitem_) if(!m_items[i].empty()) continue; // Try adding - newitem = addItem(i, newitem); - if(newitem.empty()) - return newitem; // All was eaten + new_item = addItem(script_interface, i, new_item); + if(new_item.empty()) + return new_item; // All was eaten } // Return leftover - return newitem; + return new_item; } -ItemStack InventoryList::addItem(u32 i, const ItemStack &newitem) +ItemStack InventoryList::addItem(GameScripting *script_interface, u32 i, const ItemStack &new_item) { if(i >= m_items.size()) - return newitem; - - ItemStack leftover = m_items[i].addItem(newitem, m_itemdef); - //if(leftover != newitem) + return new_item; + u16 count_before = 0; + count_before = new_item.count; + std::string item_name = new_item.name; + ItemStack leftover = m_items[i].addItem(new_item, m_itemdef); + if(leftover.count != count_before){ + ItemStack added_item (item_name,count_before - leftover.count, new_item.wear, new_item.metadata, m_itemdef); + m_rec->on_add_item(script_interface, this, i, added_item); + } + //if(leftover != new_item) // setDirty(true); return leftover; } @@ -745,7 +755,7 @@ bool InventoryList::containsItem(const ItemStack &item) const return false; } -ItemStack InventoryList::removeItem(const ItemStack &item) +ItemStack InventoryList::removeItem(GameScripting *script_interface, const ItemStack &item) { ItemStack removed; for(std::vector::reverse_iterator @@ -760,10 +770,12 @@ ItemStack InventoryList::removeItem(const ItemStack &item) break; } } + + m_rec->on_remove_item(script_interface, this, removed); return removed; } -ItemStack InventoryList::takeItem(u32 i, u32 takecount) +ItemStack InventoryList::takeItem(GameScripting *script_interface, u32 i, u32 takecount) { if(i >= m_items.size()) return ItemStack(); @@ -771,6 +783,7 @@ ItemStack InventoryList::takeItem(u32 i, u32 takecount) ItemStack taken = m_items[i].takeItem(takecount); //if(!taken.empty()) // setDirty(true); + m_rec->on_remove_item(script_interface, this, taken); return taken; } @@ -782,14 +795,14 @@ ItemStack InventoryList::peekItem(u32 i, u32 peekcount) const return m_items[i].peekItem(peekcount); } -void InventoryList::moveItemSomewhere(u32 i, InventoryList *dest, u32 count) +void InventoryList::moveItemSomewhere(GameScripting *script_interface, u32 i, InventoryList *dest, u32 count) { // Take item from source list ItemStack item1; if (count == 0) - item1 = changeItem(i, ItemStack()); + item1 = changeItem(script_interface, i, ItemStack()); else - item1 = takeItem(i, count); + item1 = takeItem(script_interface, i, count); if (item1.empty()) return; @@ -799,7 +812,7 @@ void InventoryList::moveItemSomewhere(u32 i, InventoryList *dest, u32 count) // First try all the non-empty slots for (u32 dest_i = 0; dest_i < dest_size; dest_i++) { if (!m_items[dest_i].empty()) { - item1 = dest->addItem(dest_i, item1); + item1 = dest->addItem(script_interface, dest_i, item1); if (item1.empty()) return; } } @@ -807,17 +820,17 @@ void InventoryList::moveItemSomewhere(u32 i, InventoryList *dest, u32 count) // Then try all the empty ones for (u32 dest_i = 0; dest_i < dest_size; dest_i++) { if (m_items[dest_i].empty()) { - item1 = dest->addItem(dest_i, item1); + item1 = dest->addItem(script_interface, dest_i, item1); if (item1.empty()) return; } } // If we reach this, the item was not fully added // Add the remaining part back to the source item - addItem(i, item1); + addItem(script_interface, i, item1); } -u32 InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, +u32 InventoryList::moveItem(GameScripting *script_interface, u32 i, InventoryList *dest, u32 dest_i, u32 count, bool swap_if_needed, bool *did_swap) { if(this == dest && i == dest_i) @@ -826,16 +839,16 @@ u32 InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, // Take item from source list ItemStack item1; if(count == 0) - item1 = changeItem(i, ItemStack()); + item1 = changeItem(script_interface, i, ItemStack()); else - item1 = takeItem(i, count); + item1 = takeItem(script_interface, 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); + item1 = dest->addItem(script_interface, dest_i, item1); // If something is returned, the item was not fully added if(!item1.empty()) @@ -845,7 +858,7 @@ u32 InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, // If something else is returned, part of the item was left unadded. // Add the other part back to the source item - addItem(i, item1); + addItem(script_interface, i, item1); // If olditem is returned, nothing was added. // Swap the items @@ -855,16 +868,51 @@ u32 InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, *did_swap = true; } // Take item from source list - item1 = changeItem(i, ItemStack()); + item1 = changeItem(script_interface, i, ItemStack()); // Adding was not possible, swap the items. - ItemStack item2 = dest->changeItem(dest_i, item1); + ItemStack item2 = dest->changeItem(script_interface, dest_i, item1); // Put item from destination list to the source list - changeItem(i, item2); + changeItem(script_interface, i, item2); } } return (oldcount - item1.count); } +/* + DetachedInventoryChangeReceiver +*/ + +DetachedInventoryChangeReceiver::DetachedInventoryChangeReceiver(const std::string &name) +{ + m_name=name; +} + +DetachedInventoryChangeReceiver::~DetachedInventoryChangeReceiver() +{ + delete &m_name; +} + +void DetachedInventoryChangeReceiver::on_remove_item(GameScripting *script_interface, const InventoryList *inventory_list, const ItemStack &deleted_item) +{ + if(script_interface){ + script_interface->on_detached_inventory_remove_item(m_name, inventory_list->getName(), deleted_item); + } +} + +void DetachedInventoryChangeReceiver::on_change_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &old_item,const ItemStack &new_item) +{ + if(script_interface){ + script_interface->on_detached_inventory_change_item(m_name, inventory_list->getName(), query_slot, old_item, new_item); + } +} + +void DetachedInventoryChangeReceiver::on_add_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &added_item) +{ + if(script_interface){ + script_interface->on_detached_inventory_add_item(m_name, inventory_list->getName(), query_slot, added_item); + } +} + /* Inventory */ @@ -892,15 +940,16 @@ void Inventory::clearContents() InventoryList *list = m_lists[i]; for(u32 j=0; jgetSize(); j++) { - list->deleteItem(j); + list->deleteItem(NULL, j); } } } -Inventory::Inventory(IItemDefManager *itemdef) +Inventory::Inventory(IItemDefManager *itemdef, InventoryChangeReceiver *rec) { m_dirty = false; m_itemdef = itemdef; + m_rec = rec; } Inventory::Inventory(const Inventory &other) @@ -981,7 +1030,7 @@ void Inventory::deSerialize(std::istream &is) std::getline(iss, listname, ' '); iss>>listsize; - InventoryList *list = new InventoryList(listname, listsize, m_itemdef); + InventoryList *list = new InventoryList(listname, listsize, m_itemdef, m_rec); list->deSerialize(is); m_lists.push_back(list); @@ -1002,7 +1051,7 @@ InventoryList * Inventory::addList(const std::string &name, u32 size) if(m_lists[i]->getSize() != size) { delete m_lists[i]; - m_lists[i] = new InventoryList(name, size, m_itemdef); + m_lists[i] = new InventoryList(name, size, m_itemdef, m_rec); } return m_lists[i]; } @@ -1011,7 +1060,7 @@ InventoryList * Inventory::addList(const std::string &name, u32 size) //don't create list with invalid name if (name.find(" ") != std::string::npos) return NULL; - InventoryList *list = new InventoryList(name, size, m_itemdef); + InventoryList *list = new InventoryList(name, size, m_itemdef, m_rec); m_lists.push_back(list); return list; } diff --git a/src/inventory.h b/src/inventory.h index a690eb5ae..d258db014 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -27,8 +27,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include "cpp_api/s_base.h" // For ScriptApiBase -struct ToolCapabilities; +class InventoryChangeReceiver; +class GameScripting; struct ItemStack { @@ -173,7 +175,7 @@ struct ItemStack class InventoryList { public: - InventoryList(std::string name, u32 size, IItemDefManager *itemdef); + InventoryList(std::string name, u32 size, IItemDefManager *itemdef, InventoryChangeReceiver *rec); ~InventoryList(); void clearItems(); void setSize(u32 newsize); @@ -201,18 +203,18 @@ public: const ItemStack& getItem(u32 i) const; ItemStack& getItem(u32 i); // Returns old item. Parameter can be an empty item. - ItemStack changeItem(u32 i, const ItemStack &newitem); + ItemStack changeItem(GameScripting *script_interface, u32 i, const ItemStack &newitem); // Delete item - void deleteItem(u32 i); + void deleteItem(GameScripting *script_interface, u32 i); // Adds an item to a suitable place. Returns leftover item (possibly empty). - ItemStack addItem(const ItemStack &newitem); + ItemStack addItem(GameScripting *script_interface, const ItemStack &newitem); // If possible, adds item to given slot. // If cannot be added at all, returns the item back. // If can be added partly, decremented item is returned back. // If can be added fully, empty item is returned. - ItemStack addItem(u32 i, const ItemStack &newitem); + ItemStack addItem(GameScripting *script_interface, u32 i, const ItemStack &newitem); // Checks whether the item could be added to the given slot // If restitem is non-NULL, it receives the part of newitem that @@ -232,12 +234,12 @@ public: // If not as many items exist as requested, removes as // many as possible. // Returns the items that were actually removed. - ItemStack removeItem(const ItemStack &item); + ItemStack removeItem(GameScripting *script_interface, const ItemStack &item); // Takes some items from a slot. // If there are not enough, takes as many as it can. // Returns empty item if couldn't take any. - ItemStack takeItem(u32 i, u32 takecount); + ItemStack takeItem(GameScripting *script_interface, u32 i, u32 takecount); // Similar to takeItem, but keeps the slot intact. ItemStack peekItem(u32 i, u32 peekcount) const; @@ -245,18 +247,39 @@ public: // Move an item to a different list (or a different stack in the same list) // count is the maximum number of items to move (0 for everything) // returns number of moved items - u32 moveItem(u32 i, InventoryList *dest, u32 dest_i, + u32 moveItem(GameScripting *script_interface, u32 i, InventoryList *dest, u32 dest_i, u32 count = 0, bool swap_if_needed = true, bool *did_swap = NULL); // like moveItem, but without a fixed destination index // also with optional rollback recording - void moveItemSomewhere(u32 i, InventoryList *dest, u32 count); + void moveItemSomewhere(GameScripting *script_interface, u32 i, InventoryList *dest, u32 count); private: std::vector m_items; u32 m_size, m_width; std::string m_name; IItemDefManager *m_itemdef; + InventoryChangeReceiver *m_rec; +}; + +class InventoryChangeReceiver +{ +public: + virtual void on_remove_item(GameScripting *script_interface, const InventoryList *inventory_list, const ItemStack &deleted_item) = 0; + virtual void on_change_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &old_item,const ItemStack &new_item) = 0; + virtual void on_add_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &added_item) = 0; + virtual ~InventoryChangeReceiver() {}; +}; + +class DetachedInventoryChangeReceiver: public InventoryChangeReceiver +{ + std::string m_name; +public: + DetachedInventoryChangeReceiver(const std::string &name); + ~DetachedInventoryChangeReceiver(); + void on_remove_item(GameScripting *script_interface, const InventoryList *inventory_list, const ItemStack &deleted_item); + void on_change_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &old_item,const ItemStack &new_item); + void on_add_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &added_item); }; class Inventory @@ -267,7 +290,7 @@ public: void clear(); void clearContents(); - Inventory(IItemDefManager *itemdef); + Inventory(IItemDefManager *itemdef, InventoryChangeReceiver *m_rec); Inventory(const Inventory &other); Inventory & operator = (const Inventory &other); bool operator == (const Inventory &other) const; @@ -284,15 +307,6 @@ public: const InventoryList * getList(const std::string &name) const; std::vector getLists(); bool deleteList(const std::string &name); - // A shorthand for adding items. Returns leftover item (possibly empty). - ItemStack addItem(const std::string &listname, const ItemStack &newitem) - { - m_dirty = true; - InventoryList *list = getList(listname); - if(list == NULL) - return newitem; - return list->addItem(newitem); - } bool checkModified() const { @@ -309,6 +323,7 @@ private: const s32 getListIndex(const std::string &name) const; std::vector m_lists; + InventoryChangeReceiver *m_rec; IItemDefManager *m_itemdef; bool m_dirty; }; diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp index 3d8513492..a7fc72fa6 100644 --- a/src/inventorymanager.cpp +++ b/src/inventorymanager.cpp @@ -376,7 +376,7 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame same as source), nothing happens */ bool did_swap = false; - move_count = list_from->moveItem(from_i, + move_count = list_from->moveItem(PLAYER_TO_SA(player), from_i, list_to, to_i, count, !caused_by_move_somewhere, &did_swap); // If source is infinite, reset it's stack @@ -392,24 +392,24 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame 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); + list_to->changeItem(PLAYER_TO_SA(player), i, to_stack_was); break; } } } } if (move_count > 0 || did_swap) { - list_from->deleteItem(from_i); - list_from->addItem(from_i, from_stack_was); + list_from->deleteItem(PLAYER_TO_SA(player), from_i); + list_from->addItem(PLAYER_TO_SA(player), 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); + list_to->deleteItem(PLAYER_TO_SA(player), to_i); + list_to->addItem(PLAYER_TO_SA(player), to_i, to_stack_was); + list_from->deleteItem(PLAYER_TO_SA(player), from_i); + list_from->addItem(PLAYER_TO_SA(player), from_i, from_stack_was); + list_from->takeItem(PLAYER_TO_SA(player), from_i, count); } infostream << "IMoveAction::apply(): moved" @@ -550,9 +550,9 @@ void IMoveAction::clientApply(InventoryManager *mgr, IGameDef *gamedef) return; if (!move_somewhere) - list_from->moveItem(from_i, list_to, to_i, count); + list_from->moveItem(NULL, from_i, list_to, to_i, count); else - list_from->moveItemSomewhere(from_i, list_to, count); + list_from->moveItemSomewhere(NULL, from_i, list_to, count); mgr->setInventoryModified(from_inv); if(inv_from != inv_to) @@ -663,7 +663,7 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame // If source isn't infinite if(src_can_take_count != -1){ // Take item from source list - ItemStack item2 = list_from->takeItem(from_i, actually_dropped_count); + ItemStack item2 = list_from->takeItem(PLAYER_TO_SA(player), from_i, actually_dropped_count); if(item2.count != actually_dropped_count) errorstream<<"Could not take dropped count of items"<changeItem(from_i, ItemStack()); + list_from->changeItem(NULL, from_i, ItemStack()); else - list_from->takeItem(from_i, count); + list_from->takeItem(NULL, from_i, count); mgr->setInventoryModified(from_inv); } @@ -801,7 +801,7 @@ void ICraftAction::apply(InventoryManager *mgr, ItemStack craftresultitem; int count_remaining = count; std::vector output_replacements; - getCraftingResult(inv_craft, crafted, output_replacements, false, gamedef); + getCraftingResult(PLAYER_TO_SA(player), inv_craft, crafted, output_replacements, false, gamedef); PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv); bool found = !crafted.empty(); @@ -810,9 +810,9 @@ void ICraftAction::apply(InventoryManager *mgr, std::vector temp; // Decrement input and add crafting output - getCraftingResult(inv_craft, crafted, temp, true, gamedef); + getCraftingResult(PLAYER_TO_SA(player), inv_craft, crafted, temp, true, gamedef); PLAYER_TO_SA(player)->item_OnCraft(crafted, player, &saved_craft_list, craft_inv); - list_craftresult->addItem(0, crafted); + list_craftresult->addItem(PLAYER_TO_SA(player), 0, crafted); mgr->setInventoryModified(craft_inv); // Add the new replacements to the list @@ -842,7 +842,7 @@ void ICraftAction::apply(InventoryManager *mgr, count_remaining--; // Get next crafting result - found = getCraftingResult(inv_craft, crafted, temp, false, gamedef); + found = getCraftingResult(PLAYER_TO_SA(player), inv_craft, crafted, temp, false, gamedef); PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv); found = !crafted.empty(); } @@ -852,7 +852,7 @@ void ICraftAction::apply(InventoryManager *mgr, for (std::vector::iterator it = output_replacements.begin(); it != output_replacements.end(); ++it) { if (list_main) - *it = list_main->addItem(*it); + *it = list_main->addItem(PLAYER_TO_SA(player), *it); if (it->empty()) continue; u16 count = it->count; @@ -882,7 +882,7 @@ void ICraftAction::clientApply(InventoryManager *mgr, IGameDef *gamedef) // Crafting helper -bool getCraftingResult(Inventory *inv, ItemStack& result, +bool getCraftingResult(GameScripting *script_interface, Inventory *inv, ItemStack& result, std::vector &output_replacements, bool decrementInput, IGameDef *gamedef) { @@ -914,7 +914,7 @@ bool getCraftingResult(Inventory *inv, ItemStack& result, // CraftInput has been changed, apply changes in clist for(u16 i=0; igetSize(); i++) { - clist->changeItem(i, ci.items[i]); + clist->changeItem(script_interface, i, ci.items[i]); } } diff --git a/src/inventorymanager.h b/src/inventorymanager.h index 35fcf4b99..c9570d2f0 100644 --- a/src/inventorymanager.h +++ b/src/inventorymanager.h @@ -254,7 +254,7 @@ struct ICraftAction : public InventoryAction }; // Crafting helper -bool getCraftingResult(Inventory *inv, ItemStack& result, +bool getCraftingResult(GameScripting *script_interface, Inventory *inv, ItemStack& result, std::vector &output_replacements, bool decrementInput, IGameDef *gamedef); diff --git a/src/mapblock.cpp b/src/mapblock.cpp index f8747f52b..465312bc4 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -61,7 +61,6 @@ static const char *modified_reason_strings[] = { "unknown", }; - /* MapBlock */ @@ -701,11 +700,11 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk) decompressZlib(is, oss); std::istringstream iss(oss.str(), std::ios_base::binary); if (version >= 23) - m_node_metadata.deSerialize(iss, m_gamedef->idef()); + m_node_metadata.deSerialize(iss, m_gamedef->idef(), getPosRelative()); else content_nodemeta_deserialize_legacy(iss, &m_node_metadata, &m_node_timers, - m_gamedef->idef()); + m_gamedef->idef(), getPosRelative()); } catch(SerializationError &e) { warningstream<<"MapBlock::deSerialize(): Ignoring an error" <<" while deserializing node metadata at (" @@ -880,7 +879,7 @@ void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk) std::istringstream iss(data, std::ios_base::binary); content_nodemeta_deserialize_legacy(iss, &m_node_metadata, &m_node_timers, - m_gamedef->idef()); + m_gamedef->idef(), getPosRelative()); } else { //std::string data = deSerializeLongString(is); std::ostringstream oss(std::ios_base::binary); @@ -888,7 +887,7 @@ void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk) std::istringstream iss(oss.str(), std::ios_base::binary); content_nodemeta_deserialize_legacy(iss, &m_node_metadata, &m_node_timers, - m_gamedef->idef()); + m_gamedef->idef(), getPosRelative()); } } catch(SerializationError &e) { warningstream<<"MapBlock::deSerialize(): Ignoring an error" diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 0498f4048..d0927702c 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -863,7 +863,8 @@ void Client::handleCommand_DetachedInventory(NetworkPacket* pkt) if (m_detached_inventories.count(name) > 0) inv = m_detached_inventories[name]; else { - inv = new Inventory(m_itemdef); + DetachedInventoryChangeReceiver * detached_inventory_change_receiver = new DetachedInventoryChangeReceiver(name); + inv = new Inventory(m_itemdef, detached_inventory_change_receiver); m_detached_inventories[name] = inv; } inv->deSerialize(is); diff --git a/src/nodemetadata.cpp b/src/nodemetadata.cpp index 126889ecf..8e6652d30 100644 --- a/src/nodemetadata.cpp +++ b/src/nodemetadata.cpp @@ -25,14 +25,16 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/serialize.h" #include "constants.h" // MAP_BLOCKSIZE #include +#include "script/scripting_game.h" /* NodeMetadata */ -NodeMetadata::NodeMetadata(IItemDefManager *item_def_mgr): +NodeMetadata::NodeMetadata(IItemDefManager *item_def_mgr, v3s16 node_pos): m_stringvars(), - m_inventory(new Inventory(item_def_mgr)) + m_inventory(new Inventory(item_def_mgr, this)), + m_node_pos(node_pos) { } @@ -41,6 +43,27 @@ NodeMetadata::~NodeMetadata() delete m_inventory; } +void NodeMetadata::on_remove_item(GameScripting *script_interface, const InventoryList *inventory_list, const ItemStack &deleted_item) +{ + if(script_interface){ + script_interface->on_nodemeta_inventory_remove_item(m_node_pos, inventory_list->getName(), deleted_item); + } +} + +void NodeMetadata::on_change_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &old_item,const ItemStack &new_item) +{ + if(script_interface){ + script_interface->on_nodemeta_inventory_change_item(m_node_pos, inventory_list->getName(), query_slot, old_item, new_item); + } +} + +void NodeMetadata::on_add_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &added_item) +{ + if(script_interface){ + script_interface->on_nodemeta_inventory_add_item(m_node_pos, inventory_list->getName(), query_slot, added_item); + } +} + void NodeMetadata::serialize(std::ostream &os) const { int num_vars = m_stringvars.size(); @@ -108,7 +131,7 @@ void NodeMetadataList::serialize(std::ostream &os) const } } -void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_mgr) +void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_mgr, v3s16 relative_map_block_pos) { clear(); @@ -146,7 +169,7 @@ void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_m continue; } - NodeMetadata *data = new NodeMetadata(item_def_mgr); + NodeMetadata *data = new NodeMetadata(item_def_mgr, relative_map_block_pos+p); data->deSerialize(is); m_data[p] = data; } diff --git a/src/nodemetadata.h b/src/nodemetadata.h index 8d1298212..1976aa58c 100644 --- a/src/nodemetadata.h +++ b/src/nodemetadata.h @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include "util/string.h" +#include "inventory.h" // For InventoryChangeReceiver class /* NodeMetadata stores arbitary amounts of data for special blocks. @@ -36,13 +37,18 @@ with this program; if not, write to the Free Software Foundation, Inc., class Inventory; class IItemDefManager; +class ScriptApiBase; -class NodeMetadata +class NodeMetadata: public InventoryChangeReceiver { public: - NodeMetadata(IItemDefManager *item_def_mgr); + NodeMetadata(IItemDefManager *item_def_mgr, v3s16 node_pos); ~NodeMetadata(); + void on_remove_item(GameScripting *script_interface, const InventoryList *inventory_list, const ItemStack &deleted_item); + void on_change_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &old_item,const ItemStack &new_item); + void on_add_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &added_item); + void serialize(std::ostream &os) const; void deSerialize(std::istream &is); @@ -67,6 +73,7 @@ public: private: StringMap m_stringvars; Inventory *m_inventory; + v3s16 m_node_pos; }; @@ -80,7 +87,7 @@ public: ~NodeMetadataList(); void serialize(std::ostream &os) const; - void deSerialize(std::istream &is, IItemDefManager *item_def_mgr); + void deSerialize(std::istream &is, IItemDefManager *item_def_mgr, v3s16 relative_map_block_pos); // Add all keys in this list to the vector keys std::vector getAllKeys(); diff --git a/src/player.cpp b/src/player.cpp index 5949712a5..50c55d744 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -30,6 +30,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "log.h" #include "porting.h" // strlcpy +#include "environment.h" // For calling 'getScriptIface()', because ServerEnvironment forward declared in 'serverobject.h'. +#include "script/scripting_game.h" // For calling API functions. Player::Player(IGameDef *gamedef, const char *name): @@ -41,7 +43,7 @@ Player::Player(IGameDef *gamedef, const char *name): is_climbing(false), swimming_vertical(false), camera_barely_in_ceiling(false), - inventory(gamedef->idef()), + inventory(gamedef->idef(), this), hp(PLAYER_MAX_HP), hurt_tilt_timer(0), hurt_tilt_strength(0), @@ -59,7 +61,6 @@ Player::Player(IGameDef *gamedef, const char *name): m_dirty(false) { strlcpy(m_name, name, PLAYERNAME_SIZE); - inventory.clear(); inventory.addList("main", PLAYER_INVENTORY_SIZE); InventoryList *craft = inventory.addList("craft", 9); @@ -112,6 +113,30 @@ Player::~Player() clearHud(); } +void Player::on_remove_item(GameScripting *script_interface, const InventoryList *inventory_list, const ItemStack &deleted_item) +{ + PlayerSAO *player_sao = this->getPlayerSAO(); + if(script_interface){ + script_interface->on_player_inventory_remove_item(player_sao, this, inventory_list->getName(), deleted_item); + } +} + +void Player::on_change_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &old_item,const ItemStack &new_item) +{ + PlayerSAO *player_sao = this->getPlayerSAO(); + if(script_interface){ + script_interface->on_player_inventory_change_item(player_sao, this, inventory_list->getName(), query_slot, old_item, new_item); + } +} + +void Player::on_add_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &added_item) +{ + PlayerSAO *player_sao = this->getPlayerSAO(); + if(script_interface){ + script_interface->on_player_inventory_add_item(player_sao, this, inventory_list->getName(), query_slot, added_item); + } +} + v3s16 Player::getLightPosition() const { return floatToInt(m_position + v3f(0,BS+BS/2,0), BS); @@ -176,7 +201,7 @@ void Player::deSerialize(std::istream &is, std::string playername) if(craftresult_is_preview) { // Clear craftresult - inventory.getList("craftresult")->changeItem(0, ItemStack()); + inventory.getList("craftresult")->changeItem(NULL, 0, ItemStack()); } } } diff --git a/src/player.h b/src/player.h index b317cda4f..e17ad0e5f 100644 --- a/src/player.h +++ b/src/player.h @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "inventory.h" #include "constants.h" // BS #include "threading/mutex.h" +//#include "script/scripting_game.h" // For GameScripting in callbacks #include #define PLAYERNAME_SIZE 20 @@ -92,15 +93,22 @@ struct CollisionInfo; class PlayerSAO; struct HudElement; class Environment; +class GameScripting; +class Inventory; // IMPORTANT: // Do *not* perform an assignment or copy operation on a Player or // RemotePlayer object! This will copy the lock held for HUD synchronization -class Player +class Player: public InventoryChangeReceiver { public: Player(IGameDef *gamedef, const char *name); + + void on_remove_item(GameScripting *script_interface, const InventoryList *inventory_list, const ItemStack &deleted_item); + void on_change_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &old_item,const ItemStack &new_item); + void on_add_item(GameScripting *script_interface, const InventoryList *inventory_list, u32 query_slot, const ItemStack &added_item); + virtual ~Player() = 0; virtual void move(f32 dtime, Environment *env, f32 pos_max_d) diff --git a/src/rollback_interface.cpp b/src/rollback_interface.cpp index bffe0a82c..9fb8d3020 100644 --- a/src/rollback_interface.cpp +++ b/src/rollback_interface.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/string.h" #include "util/numeric.h" #include "map.h" +#include "mapblock.h" //For getNodeBlockPos #include "gamedef.h" #include "nodedef.h" #include "nodemetadata.h" @@ -155,7 +156,9 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam } else { NodeMetadata *meta = map->getNodeMetadata(p); if (!meta) { - meta = new NodeMetadata(gamedef->idef()); + v3s16 blockpos = getNodeBlockPos(p); + v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE; + meta = new NodeMetadata(gamedef->idef(),p_rel); if (!map->setNodeMetadata(p, meta)) { delete meta; infostream << "RollbackAction::applyRevert(): " @@ -217,9 +220,9 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam // Silently ignore different current item if (list->getItem(inventory_index).name != real_name) return false; - list->takeItem(inventory_index, inventory_stack.count); + list->takeItem(NULL, inventory_index, inventory_stack.count); // No idea how to get GameScripting from this point. Therefore it is void here. } else { - list->addItem(inventory_index, inventory_stack); + list->addItem(NULL, inventory_index, inventory_stack); } // Inventory was modified; send to clients imgr->setInventoryModified(loc); diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 06e20c2a0..69357b116 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -902,11 +902,11 @@ void read_inventory_list(lua_State *L, int tableindex, i = items.begin(); i != items.end(); i++){ if(forcesize != -1 && index == forcesize) break; - invlist->changeItem(index, *i); + invlist->changeItem(NULL, index, *i); index++; } while(forcesize != -1 && index < forcesize){ - invlist->deleteItem(index); + invlist->deleteItem(NULL, index); index++; } } diff --git a/src/script/cpp_api/s_inventory.cpp b/src/script/cpp_api/s_inventory.cpp index c90c7d4e2..fddb7d8f9 100644 --- a/src/script/cpp_api/s_inventory.cpp +++ b/src/script/cpp_api/s_inventory.cpp @@ -202,6 +202,64 @@ void ScriptApiDetached::detached_inventory_OnTake( lua_pop(L, 1); // Pop error handler } + +void ScriptApiDetached::on_detached_inventory_remove_item( + const std::string &name, + const std::string &inventory_list_name, + const ItemStack &deleted_item) +{ + SCRIPTAPI_PRECHECKHEADER + + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_detached_inventory_remove_item"); + // Call callbacks + lua_pushstring(L, name.c_str());// name 1 + lua_pushstring(L, inventory_list_name.c_str());// listname 2 + LuaItemStack::create(L, deleted_item); // stack 3 + runCallbacks(3, RUN_CALLBACKS_MODE_LAST); +} + +void ScriptApiDetached::on_detached_inventory_change_item( + const std::string &name, + const std::string &inventory_list_name, + u32 query_slot, + const ItemStack &old_item, + const ItemStack &new_item) +{ + SCRIPTAPI_PRECHECKHEADER + + // Get core.registered_on_inventory_change_item + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_detached_inventory_change_item"); + // Call callbacks + lua_pushstring(L, name.c_str());// name 1 + lua_pushstring(L, inventory_list_name.c_str());// listname 2 + lua_pushnumber(L, query_slot);// slot 3 + LuaItemStack::create(L, old_item); // stack 4 + LuaItemStack::create(L, new_item); // stack 5 + runCallbacks(5, RUN_CALLBACKS_MODE_LAST); +} + +void ScriptApiDetached::on_detached_inventory_add_item( + const std::string &name, + const std::string &inventory_list_name, + u32 query_slot, + const ItemStack &added_item) +{ + SCRIPTAPI_PRECHECKHEADER + + // Get core.registered_on_inventory_add_item + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_detached_inventory_add_item"); + // Call callbacks + lua_pushstring(L, name.c_str());// name 1 + lua_pushstring(L, inventory_list_name.c_str());// listname 2 + lua_pushnumber(L, query_slot); + LuaItemStack::create(L, added_item); // stack 4 + runCallbacks(4, RUN_CALLBACKS_MODE_LAST); +} + + // Retrieves core.detached_inventories[name][callbackname] // If that is nil or on error, return false and stack is unchanged // If that is a function, returns true and pushes the diff --git a/src/script/cpp_api/s_inventory.h b/src/script/cpp_api/s_inventory.h index d1a81de80..0c55928a9 100644 --- a/src/script/cpp_api/s_inventory.h +++ b/src/script/cpp_api/s_inventory.h @@ -61,6 +61,25 @@ public: const std::string &name, const std::string &listname, int index, ItemStack &stack, ServerActiveObject *player); + + void on_detached_inventory_remove_item( + const std::string &name, + const std::string &inventory_list_name, + const ItemStack &deleted_item); + + void on_detached_inventory_change_item( + const std::string &name, + const std::string &inventory_list_name, + u32 query_slot, + const ItemStack &old_item, + const ItemStack &new_item); + + void on_detached_inventory_add_item( + const std::string &name, + const std::string &inventory_list_name, + u32 query_slot, + const ItemStack &added_item); + private: bool getDetachedInventoryCallback( const std::string &name, const char *callbackname); diff --git a/src/script/cpp_api/s_nodemeta.cpp b/src/script/cpp_api/s_nodemeta.cpp index d050c0bc9..04ecde14b 100644 --- a/src/script/cpp_api/s_nodemeta.cpp +++ b/src/script/cpp_api/s_nodemeta.cpp @@ -233,6 +233,63 @@ void ScriptApiNodemeta::nodemeta_inventory_OnTake(v3s16 p, lua_pop(L, 1); // Pop error handler } +void ScriptApiNodemeta::on_nodemeta_inventory_remove_item( + v3s16 p, + const std::string &inventory_list_name, + const ItemStack &deleted_item) +{ + SCRIPTAPI_PRECHECKHEADER + + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_nodemeta_inventory_remove_item"); + // Call callbacks + push_v3s16(L, p); // pos + lua_pushstring(L, inventory_list_name.c_str());// listname 2 + LuaItemStack::create(L, deleted_item); // stack 3 + runCallbacks(3, RUN_CALLBACKS_MODE_LAST); +} + +void ScriptApiNodemeta::on_nodemeta_inventory_change_item( + v3s16 p, + const std::string &inventory_list_name, + u32 query_slot, + const ItemStack &old_item, + const ItemStack &new_item) +{ + SCRIPTAPI_PRECHECKHEADER + + // Get core.registered_on_inventory_change_item + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_nodemeta_inventory_change_item"); + // Call callbacks + push_v3s16(L, p); // pos + lua_pushstring(L, inventory_list_name.c_str());// listname 2 + lua_pushnumber(L, query_slot);// slot 3 + LuaItemStack::create(L, old_item); // stack 4 + LuaItemStack::create(L, new_item); // stack 5 + runCallbacks(5, RUN_CALLBACKS_MODE_LAST); +} + +void ScriptApiNodemeta::on_nodemeta_inventory_add_item( + v3s16 p, + const std::string &inventory_list_name, + u32 query_slot, + const ItemStack &added_item) +{ + SCRIPTAPI_PRECHECKHEADER + + // Get core.registered_on_inventory_add_item + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_nodemeta_inventory_add_item"); + // Call callbacks + push_v3s16(L, p); // pos + lua_pushstring(L, inventory_list_name.c_str());// listname 2 + lua_pushnumber(L, query_slot); + LuaItemStack::create(L, added_item); // stack 4 + runCallbacks(4, RUN_CALLBACKS_MODE_LAST); +} + + ScriptApiNodemeta::ScriptApiNodemeta() { } diff --git a/src/script/cpp_api/s_nodemeta.h b/src/script/cpp_api/s_nodemeta.h index c2ebeba6d..6a55f4356 100644 --- a/src/script/cpp_api/s_nodemeta.h +++ b/src/script/cpp_api/s_nodemeta.h @@ -60,6 +60,25 @@ public: void nodemeta_inventory_OnTake(v3s16 p, const std::string &listname, int index, ItemStack &stack, ServerActiveObject *player); + + void on_nodemeta_inventory_remove_item( + v3s16 p, + const std::string &inventory_list_name, + const ItemStack &deleted_item); + + void on_nodemeta_inventory_change_item( + v3s16 p, + const std::string &inventory_list_name, + u32 query_slot, + const ItemStack &old_item, + const ItemStack &new_item); + + void on_nodemeta_inventory_add_item( + v3s16 p, + const std::string &inventory_list_name, + u32 query_slot, + const ItemStack &added_item); + private: }; diff --git a/src/script/cpp_api/s_player.cpp b/src/script/cpp_api/s_player.cpp index 807430678..c4d93d35b 100644 --- a/src/script/cpp_api/s_player.cpp +++ b/src/script/cpp_api/s_player.cpp @@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_converter.h" #include "common/c_content.h" #include "util/string.h" +#include "script/lua_api/l_inventory.h"// For InvRef. +#include "script/lua_api/l_item.h" // For LuaItemStack. void ScriptApiPlayer::on_newplayer(ServerActiveObject *player) { @@ -190,6 +192,70 @@ void ScriptApiPlayer::on_playerReceiveFields(ServerActiveObject *player, runCallbacks(3, RUN_CALLBACKS_MODE_OR_SC); } +void ScriptApiPlayer::on_player_inventory_remove_item( + ServerActiveObject *player_sao, + Player *player, + const std::string &inventory_list_name, + const ItemStack &deleted_item) +{ + SCRIPTAPI_PRECHECKHEADER + + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_player_inventory_remove_item"); + // Call callbacks + objectrefGetOrCreate(L, player_sao); // player 1 + InvRef::createPlayer(L, player);// InvRef from 2 + lua_pushstring(L, inventory_list_name.c_str());// listname 3 + LuaItemStack::create(L, deleted_item); // stack 4 + runCallbacks(4, RUN_CALLBACKS_MODE_LAST); +} + +void ScriptApiPlayer::on_player_inventory_change_item( + ServerActiveObject *player_sao, + Player *player, + const std::string &inventory_list_name, + u32 query_slot, + const ItemStack &old_item, + const ItemStack &new_item) +{ + SCRIPTAPI_PRECHECKHEADER + + // Get core.registered_on_inventory_change_item + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_player_inventory_change_item"); + // Call callbacks + objectrefGetOrCreate(L, player_sao); // player 1 + InvRef::createPlayer(L, player);// InvRef from 2 + lua_pushstring(L, inventory_list_name.c_str());// listname 3 + lua_pushnumber(L, query_slot);// slot 4 + LuaItemStack::create(L, old_item); // stack 5 + LuaItemStack::create(L, new_item); // stack 6 + runCallbacks(6, RUN_CALLBACKS_MODE_LAST); +} + +void ScriptApiPlayer::on_player_inventory_add_item( + ServerActiveObject *player_sao, + Player *player, + const std::string &inventory_list_name, + u32 query_slot, + const ItemStack &added_item) +{ + SCRIPTAPI_PRECHECKHEADER + + // Get core.registered_on_inventory_add_item + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_player_inventory_add_item"); + // Call callbacks + objectrefGetOrCreate(L, player_sao); // player 1 + InvRef::createPlayer(L, player);// InvRef from 2 + lua_pushstring(L, inventory_list_name.c_str());// listname 3 + lua_pushnumber(L, query_slot); + LuaItemStack::create(L, added_item); // stack 5 + runCallbacks(5, RUN_CALLBACKS_MODE_LAST); +} + + + ScriptApiPlayer::~ScriptApiPlayer() { } diff --git a/src/script/cpp_api/s_player.h b/src/script/cpp_api/s_player.h index 2e4dc2222..3a20c10e4 100644 --- a/src/script/cpp_api/s_player.h +++ b/src/script/cpp_api/s_player.h @@ -23,6 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_base.h" #include "irr_v3d.h" #include "util/string.h" +#include "inventory.h" // For InventoryList and ItemStack + +class Player; struct ToolCapabilities; @@ -46,6 +49,24 @@ public: s16 on_player_hpchange(ServerActiveObject *player, s16 hp_change); void on_playerReceiveFields(ServerActiveObject *player, const std::string &formname, const StringMap &fields); + void on_player_inventory_remove_item( + ServerActiveObject *player_sao, + Player *player, + const std::string &inventory_list_name, + const ItemStack &deleted_item); + void on_player_inventory_change_item( + ServerActiveObject *player_sao, + Player *player, + const std::string &inventory_list_name, + u32 query_slot, + const ItemStack &old_item, + const ItemStack &new_item); + void on_player_inventory_add_item( + ServerActiveObject *player_sao, + Player *player, + const std::string &inventory_list_name, + u32 query_slot, + const ItemStack &added_item); }; diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp index de9f9374a..f6509b719 100644 --- a/src/script/lua_api/l_inventory.cpp +++ b/src/script/lua_api/l_inventory.cpp @@ -197,7 +197,7 @@ int InvRef::l_set_stack(lua_State *L) ItemStack newitem = read_item(L, 4, getServer(L)); InventoryList *list = getlist(L, ref, listname); if(list != NULL && i >= 0 && i < (int) list->getSize()){ - list->changeItem(i, newitem); + list->changeItem(getServer(L)->getScriptIface(), i, newitem); reportInventoryChange(L, ref); lua_pushboolean(L, true); } else { @@ -298,7 +298,7 @@ int InvRef::l_add_item(lua_State *L) ItemStack item = read_item(L, 3, getServer(L)); InventoryList *list = getlist(L, ref, listname); if(list){ - ItemStack leftover = list->addItem(item); + ItemStack leftover = list->addItem(getServer(L)->getScriptIface(), item); if(leftover.count != item.count) reportInventoryChange(L, ref); LuaItemStack::create(L, leftover); @@ -352,7 +352,7 @@ int InvRef::l_remove_item(lua_State *L) ItemStack item = read_item(L, 3, getServer(L)); InventoryList *list = getlist(L, ref, listname); if(list){ - ItemStack removed = list->removeItem(item); + ItemStack removed = list->removeItem(getServer(L)->getScriptIface(), item); if(!removed.empty()) reportInventoryChange(L, ref); LuaItemStack::create(L, removed); diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp index c8bc7d558..f8e7fb654 100644 --- a/src/script/lua_api/l_nodemeta.cpp +++ b/src/script/lua_api/l_nodemeta.cpp @@ -44,7 +44,7 @@ NodeMetadata* NodeMetaRef::getmeta(NodeMetaRef *ref, bool auto_create) { NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p); if(meta == NULL && auto_create) { - meta = new NodeMetadata(ref->m_env->getGameDef()->idef()); + meta = new NodeMetadata(ref->m_env->getGameDef()->idef(), ref->m_p); if(!ref->m_env->getMap().setNodeMetadata(ref->m_p, meta)) { delete meta; return NULL; diff --git a/src/server.cpp b/src/server.cpp index 6c008a2a1..03359588b 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2731,14 +2731,14 @@ void Server::UpdateCrafting(Player* player) InventoryLocation loc; loc.setPlayer(player->getName()); std::vector output_replacements; - getCraftingResult(&player->inventory, preview, output_replacements, false, this); + getCraftingResult(getEnv().getScriptIface(), &player->inventory, preview, output_replacements, false, this); m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc); // Put the new preview in InventoryList *plist = player->inventory.getList("craftpreview"); sanity_check(plist); sanity_check(plist->getSize() >= 1); - plist->changeItem(0, preview); + plist->changeItem(NULL, 0, preview); } void Server::handleChatInterfaceEvent(ChatEvent *evt) @@ -3244,7 +3244,8 @@ Inventory* Server::createDetachedInventory(const std::string &name) } else { infostream<<"Server creating detached inventory \""<getList(getWieldList())) { - list->changeItem(getWieldIndex(), item); + list->changeItem(NULL, getWieldIndex(), item); return true; } } diff --git a/src/unittest/test_inventory.cpp b/src/unittest/test_inventory.cpp index 1a783afae..ddec7363b 100644 --- a/src/unittest/test_inventory.cpp +++ b/src/unittest/test_inventory.cpp @@ -48,7 +48,8 @@ void TestInventory::runTests(IGameDef *gamedef) void TestInventory::testSerializeDeserialize(IItemDefManager *idef) { - Inventory inv(idef); + DetachedInventoryChangeReceiver * detached_inventory_change_receiver = new DetachedInventoryChangeReceiver("test"); + Inventory inv(idef, detached_inventory_change_receiver); std::istringstream is(serialized_inventory, std::ios::binary); inv.deSerialize(is);