1
0
mirror of https://github.com/luanti-org/luanti.git synced 2025-10-20 11:35:21 +02:00

Entirely new version of pull request #3962

Changes to be committed:
	modified:   builtin/game/register.lua
	modified:   src/content_nodemeta.cpp
	modified:   src/content_nodemeta.h
	modified:   src/game.cpp
	modified:   src/inventory.cpp
	modified:   src/inventory.h
	modified:   src/inventorymanager.cpp
	modified:   src/inventorymanager.h
	modified:   src/mapblock.cpp
	modified:   src/network/clientpackethandler.cpp
	modified:   src/nodemetadata.cpp
	modified:   src/nodemetadata.h
	modified:   src/player.cpp
	modified:   src/player.h
	modified:   src/rollback_interface.cpp
	modified:   src/script/common/c_content.cpp
	modified:   src/script/cpp_api/s_inventory.cpp
	modified:   src/script/cpp_api/s_inventory.h
	modified:   src/script/cpp_api/s_nodemeta.cpp
	modified:   src/script/cpp_api/s_nodemeta.h
	modified:   src/script/cpp_api/s_player.cpp
	modified:   src/script/cpp_api/s_player.h
	modified:   src/script/lua_api/l_inventory.cpp
	modified:   src/script/lua_api/l_nodemeta.cpp
	modified:   src/server.cpp
	modified:   src/serverobject.cpp
	modified:   src/unittest/test_inventory.cpp
This commit is contained in:
Foghrye4
2016-04-18 21:33:28 +03:00
parent d82c5da0dc
commit b5dca28ca3
28 changed files with 509 additions and 125 deletions

3
.gitignore vendored
View File

@@ -85,3 +85,6 @@ build/android/path.cfg
build/android/and_env build/android/and_env
build/android/AndroidManifest.xml build/android/AndroidManifest.xml
timestamp timestamp
## Backup files
*backup.tar.gz

View File

@@ -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_protection_violation, core.register_on_protection_violation = make_registration()
core.registered_on_item_eats, core.register_on_item_eat = 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_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() -- Compatibility for on_mapgen_init()
-- --

View File

