serverinventorymgr.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2020 Minetest core development team
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "serverinventorymgr.h"
  17. #include "map.h"
  18. #include "nodemetadata.h"
  19. #include "player_sao.h"
  20. #include "remoteplayer.h"
  21. #include "server.h"
  22. #include "serverenvironment.h"
  23. ServerInventoryManager::ServerInventoryManager() : InventoryManager()
  24. {
  25. }
  26. ServerInventoryManager::~ServerInventoryManager()
  27. {
  28. // Delete detached inventories
  29. for (auto &detached_inventory : m_detached_inventories) {
  30. delete detached_inventory.second.inventory;
  31. }
  32. }
  33. Inventory *ServerInventoryManager::getInventory(const InventoryLocation &loc)
  34. {
  35. // No m_env check here: allow creation and modification of detached inventories
  36. switch (loc.type) {
  37. case InventoryLocation::UNDEFINED:
  38. case InventoryLocation::CURRENT_PLAYER:
  39. break;
  40. case InventoryLocation::PLAYER: {
  41. if (!m_env)
  42. return nullptr;
  43. RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
  44. if (!player)
  45. return NULL;
  46. PlayerSAO *playersao = player->getPlayerSAO();
  47. return playersao ? playersao->getInventory() : nullptr;
  48. } break;
  49. case InventoryLocation::NODEMETA: {
  50. if (!m_env)
  51. return nullptr;
  52. NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
  53. return meta ? meta->getInventory() : nullptr;
  54. } break;
  55. case InventoryLocation::DETACHED: {
  56. auto it = m_detached_inventories.find(loc.name);
  57. if (it == m_detached_inventories.end())
  58. return nullptr;
  59. return it->second.inventory;
  60. } break;
  61. default:
  62. sanity_check(false); // abort
  63. break;
  64. }
  65. return NULL;
  66. }
  67. void ServerInventoryManager::setInventoryModified(const InventoryLocation &loc)
  68. {
  69. switch (loc.type) {
  70. case InventoryLocation::UNDEFINED:
  71. break;
  72. case InventoryLocation::PLAYER: {
  73. RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
  74. if (!player)
  75. return;
  76. player->setModified(true);
  77. player->inventory.setModified(true);
  78. // Updates are sent in ServerEnvironment::step()
  79. } break;
  80. case InventoryLocation::NODEMETA: {
  81. MapEditEvent event;
  82. event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
  83. event.setPositionModified(loc.p);
  84. m_env->getMap().dispatchEvent(event);
  85. } break;
  86. case InventoryLocation::DETACHED: {
  87. // Updates are sent in ServerEnvironment::step()
  88. } break;
  89. default:
  90. sanity_check(false); // abort
  91. break;
  92. }
  93. }
  94. Inventory *ServerInventoryManager::createDetachedInventory(
  95. const std::string &name, IItemDefManager *idef, const std::string &player)
  96. {
  97. if (m_detached_inventories.count(name) > 0) {
  98. infostream << "Server clearing detached inventory \"" << name << "\""
  99. << std::endl;
  100. delete m_detached_inventories[name].inventory;
  101. } else {
  102. infostream << "Server creating detached inventory \"" << name << "\""
  103. << std::endl;
  104. }
  105. Inventory *inv = new Inventory(idef);
  106. sanity_check(inv);
  107. m_detached_inventories[name].inventory = inv;
  108. if (!player.empty()) {
  109. m_detached_inventories[name].owner = player;
  110. if (!m_env)
  111. return inv; // Mods are not loaded yet, ignore
  112. RemotePlayer *p = m_env->getPlayer(name.c_str());
  113. // if player is connected, send him the inventory
  114. if (p && p->getPeerId() != PEER_ID_INEXISTENT) {
  115. m_env->getGameDef()->sendDetachedInventory(
  116. inv, name, p->getPeerId());
  117. }
  118. } else {
  119. if (!m_env)
  120. return inv; // Mods are not loaded yet, don't send
  121. // Inventory is for everybody, broadcast
  122. m_env->getGameDef()->sendDetachedInventory(inv, name, PEER_ID_INEXISTENT);
  123. }
  124. return inv;
  125. }
  126. bool ServerInventoryManager::removeDetachedInventory(const std::string &name)
  127. {
  128. const auto &inv_it = m_detached_inventories.find(name);
  129. if (inv_it == m_detached_inventories.end())
  130. return false;
  131. delete inv_it->second.inventory;
  132. const std::string &owner = inv_it->second.owner;
  133. if (!owner.empty()) {
  134. if (m_env) {
  135. RemotePlayer *player = m_env->getPlayer(owner.c_str());
  136. if (player && player->getPeerId() != PEER_ID_INEXISTENT)
  137. m_env->getGameDef()->sendDetachedInventory(
  138. nullptr, name, player->getPeerId());
  139. }
  140. } else if (m_env) {
  141. // Notify all players about the change as soon ServerEnv exists
  142. m_env->getGameDef()->sendDetachedInventory(
  143. nullptr, name, PEER_ID_INEXISTENT);
  144. }
  145. m_detached_inventories.erase(inv_it);
  146. return true;
  147. }
  148. bool ServerInventoryManager::checkDetachedInventoryAccess(
  149. const InventoryLocation &loc, const std::string &player) const
  150. {
  151. SANITY_CHECK(loc.type == InventoryLocation::DETACHED);
  152. const auto &inv_it = m_detached_inventories.find(loc.name);
  153. if (inv_it == m_detached_inventories.end())
  154. return false;
  155. return inv_it->second.owner.empty() || inv_it->second.owner == player;
  156. }
  157. void ServerInventoryManager::sendDetachedInventories(const std::string &peer_name,
  158. bool incremental,
  159. std::function<void(const std::string &, Inventory *)> apply_cb)
  160. {
  161. for (const auto &detached_inventory : m_detached_inventories) {
  162. const DetachedInventory &dinv = detached_inventory.second;
  163. if (incremental) {
  164. if (!dinv.inventory || !dinv.inventory->checkModified())
  165. continue;
  166. }
  167. // if we are pushing inventories to a specific player
  168. // we should filter to send only the right inventories
  169. if (!peer_name.empty()) {
  170. const std::string &attached_player = dinv.owner;
  171. if (!attached_player.empty() && peer_name != attached_player)
  172. continue;
  173. }
  174. apply_cb(detached_inventory.first, detached_inventory.second.inventory);
  175. }
  176. }