]> git.lizzy.rs Git - minetest.git/blob - src/server/serverinventorymgr.cpp
Server class code cleanups (#9769)
[minetest.git] / src / server / serverinventorymgr.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2020 Minetest core development team
4
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.
9
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.
14
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.
18 */
19
20 #include "serverinventorymgr.h"
21 #include "map.h"
22 #include "nodemetadata.h"
23 #include "player_sao.h"
24 #include "remoteplayer.h"
25 #include "server.h"
26 #include "serverenvironment.h"
27
28 ServerInventoryManager::ServerInventoryManager() : InventoryManager()
29 {
30 }
31
32 ServerInventoryManager::~ServerInventoryManager()
33 {
34         // Delete detached inventories
35         for (auto &detached_inventory : m_detached_inventories) {
36                 delete detached_inventory.second.inventory;
37         }
38 }
39
40 Inventory *ServerInventoryManager::getInventory(const InventoryLocation &loc)
41 {
42         switch (loc.type) {
43         case InventoryLocation::UNDEFINED:
44         case InventoryLocation::CURRENT_PLAYER:
45                 break;
46         case InventoryLocation::PLAYER: {
47                 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
48                 if (!player)
49                         return NULL;
50                 PlayerSAO *playersao = player->getPlayerSAO();
51                 if (!playersao)
52                         return NULL;
53                 return playersao->getInventory();
54         } break;
55         case InventoryLocation::NODEMETA: {
56                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
57                 if (!meta)
58                         return NULL;
59                 return meta->getInventory();
60         } break;
61         case InventoryLocation::DETACHED: {
62                 auto it = m_detached_inventories.find(loc.name);
63                 if (it == m_detached_inventories.end())
64                         return nullptr;
65                 return it->second.inventory;
66         } break;
67         default:
68                 sanity_check(false); // abort
69                 break;
70         }
71         return NULL;
72 }
73
74 void ServerInventoryManager::setInventoryModified(const InventoryLocation &loc)
75 {
76         switch (loc.type) {
77         case InventoryLocation::UNDEFINED:
78                 break;
79         case InventoryLocation::PLAYER: {
80
81                 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
82
83                 if (!player)
84                         return;
85
86                 player->setModified(true);
87                 player->inventory.setModified(true);
88                 // Updates are sent in ServerEnvironment::step()
89         } break;
90         case InventoryLocation::NODEMETA: {
91                 MapEditEvent event;
92                 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
93                 event.p = loc.p;
94                 m_env->getMap().dispatchEvent(event);
95         } break;
96         case InventoryLocation::DETACHED: {
97                 // Updates are sent in ServerEnvironment::step()
98         } break;
99         default:
100                 sanity_check(false); // abort
101                 break;
102         }
103 }
104
105 Inventory *ServerInventoryManager::createDetachedInventory(
106                 const std::string &name, IItemDefManager *idef, const std::string &player)
107 {
108         if (m_detached_inventories.count(name) > 0) {
109                 infostream << "Server clearing detached inventory \"" << name << "\""
110                            << std::endl;
111                 delete m_detached_inventories[name].inventory;
112         } else {
113                 infostream << "Server creating detached inventory \"" << name << "\""
114                            << std::endl;
115         }
116
117         Inventory *inv = new Inventory(idef);
118         sanity_check(inv);
119         m_detached_inventories[name].inventory = inv;
120         if (!player.empty()) {
121                 m_detached_inventories[name].owner = player;
122
123                 if (!m_env)
124                         return inv; // Mods are not loaded yet, ignore
125
126                 RemotePlayer *p = m_env->getPlayer(name.c_str());
127
128                 // if player is connected, send him the inventory
129                 if (p && p->getPeerId() != PEER_ID_INEXISTENT) {
130                         m_env->getGameDef()->sendDetachedInventory(
131                                         inv, name, p->getPeerId());
132                 }
133         } else {
134                 if (!m_env)
135                         return inv; // Mods are not loaded yet, don't send
136
137                 // Inventory is for everybody, broadcast
138                 m_env->getGameDef()->sendDetachedInventory(inv, name, PEER_ID_INEXISTENT);
139         }
140
141         return inv;
142 }
143
144 bool ServerInventoryManager::removeDetachedInventory(const std::string &name)
145 {
146         const auto &inv_it = m_detached_inventories.find(name);
147         if (inv_it == m_detached_inventories.end())
148                 return false;
149
150         delete inv_it->second.inventory;
151         const std::string &owner = inv_it->second.owner;
152
153         if (!owner.empty()) {
154                 RemotePlayer *player = m_env->getPlayer(owner.c_str());
155
156                 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
157                         m_env->getGameDef()->sendDetachedInventory(
158                                         nullptr, name, player->getPeerId());
159
160         } else {
161                 // Notify all players about the change
162                 m_env->getGameDef()->sendDetachedInventory(
163                                 nullptr, name, PEER_ID_INEXISTENT);
164         }
165
166         m_detached_inventories.erase(inv_it);
167
168         return true;
169 }
170
171 void ServerInventoryManager::sendDetachedInventories(const std::string &peer_name,
172                 bool incremental,
173                 std::function<void(const std::string &, Inventory *)> apply_cb)
174 {
175         for (const auto &detached_inventory : m_detached_inventories) {
176                 const DetachedInventory &dinv = detached_inventory.second;
177                 if (incremental) {
178                         if (!dinv.inventory || !dinv.inventory->checkModified())
179                                 continue;
180                 }
181
182                 // if we are pushing inventories to a specific player
183                 // we should filter to send only the right inventories
184                 if (!peer_name.empty()) {
185                         const std::string &attached_player = dinv.owner;
186                         if (!attached_player.empty() && peer_name != attached_player)
187                                 continue;
188                 }
189
190                 apply_cb(detached_inventory.first, detached_inventory.second.inventory);
191         }
192 }