Browse Source

Add core.remove_detached_inventory (#7684)

Breaks backwards compatibility for good
Bump protocol version
SmallJoker 5 years ago
parent
commit
0a5e77132a

+ 4 - 0
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

+ 2 - 0
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`

+ 20 - 9
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);
 }
 

+ 5 - 3
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

+ 10 - 0
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);
 }

+ 2 - 0
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:

+ 54 - 21
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(&notice);
 			// 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,

+ 3 - 1
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; }