@@ -145,7 +145,7 @@ static bool content_nodemeta_deserialize_legacy_meta(
void content_nodemeta_deserialize_legacy(std::istream &is, void content_nodemeta_deserialize_legacy(std::istream &is,
NodeMetadataList *meta, NodeTimerList *timers, NodeMetadataList *meta, NodeTimerList *timers,
IItemDefManager *item_def_mgr) IItemDefManager *item_def_mgr, v3s16 relative_mapblock_pos)
{ {
meta->clear(); meta->clear();
timers->clear(); timers->clear();
@@ -181,7 +181,7 @@ void content_nodemeta_deserialize_legacy(std::istream &is,
continue; 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); bool need_timer = content_nodemeta_deserialize_legacy_meta(is, data);
meta->set(p, data); meta->set(p, data);

View File

@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define CONTENT_NODEMETA_HEADER #define CONTENT_NODEMETA_HEADER
#include <iostream> #include <iostream>
#include "irr_v3d.h" // For v3s16
class NodeMetadataList; class NodeMetadataList;
class NodeTimerList; class NodeTimerList;
@@ -32,7 +33,7 @@ class IItemDefManager;
void content_nodemeta_deserialize_legacy(std::istream &is, void content_nodemeta_deserialize_legacy(std::istream &is,
NodeMetadataList *meta, NodeTimerList *timers, 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); void content_nodemeta_serialize_legacy(std::ostream &os, NodeMetadataList *meta);

View File

@@ -2143,7 +2143,8 @@ bool Game::createClient(const std::string &playername,
sky = new Sky(smgr->getRootSceneNode(), smgr, -1, texture_src); sky = new Sky(smgr->getRootSceneNode(), smgr, -1, texture_src);
skybox = NULL; // This is used/set later on in the main run loop 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)) { if (!(sky && local_inventory)) {
*error_message = "Memory allocation error (sky or local inventory)"; *error_message = "Memory allocation error (sky or local inventory)";
@@ -2172,7 +2173,6 @@ bool Game::createClient(const std::string &playername,
str += L"]"; str += L"]";
device->setWindowCaption(str.c_str()); device->setWindowCaption(str.c_str());
LocalPlayer *player = client->getEnv().getLocalPlayer();
player->hurt_tilt_timer = 0; player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0; player->hurt_tilt_strength = 0;

View File

@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nameidmapping.h" // For loading legacy MaterialItems #include "nameidmapping.h" // For loading legacy MaterialItems
#include "util/serialize.h" #include "util/serialize.h"
#include "util/string.h" #include "util/string.h"
#include "script/scripting_game.h"
/* /*
ItemStack ItemStack
@@ -432,12 +433,13 @@ ItemStack ItemStack::peekItem(u32 peekcount) const
Inventory 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_name = name;
m_size = size; m_size = size;
m_width = 0; m_width = 0;
m_itemdef = itemdef; m_itemdef = itemdef;
m_rec=rec;
clearItems(); clearItems();
//m_dirty = false; //m_dirty = false;
} }
@@ -562,6 +564,7 @@ InventoryList & InventoryList::operator = (const InventoryList &other)
m_width = other.m_width; m_width = other.m_width;
m_name = other.m_name; m_name = other.m_name;
m_itemdef = other.m_itemdef; m_itemdef = other.m_itemdef;
m_rec = other.m_rec;
//setDirty(true); //setDirty(true);
return *this; return *this;
@@ -630,30 +633,31 @@ ItemStack& InventoryList::getItem(u32 i)
return m_items[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()) if(i >= m_items.size())
return newitem; return new_item;
ItemStack old_item = m_items[i];
ItemStack olditem = m_items[i]; m_items[i] = new_item;
m_items[i] = newitem; m_rec->on_change_item(script_interface, this, i, old_item, new_item);
//setDirty(true); //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 assert(i < m_items.size()); // Pre-condition
m_rec->on_remove_item(script_interface, this, m_items[i]);
m_items[i].clear(); m_items[i].clear();
} }
ItemStack InventoryList::addItem(const ItemStack &newitem_) ItemStack InventoryList::addItem(GameScripting *script_interface, const ItemStack &new_item_)
{ {
ItemStack newitem = newitem_; ItemStack new_item = new_item_;
if(newitem.empty())
return newitem;
if(new_item.empty()){
return new_item;
}
/* /*
First try to find if it could be added to some existing items 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()) if(m_items[i].empty())
continue; continue;
// Try adding // Try adding
newitem = addItem(i, newitem); new_item = addItem(script_interface, i, new_item);
if(newitem.empty()) if(new_item.empty())
return newitem; // All was eaten return new_item; // All was eaten
} }
/* /*
@@ -677,22 +681,28 @@ ItemStack InventoryList::addItem(const ItemStack &newitem_)
if(!m_items[i].empty()) if(!m_items[i].empty())
continue; continue;
// Try adding // Try adding
newitem = addItem(i, newitem); new_item = addItem(script_interface, i, new_item);
if(newitem.empty()) if(new_item.empty())
return newitem; // All was eaten return new_item; // All was eaten
} }
// Return leftover // 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()) if(i >= m_items.size())
return newitem; return new_item;
u16 count_before = 0;
ItemStack leftover = m_items[i].addItem(newitem, m_itemdef); count_before = new_item.count;
//if(leftover != newitem) 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); // setDirty(true);
return leftover; return leftover;
} }
@@ -745,7 +755,7 @@ bool InventoryList::containsItem(const ItemStack &item) const
return false; return false;
} }
ItemStack InventoryList::removeItem(const ItemStack &item) ItemStack InventoryList::removeItem(GameScripting *script_interface, const ItemStack &item)
{ {
ItemStack removed; ItemStack removed;
for(std::vector<ItemStack>::reverse_iterator for(std::vector<ItemStack>::reverse_iterator
@@ -760,10 +770,12 @@ ItemStack InventoryList::removeItem(const ItemStack &item)
break; break;
} }
} }
m_rec->on_remove_item(script_interface, this, removed);
return 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()) if(i >= m_items.size())
return ItemStack(); return ItemStack();
@@ -771,6 +783,7 @@ ItemStack InventoryList::takeItem(u32 i, u32 takecount)
ItemStack taken = m_items[i].takeItem(takecount); ItemStack taken = m_items[i].takeItem(takecount);
//if(!taken.empty()) //if(!taken.empty())
// setDirty(true); // setDirty(true);
m_rec->on_remove_item(script_interface, this, taken);
return taken; return taken;
} }
@@ -782,14 +795,14 @@ ItemStack InventoryList::peekItem(u32 i, u32 peekcount) const
return m_items[i].peekItem(peekcount); 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 // Take item from source list
ItemStack item1; ItemStack item1;
if (count == 0) if (count == 0)
item1 = changeItem(i, ItemStack()); item1 = changeItem(script_interface, i, ItemStack());
else else
item1 = takeItem(i, count); item1 = takeItem(script_interface, i, count);
if (item1.empty()) if (item1.empty())
return; return;
@@ -799,7 +812,7 @@ void InventoryList::moveItemSomewhere(u32 i, InventoryList *dest, u32 count)
// First try all the non-empty slots // First try all the non-empty slots
for (u32 dest_i = 0; dest_i < dest_size; dest_i++) { for (u32 dest_i = 0; dest_i < dest_size; dest_i++) {
if (!m_items[dest_i].empty()) { 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 (item1.empty()) return;
} }
} }
@@ -807,17 +820,17 @@ void InventoryList::moveItemSomewhere(u32 i, InventoryList *dest, u32 count)
// Then try all the empty ones // Then try all the empty ones
for (u32 dest_i = 0; dest_i < dest_size; dest_i++) { for (u32 dest_i = 0; dest_i < dest_size; dest_i++) {
if (m_items[dest_i].empty()) { 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 (item1.empty()) return;
} }
} }
// If we reach this, the item was not fully added // If we reach this, the item was not fully added
// Add the remaining part back to the source item // 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) u32 count, bool swap_if_needed, bool *did_swap)
{ {
if(this == dest && i == dest_i) 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 // Take item from source list
ItemStack item1; ItemStack item1;
if(count == 0) if(count == 0)
item1 = changeItem(i, ItemStack()); item1 = changeItem(script_interface, i, ItemStack());
else else
item1 = takeItem(i, count); item1 = takeItem(script_interface, i, count);
if(item1.empty()) if(item1.empty())
return 0; return 0;
// Try to add the item to destination list // Try to add the item to destination list
u32 oldcount = item1.count; 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 something is returned, the item was not fully added
if(!item1.empty()) 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. // If something else is returned, part of the item was left unadded.
// Add the other part back to the source item // Add the other part back to the source item
addItem(i, item1); addItem(script_interface, i, item1);
// If olditem is returned, nothing was added. // If olditem is returned, nothing was added.
// Swap the items // Swap the items
@@ -855,16 +868,51 @@ u32 InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i,
*did_swap = true; *did_swap = true;
} }
// Take item from source list // Take item from source list
item1 = changeItem(i, ItemStack()); item1 = changeItem(script_interface, i, ItemStack());
// Adding was not possible, swap the items. // 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 // Put item from destination list to the source list
changeItem(i, item2); changeItem(script_interface, i, item2);
} }
} }
return (oldcount - item1.count); 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 Inventory
*/ */
@@ -892,15 +940,16 @@ void Inventory::clearContents()
InventoryList *list = m_lists[i]; InventoryList *list = m_lists[i];
for(u32 j=0; j<list->getSize(); j++) for(u32 j=0; j<list->getSize(); j++)
{ {
list->deleteItem(j); list->deleteItem(NULL, j);
} }
} }
} }
Inventory::Inventory(IItemDefManager *itemdef) Inventory::Inventory(IItemDefManager *itemdef, InventoryChangeReceiver *rec)
{ {
m_dirty = false; m_dirty = false;
m_itemdef = itemdef; m_itemdef = itemdef;
m_rec = rec;
} }
Inventory::Inventory(const Inventory &other) Inventory::Inventory(const Inventory &other)
@@ -981,7 +1030,7 @@ void Inventory::deSerialize(std::istream &is)
std::getline(iss, listname, ' '); std::getline(iss, listname, ' ');
iss>>listsize; iss>>listsize;
InventoryList *list = new InventoryList(listname, listsize, m_itemdef); InventoryList *list = new InventoryList(listname, listsize, m_itemdef, m_rec);
list->deSerialize(is); list->deSerialize(is);
m_lists.push_back(list); m_lists.push_back(list);
@@ -1002,7 +1051,7 @@ InventoryList * Inventory::addList(const std::string &name, u32 size)
if(m_lists[i]->getSize() != size) if(m_lists[i]->getSize() != size)
{ {
delete m_lists[i]; 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]; return m_lists[i];
} }
@@ -1011,7 +1060,7 @@ InventoryList * Inventory::addList(const std::string &name, u32 size)
//don't create list with invalid name //don't create list with invalid name
if (name.find(" ") != std::string::npos) return NULL; 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); m_lists.push_back(list);
return list; return list;
} }

