3 Copyright (C) 2010-2020 Minetest core development team
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "serverinventorymgr.h"
22 #include "nodemetadata.h"
23 #include "player_sao.h"
24 #include "remoteplayer.h"
26 #include "serverenvironment.h"
28 ServerInventoryManager::ServerInventoryManager() : InventoryManager()
32 ServerInventoryManager::~ServerInventoryManager()
34 // Delete detached inventories
35 for (auto &detached_inventory : m_detached_inventories) {
36 delete detached_inventory.second.inventory;
40 Inventory *ServerInventoryManager::getInventory(const InventoryLocation &loc)
42 // No m_env check here: allow creation and modification of detached inventories
45 case InventoryLocation::UNDEFINED:
46 case InventoryLocation::CURRENT_PLAYER:
48 case InventoryLocation::PLAYER: {
52 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
56 PlayerSAO *playersao = player->getPlayerSAO();
57 return playersao ? playersao->getInventory() : nullptr;
59 case InventoryLocation::NODEMETA: {
63 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
64 return meta ? meta->getInventory() : nullptr;
66 case InventoryLocation::DETACHED: {
67 auto it = m_detached_inventories.find(loc.name);
68 if (it == m_detached_inventories.end())
70 return it->second.inventory;
73 sanity_check(false); // abort
79 void ServerInventoryManager::setInventoryModified(const InventoryLocation &loc)
82 case InventoryLocation::UNDEFINED:
84 case InventoryLocation::PLAYER: {
86 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
91 player->setModified(true);
92 player->inventory.setModified(true);
93 // Updates are sent in ServerEnvironment::step()
95 case InventoryLocation::NODEMETA: {
97 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
98 event.setPositionModified(loc.p);
99 m_env->getMap().dispatchEvent(event);
101 case InventoryLocation::DETACHED: {
102 // Updates are sent in ServerEnvironment::step()
105 sanity_check(false); // abort
110 Inventory *ServerInventoryManager::createDetachedInventory(
111 const std::string &name, IItemDefManager *idef, const std::string &player)
113 if (m_detached_inventories.count(name) > 0) {
114 infostream << "Server clearing detached inventory \"" << name << "\""
116 delete m_detached_inventories[name].inventory;
118 infostream << "Server creating detached inventory \"" << name << "\""
122 Inventory *inv = new Inventory(idef);
124 m_detached_inventories[name].inventory = inv;
125 if (!player.empty()) {
126 m_detached_inventories[name].owner = player;
129 return inv; // Mods are not loaded yet, ignore
131 RemotePlayer *p = m_env->getPlayer(name.c_str());
133 // if player is connected, send him the inventory
134 if (p && p->getPeerId() != PEER_ID_INEXISTENT) {
135 m_env->getGameDef()->sendDetachedInventory(
136 inv, name, p->getPeerId());
140 return inv; // Mods are not loaded yet, don't send
142 // Inventory is for everybody, broadcast
143 m_env->getGameDef()->sendDetachedInventory(inv, name, PEER_ID_INEXISTENT);
149 bool ServerInventoryManager::removeDetachedInventory(const std::string &name)
151 const auto &inv_it = m_detached_inventories.find(name);
152 if (inv_it == m_detached_inventories.end())
155 delete inv_it->second.inventory;
156 const std::string &owner = inv_it->second.owner;
158 if (!owner.empty()) {
160 RemotePlayer *player = m_env->getPlayer(owner.c_str());
162 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
163 m_env->getGameDef()->sendDetachedInventory(
164 nullptr, name, player->getPeerId());
167 // Notify all players about the change as soon ServerEnv exists
168 m_env->getGameDef()->sendDetachedInventory(
169 nullptr, name, PEER_ID_INEXISTENT);
172 m_detached_inventories.erase(inv_it);
177 bool ServerInventoryManager::checkDetachedInventoryAccess(
178 const InventoryLocation &loc, const std::string &player) const
180 SANITY_CHECK(loc.type == InventoryLocation::DETACHED);
182 const auto &inv_it = m_detached_inventories.find(loc.name);
183 if (inv_it == m_detached_inventories.end())
186 return inv_it->second.owner.empty() || inv_it->second.owner == player;
189 void ServerInventoryManager::sendDetachedInventories(const std::string &peer_name,
191 std::function<void(const std::string &, Inventory *)> apply_cb)
193 for (const auto &detached_inventory : m_detached_inventories) {
194 const DetachedInventory &dinv = detached_inventory.second;
196 if (!dinv.inventory || !dinv.inventory->checkModified())
200 // if we are pushing inventories to a specific player
201 // we should filter to send only the right inventories
202 if (!peer_name.empty()) {
203 const std::string &attached_player = dinv.owner;
204 if (!attached_player.empty() && peer_name != attached_player)
208 apply_cb(detached_inventory.first, detached_inventory.second.inventory);