From 103173fc9b4fcb4c0fded2a93d5cbb8f0bea896e Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 6 Dec 2011 15:21:56 +0200 Subject: [PATCH] Add InvRef and InvStack (currently untested and unusable) --- src/CMakeLists.txt | 1 + src/client.cpp | 29 +++ src/client.h | 5 +- src/craftdef.cpp | 1 + src/guiInventoryMenu.cpp | 1 + src/guiInventoryMenu.h | 2 + src/inventory.cpp | 471 ++------------------------------- src/inventory.h | 178 +------------ src/inventorymanager.cpp | 544 +++++++++++++++++++++++++++++++++++++++ src/inventorymanager.h | 228 ++++++++++++++++ src/scriptapi.cpp | 519 ++++++++++++++++++++++++++++++------- src/server.cpp | 88 +++++-- src/server.h | 5 +- 13 files changed, 1328 insertions(+), 744 deletions(-) create mode 100644 src/inventorymanager.cpp create mode 100644 src/inventorymanager.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2088c8b79..3b3b326c4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -94,6 +94,7 @@ configure_file( ) set(common_SRCS + inventorymanager.cpp mods.cpp serverremoteplayer.cpp content_abm.cpp diff --git a/src/client.cpp b/src/client.cpp index d092c6a10..cfdc713db 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1782,6 +1782,34 @@ InventoryContext *Client::getInventoryContext() return &m_inventory_context; } +Inventory* Client::getInventory(const InventoryLocation &loc) +{ + switch(loc.type){ + case InventoryLocation::UNDEFINED: + {} + break; + case InventoryLocation::PLAYER: + { + Player *player = m_env.getPlayer(loc.name.c_str()); + if(!player) + return NULL; + return &player->inventory; + } + break; + case InventoryLocation::NODEMETA: + { + NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p); + if(!meta) + return NULL; + return meta->getInventory(); + } + break; + default: + assert(0); + } + return NULL; +} +#if 0 Inventory* Client::getInventory(InventoryContext *c, std::string id) { if(id == "current_player") @@ -1810,6 +1838,7 @@ Inventory* Client::getInventory(InventoryContext *c, std::string id) infostream<<__FUNCTION_NAME<<": unknown id "< #include #include "log.h" +#include "inventorymanager.h" void drawInventoryItem(video::IVideoDriver *driver, gui::IGUIFont *font, diff --git a/src/guiInventoryMenu.h b/src/guiInventoryMenu.h index c8fe0d068..359268687 100644 --- a/src/guiInventoryMenu.h +++ b/src/guiInventoryMenu.h @@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "modalMenu.h" class ITextureSource; +class InventoryContext; +class InventoryManager; void drawInventoryItem(video::IVideoDriver *driver, gui::IGUIFont *font, diff --git a/src/inventory.cpp b/src/inventory.cpp index dd2713ca9..0d38bed78 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -37,7 +37,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "scriptapi.h" #include "strfnd.h" #include "nameidmapping.h" // For loading legacy MaterialItems -#include "serverremoteplayer.h" /* InventoryItem @@ -567,6 +566,22 @@ void InventoryList::clearItems() //setDirty(true); } +void InventoryList::setSize(u32 newsize) +{ + if(newsize < m_items.size()){ + for(u32 i=newsize; icurrent_player == NULL) - return "current_player=NULL"; - else - return std::string("current_player=") + c->current_player->getName(); -} - -IMoveAction::IMoveAction(std::istream &is) -{ - std::string ts; - - std::getline(is, ts, ' '); - count = stoi(ts); - - std::getline(is, from_inv, ' '); - - std::getline(is, from_list, ' '); - - std::getline(is, ts, ' '); - from_i = stoi(ts); - - std::getline(is, to_inv, ' '); - - std::getline(is, to_list, ' '); - - std::getline(is, ts, ' '); - to_i = stoi(ts); -} - -void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr, - ServerEnvironment *env) -{ - Inventory *inv_from = mgr->getInventory(c, from_inv); - Inventory *inv_to = mgr->getInventory(c, to_inv); - - if(!inv_from){ - infostream<<"IMoveAction::apply(): FAIL: source inventory not found: " - <<"context=["<getList(from_list); - InventoryList *list_to = inv_to->getList(to_list); - - /* - If a list doesn't exist or the source item doesn't exist - */ - if(!list_from){ - infostream<<"IMoveAction::apply(): FAIL: source list not found: " - <<"context=["<getItem(from_i) == NULL) - { - infostream<<"IMoveAction::apply(): FAIL: source item not found: " - <<"context=["<( - static_cast( - c->current_player - )); - - Inventory *inv_from = mgr->getInventory(c, from_inv); - - if(!inv_from){ - infostream<<"IDropAction::apply(): FAIL: source inventory not found: " - <<"context=["<getList(from_list); - - /* - If a list doesn't exist or the source item doesn't exist - */ - if(!list_from){ - infostream<<"IDropAction::apply(): FAIL: source list not found: " - <<"context=["<getItem(from_i); - if(item == NULL) - { - infostream<<"IDropAction::apply(): FAIL: source item not found: " - <<"context=["<getMaterial() != num) - return false; - } else { - if(mitem->getNodeName() != name) - return false; - } - } - else if(type == ITEM_CRAFT) - { - if(itemname != "CraftItem") - return false; - CraftItem *mitem = (CraftItem*)item; - if(mitem->getSubName() != name) - return false; - } - else if(type == ITEM_TOOL) - { - // Not supported yet - assert(0); - } - else if(type == ITEM_MBO) - { - // Not supported yet - assert(0); - } - else - { - // Not supported yet - assert(0); - } - return true; -} - -bool checkItemCombination(InventoryItem const * const *items, const ItemSpec *specs) -{ - u16 items_min_x = 100; - u16 items_max_x = 100; - u16 items_min_y = 100; - u16 items_max_y = 100; - for(u16 y=0; y<3; y++) - for(u16 x=0; x<3; x++) - { - if(items[y*3 + x] == NULL) - continue; - if(items_min_x == 100 || x < items_min_x) - items_min_x = x; - if(items_min_y == 100 || y < items_min_y) - items_min_y = y; - if(items_max_x == 100 || x > items_max_x) - items_max_x = x; - if(items_max_y == 100 || y > items_max_y) - items_max_y = y; - } - // No items at all, just return false - if(items_min_x == 100) - return false; - - u16 items_w = items_max_x - items_min_x + 1; - u16 items_h = items_max_y - items_min_y + 1; - - u16 specs_min_x = 100; - u16 specs_max_x = 100; - u16 specs_min_y = 100; - u16 specs_max_y = 100; - for(u16 y=0; y<3; y++) - for(u16 x=0; x<3; x++) - { - if(specs[y*3 + x].type == ITEM_NONE) - continue; - if(specs_min_x == 100 || x < specs_min_x) - specs_min_x = x; - if(specs_min_y == 100 || y < specs_min_y) - specs_min_y = y; - if(specs_max_x == 100 || x > specs_max_x) - specs_max_x = x; - if(specs_max_y == 100 || y > specs_max_y) - specs_max_y = y; - } - // No specs at all, just return false - if(specs_min_x == 100) - return false; - - u16 specs_w = specs_max_x - specs_min_x + 1; - u16 specs_h = specs_max_y - specs_min_y + 1; - - // Different sizes - if(items_w != specs_w || items_h != specs_h) - return false; - - for(u16 y=0; y items_max_x) - items_max_x = x; - if(items_max_y == 100 || y > items_max_y) - items_max_y = y; - } - // No items at all, just return false - if(items_min_x == 100) - return false; - - u16 items_w = items_max_x - items_min_x + 1; - u16 items_h = items_max_y - items_min_y + 1; - - u16 specs_min_x = 100; - u16 specs_max_x = 100; - u16 specs_min_y = 100; - u16 specs_max_y = 100; - for(u16 y=0; y<3; y++) - for(u16 x=0; x<3; x++) - { - if(specs[y*3 + x] == NULL) - continue; - if(specs_min_x == 100 || x < specs_min_x) - specs_min_x = x; - if(specs_min_y == 100 || y < specs_min_y) - specs_min_y = y; - if(specs_max_x == 100 || x > specs_max_x) - specs_max_x = x; - if(specs_max_y == 100 || y > specs_max_y) - specs_max_y = y; - } - // No specs at all, just return false - if(specs_min_x == 100) - return false; - - u16 specs_w = specs_max_x - specs_min_x + 1; - u16 specs_h = specs_max_y - specs_min_y + 1; - - // Different sizes - if(items_w != specs_w || items_h != specs_h) - return false; - - for(u16 y=0; yisSubsetOf(item)) - return false; - } - - return true; -} - //END diff --git a/src/inventory.h b/src/inventory.h index 795d32d3e..15de3c8e7 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -419,6 +419,7 @@ public: InventoryList(std::string name, u32 size); ~InventoryList(); void clearItems(); + void setSize(u32 newsize); void serialize(std::ostream &os) const; void deSerialize(std::istream &is, IGameDef *gamedef); @@ -513,182 +514,5 @@ private: core::array m_lists; }; -class Player; - -struct InventoryContext -{ - Player *current_player; - - InventoryContext(): - current_player(NULL) - {} -}; - -struct InventoryAction; - -class InventoryManager -{ -public: - InventoryManager(){} - virtual ~InventoryManager(){} - - /* - Get a pointer to an inventory specified by id. - id can be: - - "current_player" - - "nodemeta:X,Y,Z" - */ - virtual Inventory* getInventory(InventoryContext *c, std::string id) - {return NULL;} - // Used on the server by InventoryAction::apply and other stuff - virtual void inventoryModified(InventoryContext *c, std::string id) - {} - // Used on the client - virtual void inventoryAction(InventoryAction *a) - {} -}; - -#define IACTION_MOVE 0 -#define IACTION_DROP 1 - -struct InventoryAction -{ - static InventoryAction * deSerialize(std::istream &is); - - virtual u16 getType() const = 0; - virtual void serialize(std::ostream &os) const = 0; - virtual void apply(InventoryContext *c, InventoryManager *mgr, - ServerEnvironment *env) = 0; - virtual ~InventoryAction() {}; -}; - -struct IMoveAction : public InventoryAction -{ - // count=0 means "everything" - u16 count; - std::string from_inv; - std::string from_list; - s16 from_i; - std::string to_inv; - std::string to_list; - s16 to_i; - - IMoveAction() - { - count = 0; - from_i = -1; - to_i = -1; - } - - IMoveAction(std::istream &is); - - u16 getType() const - { - return IACTION_MOVE; - } - - void serialize(std::ostream &os) const - { - os<<"Move "; - os< + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "inventorymanager.h" +#include "serverremoteplayer.h" +#include "log.h" +#include "mapblock.h" // getNodeBlockPos + +/* + InventoryManager +*/ + +// Wrapper for old code +Inventory* InventoryManager::getInventory(InventoryContext *c, std::string id) +{ + if(id == "current_player") + { + assert(c->current_player); + InventoryLocation loc; + loc.setPlayer(c->current_player->getName()); + return getInventory(loc); + } + + Strfnd fn(id); + std::string id0 = fn.next(":"); + + if(id0 == "nodemeta") + { + v3s16 p; + p.X = stoi(fn.next(",")); + p.Y = stoi(fn.next(",")); + p.Z = stoi(fn.next(",")); + + InventoryLocation loc; + loc.setNodeMeta(p); + return getInventory(loc); + } + + errorstream<<__FUNCTION_NAME<<": unknown id "<current_player); + InventoryLocation loc; + loc.setPlayer(c->current_player->getName()); + setInventoryModified(loc); + return; + } + + Strfnd fn(id); + std::string id0 = fn.next(":"); + + if(id0 == "nodemeta") + { + v3s16 p; + p.X = stoi(fn.next(",")); + p.Y = stoi(fn.next(",")); + p.Z = stoi(fn.next(",")); + v3s16 blockpos = getNodeBlockPos(p); + + InventoryLocation loc; + loc.setNodeMeta(p); + setInventoryModified(loc); + return; + } + + errorstream<<__FUNCTION_NAME<<": unknown id "<current_player == NULL) + return "current_player=NULL"; + else + return std::string("current_player=") + c->current_player->getName(); +} + +IMoveAction::IMoveAction(std::istream &is) +{ + std::string ts; + + std::getline(is, ts, ' '); + count = stoi(ts); + + std::getline(is, from_inv, ' '); + + std::getline(is, from_list, ' '); + + std::getline(is, ts, ' '); + from_i = stoi(ts); + + std::getline(is, to_inv, ' '); + + std::getline(is, to_list, ' '); + + std::getline(is, ts, ' '); + to_i = stoi(ts); +} + +void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr, + ServerEnvironment *env) +{ + Inventory *inv_from = mgr->getInventory(c, from_inv); + Inventory *inv_to = mgr->getInventory(c, to_inv); + + if(!inv_from){ + infostream<<"IMoveAction::apply(): FAIL: source inventory not found: " + <<"context=["<getList(from_list); + InventoryList *list_to = inv_to->getList(to_list); + + /* + If a list doesn't exist or the source item doesn't exist + */ + if(!list_from){ + infostream<<"IMoveAction::apply(): FAIL: source list not found: " + <<"context=["<getItem(from_i) == NULL) + { + infostream<<"IMoveAction::apply(): FAIL: source item not found: " + <<"context=["<( + static_cast( + c->current_player + )); + + Inventory *inv_from = mgr->getInventory(c, from_inv); + + if(!inv_from){ + infostream<<"IDropAction::apply(): FAIL: source inventory not found: " + <<"context=["<getList(from_list); + + /* + If a list doesn't exist or the source item doesn't exist + */ + if(!list_from){ + infostream<<"IDropAction::apply(): FAIL: source list not found: " + <<"context=["<getItem(from_i); + if(item == NULL) + { + infostream<<"IDropAction::apply(): FAIL: source item not found: " + <<"context=["<getMaterial() != num) + return false; + } else { + if(mitem->getNodeName() != name) + return false; + } + } + else if(type == ITEM_CRAFT) + { + if(itemname != "CraftItem") + return false; + CraftItem *mitem = (CraftItem*)item; + if(mitem->getSubName() != name) + return false; + } + else if(type == ITEM_TOOL) + { + // Not supported yet + assert(0); + } + else if(type == ITEM_MBO) + { + // Not supported yet + assert(0); + } + else + { + // Not supported yet + assert(0); + } + return true; +} + +bool checkItemCombination(InventoryItem const * const *items, const ItemSpec *specs) +{ + u16 items_min_x = 100; + u16 items_max_x = 100; + u16 items_min_y = 100; + u16 items_max_y = 100; + for(u16 y=0; y<3; y++) + for(u16 x=0; x<3; x++) + { + if(items[y*3 + x] == NULL) + continue; + if(items_min_x == 100 || x < items_min_x) + items_min_x = x; + if(items_min_y == 100 || y < items_min_y) + items_min_y = y; + if(items_max_x == 100 || x > items_max_x) + items_max_x = x; + if(items_max_y == 100 || y > items_max_y) + items_max_y = y; + } + // No items at all, just return false + if(items_min_x == 100) + return false; + + u16 items_w = items_max_x - items_min_x + 1; + u16 items_h = items_max_y - items_min_y + 1; + + u16 specs_min_x = 100; + u16 specs_max_x = 100; + u16 specs_min_y = 100; + u16 specs_max_y = 100; + for(u16 y=0; y<3; y++) + for(u16 x=0; x<3; x++) + { + if(specs[y*3 + x].type == ITEM_NONE) + continue; + if(specs_min_x == 100 || x < specs_min_x) + specs_min_x = x; + if(specs_min_y == 100 || y < specs_min_y) + specs_min_y = y; + if(specs_max_x == 100 || x > specs_max_x) + specs_max_x = x; + if(specs_max_y == 100 || y > specs_max_y) + specs_max_y = y; + } + // No specs at all, just return false + if(specs_min_x == 100) + return false; + + u16 specs_w = specs_max_x - specs_min_x + 1; + u16 specs_h = specs_max_y - specs_min_y + 1; + + // Different sizes + if(items_w != specs_w || items_h != specs_h) + return false; + + for(u16 y=0; y items_max_x) + items_max_x = x; + if(items_max_y == 100 || y > items_max_y) + items_max_y = y; + } + // No items at all, just return false + if(items_min_x == 100) + return false; + + u16 items_w = items_max_x - items_min_x + 1; + u16 items_h = items_max_y - items_min_y + 1; + + u16 specs_min_x = 100; + u16 specs_max_x = 100; + u16 specs_min_y = 100; + u16 specs_max_y = 100; + for(u16 y=0; y<3; y++) + for(u16 x=0; x<3; x++) + { + if(specs[y*3 + x] == NULL) + continue; + if(specs_min_x == 100 || x < specs_min_x) + specs_min_x = x; + if(specs_min_y == 100 || y < specs_min_y) + specs_min_y = y; + if(specs_max_x == 100 || x > specs_max_x) + specs_max_x = x; + if(specs_max_y == 100 || y > specs_max_y) + specs_max_y = y; + } + // No specs at all, just return false + if(specs_min_x == 100) + return false; + + u16 specs_w = specs_max_x - specs_min_x + 1; + u16 specs_h = specs_max_y - specs_min_y + 1; + + // Different sizes + if(items_w != specs_w || items_h != specs_h) + return false; + + for(u16 y=0; yisSubsetOf(item)) + return false; + } + + return true; +} + + diff --git a/src/inventorymanager.h b/src/inventorymanager.h new file mode 100644 index 000000000..4abe5e73d --- /dev/null +++ b/src/inventorymanager.h @@ -0,0 +1,228 @@ +/* +Minetest-c55 +Copyright (C) 2010-2011 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef INVENTORYMANAGER_HEADER +#define INVENTORYMANAGER_HEADER + +#include "inventory.h" + +// Should probably somehow replace InventoryContext over time +struct InventoryLocation +{ + enum Type{ + UNDEFINED, + PLAYER, + NODEMETA + } type; + + std::string name; // PLAYER + v3s16 p; // NODEMETA + + void setPlayer(const std::string &name_) + { + type = PLAYER; + name = name_; + } + void setNodeMeta(v3s16 p_) + { + type = NODEMETA; + p = p_; + } +}; + +class Player; + +struct InventoryContext +{ + Player *current_player; + + InventoryContext(): + current_player(NULL) + {} +}; + +struct InventoryAction; + +class InventoryManager +{ +public: + InventoryManager(){} + virtual ~InventoryManager(){} + + // Get an inventory or set it modified (so it will be updated over + // network or so) + virtual Inventory* getInventory(const InventoryLocation &loc){return NULL;} + virtual void setInventoryModified(const InventoryLocation &loc){} + + // Used on the client to send an action to the server + virtual void inventoryAction(InventoryAction *a){} + + // (Deprecated; these wrap to the latter ones) + // Get a pointer to an inventory specified by id. id can be: + // - "current_player" + // - "nodemeta:X,Y,Z" + Inventory* getInventory(InventoryContext *c, std::string id); + // Used on the server by InventoryAction::apply and other stuff + void inventoryModified(InventoryContext *c, std::string id); +}; + +#define IACTION_MOVE 0 +#define IACTION_DROP 1 + +struct InventoryAction +{ + static InventoryAction * deSerialize(std::istream &is); + + virtual u16 getType() const = 0; + virtual void serialize(std::ostream &os) const = 0; + virtual void apply(InventoryContext *c, InventoryManager *mgr, + ServerEnvironment *env) = 0; +}; + +struct IMoveAction : public InventoryAction +{ + // count=0 means "everything" + u16 count; + std::string from_inv; + std::string from_list; + s16 from_i; + std::string to_inv; + std::string to_list; + s16 to_i; + + IMoveAction() + { + count = 0; + from_i = -1; + to_i = -1; + } + + IMoveAction(std::istream &is); + + u16 getType() const + { + return IACTION_MOVE; + } + + void serialize(std::ostream &os) const + { + os<<"Move "; + os<getName()){ + MaterialItem *item = (MaterialItem*)item0; + lua_newtable(L); + lua_pushstring(L, "NodeItem"); + lua_setfield(L, -2, "type"); + lua_pushstring(L, item->getNodeName().c_str()); + lua_setfield(L, -2, "name"); + } + else if(std::string("CraftItem") == item0->getName()){ + CraftItem *item = (CraftItem*)item0; + lua_newtable(L); + lua_pushstring(L, "CraftItem"); + lua_setfield(L, -2, "type"); + lua_pushstring(L, item->getSubName().c_str()); + lua_setfield(L, -2, "name"); + } + else if(std::string("ToolItem") == item0->getName()){ + ToolItem *item = (ToolItem*)item0; + lua_newtable(L); + lua_pushstring(L, "ToolItem"); + lua_setfield(L, -2, "type"); + lua_pushstring(L, item->getToolName().c_str()); + lua_setfield(L, -2, "name"); + lua_pushstring(L, itos(item->getWear()).c_str()); + lua_setfield(L, -2, "wear"); + } + else{ + errorstream<<"push_stack_item: Unknown item name: \"" + <getName()<<"\""<getWritableToolDefManager(); + get_server(L)->getWritableToolDefManager(); ToolDefinition def = read_tool_definition(L, table); @@ -857,12 +930,9 @@ static int l_register_craftitem(lua_State *L) luaL_checktype(L, 2, LUA_TTABLE); int table = 2; - // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); - Server *server = (Server*)lua_touserdata(L, -1); - // And get the writable CraftItem definition manager from the server + // Get the writable CraftItem definition manager from the server IWritableCraftItemDefManager *craftitemdef = - server->getWritableCraftItemDefManager(); + get_server(L)->getWritableCraftItemDefManager(); // Check if on_drop is defined lua_getfield(L, table, "on_drop"); @@ -907,12 +977,9 @@ static int l_register_node(lua_State *L) luaL_checktype(L, 2, LUA_TTABLE); int nodedef_table = 2; - // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); - Server *server = (Server*)lua_touserdata(L, -1); - // And get the writable node definition manager from the server + // Get the writable node definition manager from the server IWritableNodeDefManager *nodedef = - server->getWritableNodeDefManager(); + get_server(L)->getWritableNodeDefManager(); // Get default node definition from registry lua_getfield(L, LUA_REGISTRYINDEX, "minetest_nodedef_default"); @@ -1147,12 +1214,9 @@ static int l_alias_node(lua_State *L) std::string name = luaL_checkstring(L, 1); std::string convert_to = luaL_checkstring(L, 2); - // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); - Server *server = (Server*)lua_touserdata(L, -1); - // And get the writable node definition manager from the server + // Get the writable node definition manager from the server IWritableNodeDefManager *nodedef = - server->getWritableNodeDefManager(); + get_server(L)->getWritableNodeDefManager(); nodedef->setAlias(name, convert_to); @@ -1165,12 +1229,9 @@ static int l_alias_tool(lua_State *L) std::string name = luaL_checkstring(L, 1); std::string convert_to = luaL_checkstring(L, 2); - // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); - Server *server = (Server*)lua_touserdata(L, -1); - // And get the writable tool definition manager from the server + // Get the writable tool definition manager from the server IWritableToolDefManager *tooldef = - server->getWritableToolDefManager(); + get_server(L)->getWritableToolDefManager(); tooldef->setAlias(name, convert_to); @@ -1183,12 +1244,9 @@ static int l_alias_craftitem(lua_State *L) std::string name = luaL_checkstring(L, 1); std::string convert_to = luaL_checkstring(L, 2); - // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); - Server *server = (Server*)lua_touserdata(L, -1); - // And get the writable CraftItem definition manager from the server + // Get the writable CraftItem definition manager from the server IWritableCraftItemDefManager *craftitemdef = - server->getWritableCraftItemDefManager(); + get_server(L)->getWritableCraftItemDefManager(); craftitemdef->setAlias(name, convert_to); @@ -1202,12 +1260,9 @@ static int l_register_craft(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); int table0 = 1; - // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); - Server *server = (Server*)lua_touserdata(L, -1); - // And get the writable craft definition manager from the server + // Get the writable craft definition manager from the server IWritableCraftDefManager *craftdef = - server->getWritableCraftDefManager(); + get_server(L)->getWritableCraftDefManager(); std::string output; int width = 0; @@ -1295,8 +1350,7 @@ static int l_chat_send_all(lua_State *L) { const char *text = luaL_checkstring(L, 1); // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); - Server *server = (Server*)lua_touserdata(L, -1); + Server *server = get_server(L); // Send server->notifyPlayers(narrow_to_wide(text)); return 0; @@ -1308,8 +1362,7 @@ static int l_chat_send_player(lua_State *L) const char *name = luaL_checkstring(L, 1); const char *text = luaL_checkstring(L, 2); // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); - Server *server = (Server*)lua_touserdata(L, -1); + Server *server = get_server(L); // Send server->notifyPlayer(name, narrow_to_wide(text)); return 0; @@ -1320,8 +1373,7 @@ static int l_get_player_privs(lua_State *L) { const char *name = luaL_checkstring(L, 1); // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); - Server *server = (Server*)lua_touserdata(L, -1); + Server *server = get_server(L); // Do it lua_newtable(L); int table = lua_gettop(L); @@ -1413,11 +1465,337 @@ static void luaentity_get(lua_State *L, u16 id) } /* - Reference wrappers + Object wrappers */ #define method(class, name) {#name, class::l_##name} +/* + InvStack +*/ + +class InvStack +{ +private: + InventoryItem *m_stack; + + static const char className[]; + static const luaL_reg methods[]; + + // Exported functions + + // garbage collector + static int gc_object(lua_State *L) { + InvStack *o = *(InvStack **)(lua_touserdata(L, 1)); + delete o; + return 0; + } + + // take_item(self) + static int l_take_item(lua_State *L) + { + InvStack *o = checkobject(L, 1); + push_stack_item(L, o->m_stack); + if(o->m_stack->getCount() == 1){ + delete o->m_stack; + o->m_stack = NULL; + } else { + o->m_stack->remove(1); + } + return 1; + } + + // put_item(self, item) -> true/false + static int l_put_item(lua_State *L) + { + InvStack *o = checkobject(L, 1); + InventoryItem *item = check_stack_item(L, 2); + if(!item){ // nil can always be inserted + lua_pushboolean(L, true); + return 1; + } + if(!item->addableTo(o->m_stack)){ + lua_pushboolean(L, false); + return 1; + } + o->m_stack->add(1); + delete item; + lua_pushboolean(L, true); + return 1; + } + +public: + InvStack(InventoryItem *item=NULL): + m_stack(item) + { + } + + ~InvStack() + { + delete m_stack; + } + + static InvStack* checkobject(lua_State *L, int narg) + { + luaL_checktype(L, narg, LUA_TUSERDATA); + void *ud = luaL_checkudata(L, narg, className); + if(!ud) luaL_typerror(L, narg, className); + return *(InvStack**)ud; // unbox pointer + } + + InventoryItem* getItemCopy() + { + if(!m_stack) + return NULL; + return m_stack->clone(); + } + + // Creates an InvStack and leaves it on top of stack + static int create_object(lua_State *L) + { + InventoryItem *item = NULL; + if(lua_isstring(L, 1)){ + std::string itemstring = lua_tostring(L, 1); + if(itemstring != ""){ + try{ + IGameDef *gdef = get_server(L); + item = InventoryItem::deSerialize(itemstring, gdef); + }catch(SerializationError &e){ + } + } + } + InvStack *o = new InvStack(item); + *(void **)(lua_newuserdata(L, sizeof(void *))) = o; + luaL_getmetatable(L, className); + lua_setmetatable(L, -2); + return 1; + } + // Not callable from Lua + static int create(lua_State *L, InventoryItem *item) + { + InvStack *o = new InvStack(item); + *(void **)(lua_newuserdata(L, sizeof(void *))) = o; + luaL_getmetatable(L, className); + lua_setmetatable(L, -2); + return 1; + } + + static void Register(lua_State *L) + { + lua_newtable(L); + int methodtable = lua_gettop(L); + luaL_newmetatable(L, className); + int metatable = lua_gettop(L); + + lua_pushliteral(L, "__metatable"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); // hide metatable from Lua getmetatable() + + lua_pushliteral(L, "__index"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); + + lua_pushliteral(L, "__gc"); + lua_pushcfunction(L, gc_object); + lua_settable(L, metatable); + + lua_pop(L, 1); // drop metatable + + luaL_openlib(L, 0, methods, 0); // fill methodtable + lua_pop(L, 1); // drop methodtable + + // Can be created from Lua (InvStack::create(itemstring)) + lua_register(L, className, create_object); + } +}; +const char InvStack::className[] = "InvStack"; +const luaL_reg InvStack::methods[] = { + method(InvStack, take_item), + method(InvStack, put_item), + {0,0} +}; + +/* + InvRef +*/ + +class InvRef +{ +private: + InventoryLocation m_loc; + + static const char className[]; + static const luaL_reg methods[]; + + static InvRef *checkobject(lua_State *L, int narg) + { + luaL_checktype(L, narg, LUA_TUSERDATA); + void *ud = luaL_checkudata(L, narg, className); + if(!ud) luaL_typerror(L, narg, className); + return *(InvRef**)ud; // unbox pointer + } + + static Inventory* getinv(lua_State *L, InvRef *ref) + { + return get_server(L)->getInventory(ref->m_loc); + } + + static InventoryList* getlist(lua_State *L, InvRef *ref, + const char *listname) + { + Inventory *inv = getinv(L, ref); + if(!inv) + return NULL; + return inv->getList(listname); + } + + static InventoryItem* getitem(lua_State *L, InvRef *ref, + const char *listname, int i) + { + InventoryList *list = getlist(L, ref, listname); + if(!list) + return NULL; + return list->getItem(i); + } + + static void reportInventoryChange(lua_State *L, InvRef *ref) + { + // Inform other things that the inventory has changed + get_server(L)->setInventoryModified(ref->m_loc); + } + + // Exported functions + + // garbage collector + static int gc_object(lua_State *L) { + InvRef *o = *(InvRef **)(lua_touserdata(L, 1)); + delete o; + return 0; + } + + // set_size(self, listname, size) + static int l_set_size(lua_State *L) + { + InvRef *ref = checkobject(L, 1); + const char *listname = luaL_checkstring(L, 2); + int newsize = luaL_checknumber(L, 3); + Inventory *inv = getinv(L, ref); + if(newsize == 0){ + inv->deleteList(listname); + return 0; + } + InventoryList *list = inv->getList(listname); + if(list){ + list->setSize(newsize); + } else { + list = inv->addList(listname, newsize); + } + return 0; + } + + // get_stack(self, listname, i) + static int l_get_stack(lua_State *L) + { + InvRef *ref = checkobject(L, 1); + const char *listname = luaL_checkstring(L, 2); + int i = luaL_checknumber(L, 3); + InventoryItem *item = getitem(L, ref, listname, i); + if(!item){ + InvStack::create(L, NULL); + return 1; + } + InvStack::create(L, item->clone()); + return 1; + } + + // set_stack(self, listname, i, stack) + static int l_set_stack(lua_State *L) + { + InvRef *ref = checkobject(L, 1); + const char *listname = luaL_checkstring(L, 2); + int i = luaL_checknumber(L, 3); + InvStack *stack = InvStack::checkobject(L, 4); + InventoryList *list = getlist(L, ref, listname); + if(!list){ + lua_pushboolean(L, false); + return 1; + } + InventoryItem *newitem = stack->getItemCopy(); + InventoryItem *olditem = list->changeItem(i, newitem); + bool success = (olditem != newitem); + delete olditem; + lua_pushboolean(L, success); + return 1; + } + +public: + InvRef(const InventoryLocation &loc): + m_loc(loc) + { + } + + ~InvRef() + { + } + + // Creates an InvRef and leaves it on top of stack + // Not callable from Lua; all references are created on the C side. + static void create(lua_State *L, const InventoryLocation &loc) + { + InvRef *o = new InvRef(loc); + *(void **)(lua_newuserdata(L, sizeof(void *))) = o; + luaL_getmetatable(L, className); + lua_setmetatable(L, -2); + } + static void createPlayer(lua_State *L, Player *player) + { + InventoryLocation loc; + loc.setPlayer(player->getName()); + create(L, loc); + } + static void createNodeMeta(lua_State *L, v3s16 p) + { + InventoryLocation loc; + loc.setNodeMeta(p); + create(L, loc); + } + + static void Register(lua_State *L) + { + lua_newtable(L); + int methodtable = lua_gettop(L); + luaL_newmetatable(L, className); + int metatable = lua_gettop(L); + + lua_pushliteral(L, "__metatable"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); // hide metatable from Lua getmetatable() + + lua_pushliteral(L, "__index"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); + + lua_pushliteral(L, "__gc"); + lua_pushcfunction(L, gc_object); + lua_settable(L, metatable); + + lua_pop(L, 1); // drop metatable + + luaL_openlib(L, 0, methods, 0); // fill methodtable + lua_pop(L, 1); // drop methodtable + + // Cannot be created from Lua + //lua_register(L, className, create_object); + } +}; +const char InvRef::className[] = "InvRef"; +const luaL_reg InvRef::methods[] = { + method(InvRef, set_size), + method(InvRef, get_stack), + method(InvRef, set_stack), + {0,0} +}; + /* NodeMetaRef */ @@ -2189,41 +2567,7 @@ private: if(player == NULL) return 0; // Do it InventoryItem *item0 = player->getWieldedItem(); - if(item0 == NULL){ - lua_pushnil(L); - return 1; - } - if(std::string("MaterialItem") == item0->getName()){ - MaterialItem *item = (MaterialItem*)item0; - lua_newtable(L); - lua_pushstring(L, "NodeItem"); - lua_setfield(L, -2, "type"); - lua_pushstring(L, item->getNodeName().c_str()); - lua_setfield(L, -2, "name"); - } - else if(std::string("CraftItem") == item0->getName()){ - CraftItem *item = (CraftItem*)item0; - lua_newtable(L); - lua_pushstring(L, "CraftItem"); - lua_setfield(L, -2, "type"); - lua_pushstring(L, item->getSubName().c_str()); - lua_setfield(L, -2, "name"); - } - else if(std::string("ToolItem") == item0->getName()){ - ToolItem *item = (ToolItem*)item0; - lua_newtable(L); - lua_pushstring(L, "ToolItem"); - lua_setfield(L, -2, "type"); - lua_pushstring(L, item->getToolName().c_str()); - lua_setfield(L, -2, "name"); - lua_pushstring(L, itos(item->getWear()).c_str()); - lua_setfield(L, -2, "wear"); - } - else{ - errorstream<<"l_get_wielded_item: Unknown item name: \"" - <getName()<<"\""<getWritableNodeDefManager(); + get_server(L)->getWritableNodeDefManager(); // Get minetest.registered_on_placenodes lua_getglobal(L, "minetest"); @@ -3271,12 +3612,9 @@ void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode, //infostream<<"scriptapi_environment_on_dignode"<getWritableNodeDefManager(); + get_server(L)->getWritableNodeDefManager(); // Get minetest.registered_on_dignodes lua_getglobal(L, "minetest"); @@ -3306,12 +3644,9 @@ void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node, //infostream<<"scriptapi_environment_on_punchnode"<getWritableNodeDefManager(); + get_server(L)->getWritableNodeDefManager(); // Get minetest.registered_on_punchnodes lua_getglobal(L, "minetest"); diff --git a/src/server.cpp b/src/server.cpp index 4a0e952a8..3679195f3 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2458,7 +2458,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) craftresult and immediately moved to the free slot. */ do{ - Inventory *inv_to = getInventory(&c, ma->to_inv); + Inventory *inv_to = InventoryManager::getInventory(&c, ma->to_inv); if(!inv_to) break; InventoryList *list_to = inv_to->getList(ma->to_list); if(!list_to) break; @@ -3517,6 +3517,68 @@ void Server::onMapEditEvent(MapEditEvent *event) m_unsent_map_edit_queue.push_back(e); } +Inventory* Server::getInventory(const InventoryLocation &loc) +{ + switch(loc.type){ + case InventoryLocation::UNDEFINED: + {} + break; + case InventoryLocation::PLAYER: + { + Player *player = m_env->getPlayer(loc.name.c_str()); + if(!player) + return NULL; + return &player->inventory; + } + break; + case InventoryLocation::NODEMETA: + { + NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p); + if(!meta) + return NULL; + return meta->getInventory(); + } + break; + default: + assert(0); + } + return NULL; +} +void Server::setInventoryModified(const InventoryLocation &loc) +{ + switch(loc.type){ + case InventoryLocation::UNDEFINED: + {} + break; + case InventoryLocation::PLAYER: + { + ServerRemotePlayer *srp = static_cast + (m_env->getPlayer(loc.name.c_str())); + if(!srp) + return; + srp->m_inventory_not_sent = true; + } + break; + case InventoryLocation::NODEMETA: + { + v3s16 blockpos = getNodeBlockPos(loc.p); + + NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p); + if(meta) + meta->inventoryModified(); + + MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos); + if(block) + block->raiseModified(MOD_STATE_WRITE_NEEDED); + + setBlockNotSent(blockpos); + } + break; + default: + assert(0); + } +} +#if 0 Inventory* Server::getInventory(InventoryContext *c, std::string id) { if(id == "current_player") @@ -3534,12 +3596,10 @@ Inventory* Server::getInventory(InventoryContext *c, std::string id) p.X = stoi(fn.next(",")); p.Y = stoi(fn.next(",")); p.Z = stoi(fn.next(",")); - NodeMetadata *meta = m_env->getMap().getNodeMetadata(p); - if(meta) - return meta->getInventory(); - infostream<<"nodemeta at ("<getMap().getNodeMetadata(p); - if(meta) - meta->inventoryModified(); - - MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos); - if(block) - block->raiseModified(MOD_STATE_WRITE_NEEDED); - - setBlockNotSent(blockpos); - + InventoryLocation loc; + loc.setNodeMeta(p); + setInventoryModified(loc); return; } infostream<<__FUNCTION_NAME<<": unknown id "< Server::getPlayerInfo() { diff --git a/src/server.h b/src/server.h index ac8938175..129b4ac81 100644 --- a/src/server.h +++ b/src/server.h @@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "serialization.h" // For SER_FMT_VER_INVALID #include "serverremoteplayer.h" #include "mods.h" +#include "inventorymanager.h" struct LuaState; typedef struct lua_State lua_State; class IWritableToolDefManager; @@ -413,8 +414,8 @@ public: /* Shall be called with the environment and the connection locked. */ - Inventory* getInventory(InventoryContext *c, std::string id); - void inventoryModified(InventoryContext *c, std::string id); + Inventory* getInventory(const InventoryLocation &loc); + void setInventoryModified(const InventoryLocation &loc); // Connection must be locked when called std::wstring getStatusString();