View File

@@ -27,8 +27,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <ostream> #include <ostream>
#include <string> #include <string>
#include <vector> #include <vector>
#include "cpp_api/s_base.h" // For ScriptApiBase
struct ToolCapabilities; class InventoryChangeReceiver;
class GameScripting;
struct ItemStack struct ItemStack
{ {
@@ -173,7 +175,7 @@ struct ItemStack
class InventoryList class InventoryList
{ {
public: public:
InventoryList(std::string name, u32 size, IItemDefManager *itemdef); InventoryList(std::string name, u32 size, IItemDefManager *itemdef, InventoryChangeReceiver *rec);
~InventoryList(); ~InventoryList();
void clearItems(); void clearItems();
void setSize(u32 newsize); void setSize(u32 newsize);
@@ -201,18 +203,18 @@ public:
const ItemStack& getItem(u32 i) const; const ItemStack& getItem(u32 i) const;
ItemStack& getItem(u32 i); ItemStack& getItem(u32 i);
// Returns old item. Parameter can be an empty item. // 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 // 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). // 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 possible, adds item to given slot.
// If cannot be added at all, returns the item back. // If cannot be added at all, returns the item back.
// If can be added partly, decremented item is returned back. // If can be added partly, decremented item is returned back.
// If can be added fully, empty item is returned. // 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 // Checks whether the item could be added to the given slot
// If restitem is non-NULL, it receives the part of newitem that // 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 // If not as many items exist as requested, removes as
// many as possible. // many as possible.
// Returns the items that were actually removed. // 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. // Takes some items from a slot.
// If there are not enough, takes as many as it can. // If there are not enough, takes as many as it can.
// Returns empty item if couldn't take any. // 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. // Similar to takeItem, but keeps the slot intact.
ItemStack peekItem(u32 i, u32 peekcount) const; 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) // 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) // count is the maximum number of items to move (0 for everything)
// returns number of moved items // 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); u32 count = 0, bool swap_if_needed = true, bool *did_swap = NULL);
// like moveItem, but without a fixed destination index // like moveItem, but without a fixed destination index
// also with optional rollback recording // 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: private:
std::vector<ItemStack> m_items; std::vector<ItemStack> m_items;
u32 m_size, m_width; u32 m_size, m_width;
std::string m_name; std::string m_name;
IItemDefManager *m_itemdef; 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 class Inventory
@@ -267,7 +290,7 @@ public:
void clear(); void clear();
void clearContents(); void clearContents();
Inventory(IItemDefManager *itemdef); Inventory(IItemDefManager *itemdef, InventoryChangeReceiver *m_rec);
Inventory(const Inventory &other); Inventory(const Inventory &other);
Inventory & operator = (const Inventory &other); Inventory & operator = (const Inventory &other);
bool operator == (const Inventory &other) const; bool operator == (const Inventory &other) const;
@@ -284,15 +307,6 @@ public:
const InventoryList * getList(const std::string &name) const; const InventoryList * getList(const std::string &name) const;
std::vector<const InventoryList*> getLists(); std::vector<const InventoryList*> getLists();
bool deleteList(const std::string &name); 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 bool checkModified() const
{ {
@@ -309,6 +323,7 @@ private:
const s32 getListIndex(const std::string &name) const; const s32 getListIndex(const std::string &name) const;
std::vector<InventoryList*> m_lists; std::vector<InventoryList*> m_lists;
InventoryChangeReceiver *m_rec;
IItemDefManager *m_itemdef; IItemDefManager *m_itemdef;
bool m_dirty; bool m_dirty;
}; };

View File

@@ -376,7 +376,7 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
same as source), nothing happens same as source), nothing happens
*/ */
bool did_swap = false; 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); list_to, to_i, count, !caused_by_move_somewhere, &did_swap);
// If source is infinite, reset it's stack // 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) { if (from_stack_was.name != to_stack_was.name) {
for (u32 i = 0; i < list_to->getSize(); i++) { for (u32 i = 0; i < list_to->getSize(); i++) {
if (list_to->getItem(i).empty()) { 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; break;
} }
} }
} }
} }
if (move_count > 0 || did_swap) { if (move_count > 0 || did_swap) {
list_from->deleteItem(from_i); list_from->deleteItem(PLAYER_TO_SA(player), from_i);
list_from->addItem(from_i, from_stack_was); 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 destination is infinite, reset it's stack and take count from source
if(dst_can_put_count == -1){ if(dst_can_put_count == -1){
list_to->deleteItem(to_i); list_to->deleteItem(PLAYER_TO_SA(player), to_i);
list_to->addItem(to_i, to_stack_was); list_to->addItem(PLAYER_TO_SA(player), to_i, to_stack_was);
list_from->deleteItem(from_i); list_from->deleteItem(PLAYER_TO_SA(player), from_i);
list_from->addItem(from_i, from_stack_was); list_from->addItem(PLAYER_TO_SA(player), from_i, from_stack_was);
list_from->takeItem(from_i, count); list_from->takeItem(PLAYER_TO_SA(player), from_i, count);
} }
infostream << "IMoveAction::apply(): moved" infostream << "IMoveAction::apply(): moved"
@@ -550,9 +550,9 @@ void IMoveAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
return; return;
if (!move_somewhere) 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 else
list_from->moveItemSomewhere(from_i, list_to, count); list_from->moveItemSomewhere(NULL, from_i, list_to, count);
mgr->setInventoryModified(from_inv); mgr->setInventoryModified(from_inv);
if(inv_from != inv_to) if(inv_from != inv_to)
@@ -663,7 +663,7 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
// If source isn't infinite // If source isn't infinite
if(src_can_take_count != -1){ if(src_can_take_count != -1){
// Take item from source list // 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) if(item2.count != actually_dropped_count)
errorstream<<"Could not take dropped count of items"<<std::endl; errorstream<<"Could not take dropped count of items"<<std::endl;
@@ -741,9 +741,9 @@ void IDropAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
return; return;
if(count == 0) if(count == 0)
list_from->changeItem(from_i, ItemStack()); list_from->changeItem(NULL, from_i, ItemStack());
else else
list_from->takeItem(from_i, count); list_from->takeItem(NULL, from_i, count);
mgr->setInventoryModified(from_inv); mgr->setInventoryModified(from_inv);
} }
@@ -801,7 +801,7 @@ void ICraftAction::apply(InventoryManager *mgr,
ItemStack craftresultitem; ItemStack craftresultitem;
int count_remaining = count; int count_remaining = count;
std::vector<ItemStack> output_replacements; std::vector<ItemStack> 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); PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv);
bool found = !crafted.empty(); bool found = !crafted.empty();
@@ -810,9 +810,9 @@ void ICraftAction::apply(InventoryManager *mgr,
std::vector<ItemStack> temp; std::vector<ItemStack> temp;
// Decrement input and add crafting output // 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); 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); mgr->setInventoryModified(craft_inv);
// Add the new replacements to the list // Add the new replacements to the list
@@ -842,7 +842,7 @@ void ICraftAction::apply(InventoryManager *mgr,
count_remaining--; count_remaining--;
// Get next crafting result // 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); PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv);
found = !crafted.empty(); found = !crafted.empty();
} }
@@ -852,7 +852,7 @@ void ICraftAction::apply(InventoryManager *mgr,
for (std::vector<ItemStack>::iterator it = output_replacements.begin(); for (std::vector<ItemStack>::iterator it = output_replacements.begin();
it != output_replacements.end(); ++it) { it != output_replacements.end(); ++it) {
if (list_main) if (list_main)
*it = list_main->addItem(*it); *it = list_main->addItem(PLAYER_TO_SA(player), *it);
if (it->empty()) if (it->empty())
continue; continue;
u16 count = it->count; u16 count = it->count;
@@ -882,7 +882,7 @@ void ICraftAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
// Crafting helper // Crafting helper
bool getCraftingResult(Inventory *inv, ItemStack& result, bool getCraftingResult(GameScripting *script_interface, Inventory *inv, ItemStack& result,
std::vector<ItemStack> &output_replacements, std::vector<ItemStack> &output_replacements,
bool decrementInput, IGameDef *gamedef) bool decrementInput, IGameDef *gamedef)
{ {
@@ -914,7 +914,7 @@ bool getCraftingResult(Inventory *inv, ItemStack& result,
// CraftInput has been changed, apply changes in clist // CraftInput has been changed, apply changes in clist
for(u16 i=0; i<clist->getSize(); i++) for(u16 i=0; i<clist->getSize(); i++)
{ {
clist->changeItem(i, ci.items[i]); clist->changeItem(script_interface, i, ci.items[i]);
} }
} }

View File

@@ -254,7 +254,7 @@ struct ICraftAction : public InventoryAction
}; };
// Crafting helper // Crafting helper
bool getCraftingResult(Inventory *inv, ItemStack& result, bool getCraftingResult(GameScripting *script_interface, Inventory *inv, ItemStack& result,
std::vector<ItemStack> &output_replacements, std::vector<ItemStack> &output_replacements,
bool decrementInput, IGameDef *gamedef); bool decrementInput, IGameDef *gamedef);

View File

@@ -61,7 +61,6 @@ static const char *modified_reason_strings[] = {
"unknown", "unknown",
}; };
/* /*
MapBlock MapBlock
*/ */
@@ -701,11 +700,11 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
decompressZlib(is, oss); decompressZlib(is, oss);
std::istringstream iss(oss.str(), std::ios_base::binary); std::istringstream iss(oss.str(), std::ios_base::binary);
if (version >= 23) if (version >= 23)
m_node_metadata.deSerialize(iss, m_gamedef->idef()); m_node_metadata.deSerialize(iss, m_gamedef->idef(), getPosRelative());
else else
content_nodemeta_deserialize_legacy(iss, content_nodemeta_deserialize_legacy(iss,
&m_node_metadata, &m_node_timers, &m_node_metadata, &m_node_timers,
m_gamedef->idef()); m_gamedef->idef(), getPosRelative());
} catch(SerializationError &e) { } catch(SerializationError &e) {
warningstream<<"MapBlock::deSerialize(): Ignoring an error" warningstream<<"MapBlock::deSerialize(): Ignoring an error"
<<" while deserializing node metadata at (" <<" 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); std::istringstream iss(data, std::ios_base::binary);
content_nodemeta_deserialize_legacy(iss, content_nodemeta_deserialize_legacy(iss,
&m_node_metadata, &m_node_timers, &m_node_metadata, &m_node_timers,
m_gamedef->idef()); m_gamedef->idef(), getPosRelative());
} else { } else {
//std::string data = deSerializeLongString(is); //std::string data = deSerializeLongString(is);
std::ostringstream oss(std::ios_base::binary); 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); std::istringstream iss(oss.str(), std::ios_base::binary);
content_nodemeta_deserialize_legacy(iss, content_nodemeta_deserialize_legacy(iss,
&m_node_metadata, &m_node_timers, &m_node_metadata, &m_node_timers,
m_gamedef->idef()); m_gamedef->idef(), getPosRelative());
} }
} catch(SerializationError &e) { } catch(SerializationError &e) {
warningstream<<"MapBlock::deSerialize(): Ignoring an error" warningstream<<"MapBlock::deSerialize(): Ignoring an error"

View File

@@ -863,7 +863,8 @@ void Client::handleCommand_DetachedInventory(NetworkPacket* pkt)
if (m_detached_inventories.count(name) > 0) if (m_detached_inventories.count(name) > 0)
inv = m_detached_inventories[name]; inv = m_detached_inventories[name];
else { 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; m_detached_inventories[name] = inv;
} }
inv->deSerialize(is); inv->deSerialize(is);

