diff options
-rw-r--r-- | builtin/game/detached_inventory.lua | 4 | ||||
-rw-r--r-- | doc/lua_api.txt | 2 | ||||
-rw-r--r-- | src/network/clientpackethandler.cpp | 29 | ||||
-rw-r--r-- | src/network/networkprotocol.h | 8 | ||||
-rw-r--r-- | src/script/lua_api/l_inventory.cpp | 10 | ||||
-rw-r--r-- | src/script/lua_api/l_inventory.h | 2 | ||||
-rw-r--r-- | src/server.cpp | 75 | ||||
-rw-r--r-- | src/server.h | 4 |
8 files changed, 100 insertions, 34 deletions
diff --git a/builtin/game/detached_inventory.lua b/builtin/game/detached_inventory.lua index 420e89ff2..2e27168a1 100644 --- a/builtin/game/detached_inventory.lua +++ b/builtin/game/detached_inventory.lua @@ -18,3 +18,7 @@ function core.create_detached_inventory(name, callbacks, player_name) return core.create_detached_inventory_raw(name, player_name) end +function core.remove_detached_inventory(name) + core.detached_inventories[name] = nil + return core.remove_detached_inventory_raw(name) +end diff --git a/doc/lua_api.txt b/doc/lua_api.txt index e144a2c8f..19d6482ae 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -4141,6 +4141,8 @@ Inventory Note that this parameter is mostly just a workaround and will be removed in future releases. * Creates a detached inventory. If it already exists, it is cleared. +* `minetest.remove_detached_inventory(name)` + * Returns a `boolean` indicating whether the removal succeeded. * `minetest.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)`: returns left over ItemStack. * See `minetest.item_eat` and `minetest.register_on_item_eat` diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index cbd0d6a57..5a62fec3d 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -843,21 +843,32 @@ void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt) void Client::handleCommand_DetachedInventory(NetworkPacket* pkt) { - std::string datastring(pkt->getString(0), pkt->getSize()); - std::istringstream is(datastring, std::ios_base::binary); - - std::string name = deSerializeString(is); + std::string name; + bool keep_inv = true; + *pkt >> name >> keep_inv; infostream << "Client: Detached inventory update: \"" << name - << "\"" << std::endl; + << "\", mode=" << (keep_inv ? "update" : "remove") << std::endl; - Inventory *inv = NULL; - if (m_detached_inventories.count(name) > 0) - inv = m_detached_inventories[name]; - else { + const auto &inv_it = m_detached_inventories.find(name); + if (!keep_inv) { + if (inv_it != m_detached_inventories.end()) { + delete inv_it->second; + m_detached_inventories.erase(inv_it); + } + return; + } + Inventory *inv = nullptr; + if (inv_it == m_detached_inventories.end()) { inv = new Inventory(m_itemdef); m_detached_inventories[name] = inv; + } else { + inv = inv_it->second; } + + std::string contents; + *pkt >> contents; + std::istringstream is(contents, std::ios::binary); inv->deSerialize(is); } diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 4e896602b..855afc638 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -188,19 +188,21 @@ with this program; if not, write to the Free Software Foundation, Inc., Nodebox version 5 Add disconnected nodeboxes Add TOCLIENT_FORMSPEC_PREPEND + PROTOCOL VERSION 37: + Redo detached inventory sending */ -#define LATEST_PROTOCOL_VERSION 36 +#define LATEST_PROTOCOL_VERSION 37 #define LATEST_PROTOCOL_VERSION_STRING TOSTRING(LATEST_PROTOCOL_VERSION) // Server's supported network protocol range -#define SERVER_PROTOCOL_VERSION_MIN 36 +#define SERVER_PROTOCOL_VERSION_MIN 37 #define SERVER_PROTOCOL_VERSION_MAX LATEST_PROTOCOL_VERSION // Client's supported network protocol range // The minimal version depends on whether // send_pre_v25_init is enabled or not -#define CLIENT_PROTOCOL_VERSION_MIN 36 +#define CLIENT_PROTOCOL_VERSION_MIN 37 #define CLIENT_PROTOCOL_VERSION_MAX LATEST_PROTOCOL_VERSION // Constant that differentiates the protocol from random data and other protocols diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp index 04fa3a196..6e7afa4a4 100644 --- a/src/script/lua_api/l_inventory.cpp +++ b/src/script/lua_api/l_inventory.cpp @@ -536,8 +536,18 @@ int ModApiInventory::l_create_detached_inventory_raw(lua_State *L) return 1; } +// remove_detached_inventory_raw(name) +int ModApiInventory::l_remove_detached_inventory_raw(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + const std::string &name = luaL_checkstring(L, 1); + lua_pushboolean(L, getServer(L)->removeDetachedInventory(name)); + return 1; +} + void ModApiInventory::Initialize(lua_State *L, int top) { API_FCT(create_detached_inventory_raw); + API_FCT(remove_detached_inventory_raw); API_FCT(get_inventory); } diff --git a/src/script/lua_api/l_inventory.h b/src/script/lua_api/l_inventory.h index 2b7910ac3..94f670c9d 100644 --- a/src/script/lua_api/l_inventory.h +++ b/src/script/lua_api/l_inventory.h @@ -120,6 +120,8 @@ class ModApiInventory : public ModApiBase { private: static int l_create_detached_inventory_raw(lua_State *L); + static int l_remove_detached_inventory_raw(lua_State *L); + static int l_get_inventory(lua_State *L); public: diff --git a/src/server.cpp b/src/server.cpp index 41248c869..678ee387b 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2478,33 +2478,41 @@ void Server::sendRequestedMedia(session_t peer_id, void Server::sendDetachedInventory(const std::string &name, session_t peer_id) { - if(m_detached_inventories.count(name) == 0) { - errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl; - return; - } - Inventory *inv = m_detached_inventories[name]; - std::ostringstream os(std::ios_base::binary); + const auto &inv_it = m_detached_inventories.find(name); + const auto &player_it = m_detached_inventories_player.find(name); - os << serializeString(name); - inv->serialize(os); + if (player_it == m_detached_inventories_player.end() || + player_it->second.empty()) { + // OK. Send to everyone + } else { + RemotePlayer *p = m_env->getPlayer(player_it->second.c_str()); + if (!p) + return; // Player is offline - // Make data buffer - std::string s = os.str(); + if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId()) + return; // Caller requested send to a different player, so don't send. + + peer_id = p->getPeerId(); + } NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id); - pkt.putRawString(s.c_str(), s.size()); + pkt << name; - const std::string &check = m_detached_inventories_player[name]; - if (peer_id == PEER_ID_INEXISTENT) { - if (check.empty()) - return m_clients.sendToAll(&pkt); - RemotePlayer *p = m_env->getPlayer(check.c_str()); - if (p) - m_clients.send(p->getPeerId(), 0, &pkt, true); + if (inv_it == m_detached_inventories.end()) { + pkt << false; // Remove inventory } else { - if (check.empty() || getPlayerName(peer_id) == check) - Send(&pkt); + pkt << true; // Update inventory + + // Serialization & NetworkPacket isn't a love story + std::ostringstream os(std::ios_base::binary); + inv_it->second->serialize(os); + pkt << os.str(); } + + if (peer_id == PEER_ID_INEXISTENT) + m_clients.sendToAll(&pkt); + else + Send(&pkt); } void Server::sendDetachedInventories(session_t peer_id) @@ -2665,9 +2673,10 @@ void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason) playersao->clearParentAttachment(); // inform connected clients + const std::string &player_name = player->getName(); NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT); // (u16) 1 + std::string represents a vector serialization representation - notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName()); + notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name; m_clients.sendToAll(¬ice); // run scripts m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT); @@ -3265,6 +3274,30 @@ Inventory* Server::createDetachedInventory(const std::string &name, const std::s return inv; } +bool Server::removeDetachedInventory(const std::string &name) +{ + const auto &inv_it = m_detached_inventories.find(name); + if (inv_it == m_detached_inventories.end()) + return false; + + delete inv_it->second; + m_detached_inventories.erase(inv_it); + + const auto &player_it = m_detached_inventories_player.find(name); + if (player_it != m_detached_inventories_player.end()) { + RemotePlayer *player = m_env->getPlayer(player_it->second.c_str()); + + if (player && player->getPeerId() != PEER_ID_INEXISTENT) + sendDetachedInventory(name, player->getPeerId()); + + m_detached_inventories_player.erase(player_it); + } else { + // Notify all players about the change + sendDetachedInventory(name, PEER_ID_INEXISTENT); + } + return true; +} + // actions: time-reversed list // Return value: success/failure bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions, diff --git a/src/server.h b/src/server.h index c2adbbc07..9643fe456 100644 --- a/src/server.h +++ b/src/server.h @@ -248,7 +248,9 @@ public: void deleteParticleSpawner(const std::string &playername, u32 id); // Creates or resets inventory - Inventory* createDetachedInventory(const std::string &name, const std::string &player=""); + Inventory *createDetachedInventory(const std::string &name, + const std::string &player = ""); + bool removeDetachedInventory(const std::string &name); // Envlock and conlock should be locked when using scriptapi ServerScripting *getScriptIface(){ return m_script; } |