View File

@@ -25,14 +25,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/serialize.h" #include "util/serialize.h"
#include "constants.h" // MAP_BLOCKSIZE #include "constants.h" // MAP_BLOCKSIZE
#include <sstream> #include <sstream>
#include "script/scripting_game.h"
/* /*
NodeMetadata NodeMetadata
*/ */
NodeMetadata::NodeMetadata(IItemDefManager *item_def_mgr): NodeMetadata::NodeMetadata(IItemDefManager *item_def_mgr, v3s16 node_pos):
m_stringvars(), 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; 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 void NodeMetadata::serialize(std::ostream &os) const
{ {
int num_vars = m_stringvars.size(); 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(); clear();
@@ -146,7 +169,7 @@ void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_m
continue; continue;
} }
NodeMetadata *data = new NodeMetadata(item_def_mgr); NodeMetadata *data = new NodeMetadata(item_def_mgr, relative_map_block_pos+p);
data->deSerialize(is); data->deSerialize(is);
m_data[p] = data; m_data[p] = data;
} }

View File

@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include "util/string.h" #include "util/string.h"
#include "inventory.h" // For InventoryChangeReceiver class
/* /*
NodeMetadata stores arbitary amounts of data for special blocks. 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 Inventory;
class IItemDefManager; class IItemDefManager;
class ScriptApiBase;
class NodeMetadata class NodeMetadata: public InventoryChangeReceiver
{ {
public: public:
NodeMetadata(IItemDefManager *item_def_mgr); NodeMetadata(IItemDefManager *item_def_mgr, v3s16 node_pos);
~NodeMetadata(); ~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 serialize(std::ostream &os) const;
void deSerialize(std::istream &is); void deSerialize(std::istream &is);
@@ -67,6 +73,7 @@ public:
private: private:
StringMap m_stringvars; StringMap m_stringvars;
Inventory *m_inventory; Inventory *m_inventory;
v3s16 m_node_pos;
}; };
@@ -80,7 +87,7 @@ public:
~NodeMetadataList(); ~NodeMetadataList();
void serialize(std::ostream &os) const; 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 // Add all keys in this list to the vector keys
std::vector<v3s16> getAllKeys(); std::vector<v3s16> getAllKeys();

View File

@@ -30,6 +30,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h" #include "filesys.h"
#include "log.h" #include "log.h"
#include "porting.h" // strlcpy #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): Player::Player(IGameDef *gamedef, const char *name):
@@ -41,7 +43,7 @@ Player::Player(IGameDef *gamedef, const char *name):
is_climbing(false), is_climbing(false),
swimming_vertical(false), swimming_vertical(false),
camera_barely_in_ceiling(false), camera_barely_in_ceiling(false),
inventory(gamedef->idef()), inventory(gamedef->idef(), this),
hp(PLAYER_MAX_HP), hp(PLAYER_MAX_HP),
hurt_tilt_timer(0), hurt_tilt_timer(0),
hurt_tilt_strength(0), hurt_tilt_strength(0),
@@ -59,7 +61,6 @@ Player::Player(IGameDef *gamedef, const char *name):
m_dirty(false) m_dirty(false)
{ {
strlcpy(m_name, name, PLAYERNAME_SIZE); strlcpy(m_name, name, PLAYERNAME_SIZE);
inventory.clear(); inventory.clear();
inventory.addList("main", PLAYER_INVENTORY_SIZE); inventory.addList("main", PLAYER_INVENTORY_SIZE);
InventoryList *craft = inventory.addList("craft", 9); InventoryList *craft = inventory.addList("craft", 9);
@@ -112,6 +113,30 @@ Player::~Player()
clearHud(); 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 v3s16 Player::getLightPosition() const
{ {
return floatToInt(m_position + v3f(0,BS+BS/2,0), BS); 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) if(craftresult_is_preview)
{ {
// Clear craftresult // Clear craftresult
inventory.getList("craftresult")->changeItem(0, ItemStack()); inventory.getList("craftresult")->changeItem(NULL, 0, ItemStack());
} }
} }
} }

View File

@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventory.h" #include "inventory.h"
#include "constants.h" // BS #include "constants.h" // BS
#include "threading/mutex.h" #include "threading/mutex.h"
//#include "script/scripting_game.h" // For GameScripting in callbacks
#include <list> #include <list>
#define PLAYERNAME_SIZE 20 #define PLAYERNAME_SIZE 20
@@ -92,15 +93,22 @@ struct CollisionInfo;
class PlayerSAO; class PlayerSAO;
struct HudElement; struct HudElement;
class Environment; class Environment;
class GameScripting;
class Inventory;
// IMPORTANT: // IMPORTANT:
// Do *not* perform an assignment or copy operation on a Player or // Do *not* perform an assignment or copy operation on a Player or
// RemotePlayer object! This will copy the lock held for HUD synchronization // RemotePlayer object! This will copy the lock held for HUD synchronization
class Player class Player: public InventoryChangeReceiver
{ {
public: public:
Player(IGameDef *gamedef, const char *name); 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 ~Player() = 0;
virtual void move(f32 dtime, Environment *env, f32 pos_max_d) virtual void move(f32 dtime, Environment *env, f32 pos_max_d)

View File

@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h" #include "util/string.h"
#include "util/numeric.h" #include "util/numeric.h"
#include "map.h" #include "map.h"
#include "mapblock.h" //For getNodeBlockPos
#include "gamedef.h" #include "gamedef.h"
#include "nodedef.h" #include "nodedef.h"
#include "nodemetadata.h" #include "nodemetadata.h"
@@ -155,7 +156,9 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam
} else { } else {
NodeMetadata *meta = map->getNodeMetadata(p); NodeMetadata *meta = map->getNodeMetadata(p);
if (!meta) { 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)) { if (!map->setNodeMetadata(p, meta)) {
delete meta; delete meta;
infostream << "RollbackAction::applyRevert(): " infostream << "RollbackAction::applyRevert(): "
@@ -217,9 +220,9 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam
// Silently ignore different current item // Silently ignore different current item
if (list->getItem(inventory_index).name != real_name) if (list->getItem(inventory_index).name != real_name)
return false; 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 { } else {
list->addItem(inventory_index, inventory_stack); list->addItem(NULL, inventory_index, inventory_stack);
} }
// Inventory was modified; send to clients // Inventory was modified; send to clients
imgr->setInventoryModified(loc); imgr->setInventoryModified(loc);

View File

@@ -902,11 +902,11 @@ void read_inventory_list(lua_State *L, int tableindex,
i = items.begin(); i != items.end(); i++){ i = items.begin(); i != items.end(); i++){
if(forcesize != -1 && index == forcesize) if(forcesize != -1 && index == forcesize)
break; break;
invlist->changeItem(index, *i); invlist->changeItem(NULL, index, *i);
index++; index++;
} }
while(forcesize != -1 && index < forcesize){ while(forcesize != -1 && index < forcesize){
invlist->deleteItem(index); invlist->deleteItem(NULL, index);
index++; index++;
} }
} }

View File

@@ -202,6 +202,64 @@ void ScriptApiDetached::detached_inventory_OnTake(
lua_pop(L, 1); // Pop error handler 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] // Retrieves core.detached_inventories[name][callbackname]
// If that is nil or on error, return false and stack is unchanged // If that is nil or on error, return false and stack is unchanged
// If that is a function, returns true and pushes the // If that is a function, returns true and pushes the

View File

@@ -61,6 +61,25 @@ public:
const std::string &name, const std::string &name,
const std::string &listname, int index, ItemStack &stack, const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player); 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: private:
bool getDetachedInventoryCallback( bool getDetachedInventoryCallback(
const std::string &name, const char *callbackname); const std::string &name, const char *callbackname);

View File

@@ -233,6 +233,63 @@ void ScriptApiNodemeta::nodemeta_inventory_OnTake(v3s16 p,
lua_pop(L, 1); // Pop error handler 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() ScriptApiNodemeta::ScriptApiNodemeta()
{ {
} }

View File

@@ -60,6 +60,25 @@ public:
void nodemeta_inventory_OnTake(v3s16 p, void nodemeta_inventory_OnTake(v3s16 p,
const std::string &listname, int index, ItemStack &stack, const std::string &listname, int index, ItemStack &stack,
ServerActiveObject *player); 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: private:
}; };

View File

@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_converter.h" #include "common/c_converter.h"
#include "common/c_content.h" #include "common/c_content.h"
#include "util/string.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) void ScriptApiPlayer::on_newplayer(ServerActiveObject *player)
{ {
@@ -190,6 +192,70 @@ void ScriptApiPlayer::on_playerReceiveFields(ServerActiveObject *player,
runCallbacks(3, RUN_CALLBACKS_MODE_OR_SC); 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() ScriptApiPlayer::~ScriptApiPlayer()
{ {
} }

View File

@@ -23,6 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_base.h" #include "cpp_api/s_base.h"
#include "irr_v3d.h" #include "irr_v3d.h"
#include "util/string.h" #include "util/string.h"
#include "inventory.h" // For InventoryList and ItemStack
class Player;
struct ToolCapabilities; struct ToolCapabilities;
@@ -46,6 +49,24 @@ public:
s16 on_player_hpchange(ServerActiveObject *player, s16 hp_change); s16 on_player_hpchange(ServerActiveObject *player, s16 hp_change);
void on_playerReceiveFields(ServerActiveObject *player, void on_playerReceiveFields(ServerActiveObject *player,
const std::string &formname, const StringMap &fields); 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);
}; };

View File

@@ -197,7 +197,7 @@ int InvRef::l_set_stack(lua_State *L)
ItemStack newitem = read_item(L, 4, getServer(L)); ItemStack newitem = read_item(L, 4, getServer(L));
InventoryList *list = getlist(L, ref, listname); InventoryList *list = getlist(L, ref, listname);
if(list != NULL && i >= 0 && i < (int) list->getSize()){ if(list != NULL && i >= 0 && i < (int) list->getSize()){
list->changeItem(i, newitem); list->changeItem(getServer(L)->getScriptIface(), i, newitem);
reportInventoryChange(L, ref); reportInventoryChange(L, ref);
lua_pushboolean(L, true); lua_pushboolean(L, true);
} else { } else {
@@ -298,7 +298,7 @@ int InvRef::l_add_item(lua_State *L)
ItemStack item = read_item(L, 3, getServer(L)); ItemStack item = read_item(L, 3, getServer(L));
InventoryList *list = getlist(L, ref, listname); InventoryList *list = getlist(L, ref, listname);
if(list){ if(list){
ItemStack leftover = list->addItem(item); ItemStack leftover = list->addItem(getServer(L)->getScriptIface(), item);
if(leftover.count != item.count) if(leftover.count != item.count)
reportInventoryChange(L, ref); reportInventoryChange(L, ref);
LuaItemStack::create(L, leftover); LuaItemStack::create(L, leftover);
@@ -352,7 +352,7 @@ int InvRef::l_remove_item(lua_State *L)
ItemStack item = read_item(L, 3, getServer(L)); ItemStack item = read_item(L, 3, getServer(L));
InventoryList *list = getlist(L, ref, listname); InventoryList *list = getlist(L, ref, listname);
if(list){ if(list){
ItemStack removed = list->removeItem(item); ItemStack removed = list->removeItem(getServer(L)->getScriptIface(), item);
if(!removed.empty()) if(!removed.empty())
reportInventoryChange(L, ref); reportInventoryChange(L, ref);
LuaItemStack::create(L, removed); LuaItemStack::create(L, removed);

View File

@@ -44,7 +44,7 @@ NodeMetadata* NodeMetaRef::getmeta(NodeMetaRef *ref, bool auto_create)
{ {
NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p); NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p);
if(meta == NULL && auto_create) { 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)) { if(!ref->m_env->getMap().setNodeMetadata(ref->m_p, meta)) {
delete meta; delete meta;
return NULL; return NULL;

View File

@@ -2731,14 +2731,14 @@ void Server::UpdateCrafting(Player* player)
InventoryLocation loc; InventoryLocation loc;
loc.setPlayer(player->getName()); loc.setPlayer(player->getName());
std::vector<ItemStack> output_replacements; std::vector<ItemStack> 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); m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
// Put the new preview in // Put the new preview in
InventoryList *plist = player->inventory.getList("craftpreview"); InventoryList *plist = player->inventory.getList("craftpreview");
sanity_check(plist); sanity_check(plist);
sanity_check(plist->getSize() >= 1); sanity_check(plist->getSize() >= 1);
plist->changeItem(0, preview); plist->changeItem(NULL, 0, preview);
} }
void Server::handleChatInterfaceEvent(ChatEvent *evt) void Server::handleChatInterfaceEvent(ChatEvent *evt)
@@ -3244,7 +3244,8 @@ Inventory* Server::createDetachedInventory(const std::string &name)
} else { } else {
infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl; infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
} }
Inventory *inv = new Inventory(m_itemdef); DetachedInventoryChangeReceiver * detached_inventory_change_reciever = new DetachedInventoryChangeReceiver(name);
Inventory *inv = new Inventory(m_itemdef, detached_inventory_change_reciever);
sanity_check(inv); sanity_check(inv);
m_detached_inventories[name] = inv; m_detached_inventories[name] = inv;
//TODO find a better way to do this //TODO find a better way to do this

View File

@@ -92,7 +92,7 @@ bool ServerActiveObject::setWieldedItem(const ItemStack &item)
{ {
if(Inventory *inv = getInventory()) { if(Inventory *inv = getInventory()) {
if (InventoryList *list = inv->getList(getWieldList())) { if (InventoryList *list = inv->getList(getWieldList())) {
list->changeItem(getWieldIndex(), item); list->changeItem(NULL, getWieldIndex(), item);
return true; return true;
} }
} }

View File

@@ -48,7 +48,8 @@ void TestInventory::runTests(IGameDef *gamedef)
void TestInventory::testSerializeDeserialize(IItemDefManager *idef) 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); std::istringstream is(serialized_inventory, std::ios::binary);
inv.deSerialize(is); inv.deSerialize(is);