forked from Mirrorlandia_minetest/minetest
Server class code cleanups (#9769)
* Server::overrideDayNightRatio doesn't require to return bool There is no sense to sending null player, the caller should send a valid object * Server::init: make private & cleanup This function is always called before start() and loads some variables which can be loaded in constructor directly. Make it private and call it directly in start * Split Server inventory responsibility to a dedicated object This splits permit to found various historical issues: * duplicate lookups on player connection * sending inventory to non related player when a player connects * non friendly lookups on detached inventories ownership This reduce the detached inventory complexity and also increased the lookup performance in a quite interesting way for servers with thousands of inventories.
This commit is contained in:
parent
650168cada
commit
454dbf83a9
@ -1302,7 +1302,6 @@ bool Game::createSingleplayerServer(const std::string &map_dir,
|
|||||||
}
|
}
|
||||||
|
|
||||||
server = new Server(map_dir, gamespec, simple_singleplayer_mode, bind_addr, false);
|
server = new Server(map_dir, gamespec, simple_singleplayer_mode, bind_addr, false);
|
||||||
server->init();
|
|
||||||
server->start();
|
server->start();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -887,7 +887,6 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings &
|
|||||||
// Create server
|
// Create server
|
||||||
Server server(game_params.world_path, game_params.game_spec,
|
Server server(game_params.world_path, game_params.game_spec,
|
||||||
false, bind_addr, true, &iface);
|
false, bind_addr, true, &iface);
|
||||||
server.init();
|
|
||||||
|
|
||||||
g_term_console.setup(&iface, &kill, admin_nick);
|
g_term_console.setup(&iface, &kill, admin_nick);
|
||||||
|
|
||||||
@ -922,7 +921,6 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings &
|
|||||||
// Create server
|
// Create server
|
||||||
Server server(game_params.world_path, game_params.game_spec, false,
|
Server server(game_params.world_path, game_params.game_spec, false,
|
||||||
bind_addr, true);
|
bind_addr, true);
|
||||||
server.init();
|
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
// Run server
|
// Run server
|
||||||
|
@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "network/networkprotocol.h"
|
#include "network/networkprotocol.h"
|
||||||
#include "network/serveropcodes.h"
|
#include "network/serveropcodes.h"
|
||||||
#include "server/player_sao.h"
|
#include "server/player_sao.h"
|
||||||
|
#include "server/serverinventorymgr.h"
|
||||||
#include "util/auth.h"
|
#include "util/auth.h"
|
||||||
#include "util/base64.h"
|
#include "util/base64.h"
|
||||||
#include "util/pointedthing.h"
|
#include "util/pointedthing.h"
|
||||||
@ -620,9 +621,9 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
|
|||||||
ma->from_inv.applyCurrentPlayer(player->getName());
|
ma->from_inv.applyCurrentPlayer(player->getName());
|
||||||
ma->to_inv.applyCurrentPlayer(player->getName());
|
ma->to_inv.applyCurrentPlayer(player->getName());
|
||||||
|
|
||||||
setInventoryModified(ma->from_inv);
|
m_inventory_mgr->setInventoryModified(ma->from_inv);
|
||||||
if (ma->from_inv != ma->to_inv)
|
if (ma->from_inv != ma->to_inv)
|
||||||
setInventoryModified(ma->to_inv);
|
m_inventory_mgr->setInventoryModified(ma->to_inv);
|
||||||
|
|
||||||
bool from_inv_is_current_player =
|
bool from_inv_is_current_player =
|
||||||
(ma->from_inv.type == InventoryLocation::PLAYER) &&
|
(ma->from_inv.type == InventoryLocation::PLAYER) &&
|
||||||
@ -687,7 +688,7 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
|
|||||||
|
|
||||||
da->from_inv.applyCurrentPlayer(player->getName());
|
da->from_inv.applyCurrentPlayer(player->getName());
|
||||||
|
|
||||||
setInventoryModified(da->from_inv);
|
m_inventory_mgr->setInventoryModified(da->from_inv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Disable dropping items out of craftpreview
|
Disable dropping items out of craftpreview
|
||||||
@ -723,7 +724,7 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
|
|||||||
|
|
||||||
ca->craft_inv.applyCurrentPlayer(player->getName());
|
ca->craft_inv.applyCurrentPlayer(player->getName());
|
||||||
|
|
||||||
setInventoryModified(ca->craft_inv);
|
m_inventory_mgr->setInventoryModified(ca->craft_inv);
|
||||||
|
|
||||||
//bool craft_inv_is_current_player =
|
//bool craft_inv_is_current_player =
|
||||||
// (ca->craft_inv.type == InventoryLocation::PLAYER) &&
|
// (ca->craft_inv.type == InventoryLocation::PLAYER) &&
|
||||||
@ -739,7 +740,7 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do the action
|
// Do the action
|
||||||
a->apply(this, playersao, this);
|
a->apply(m_inventory_mgr.get(), playersao, this);
|
||||||
// Eat the action
|
// Eat the action
|
||||||
delete a;
|
delete a;
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,11 @@ Server *ModApiBase::getServer(lua_State *L)
|
|||||||
return getScriptApiBase(L)->getServer();
|
return getScriptApiBase(L)->getServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ServerInventoryManager *ModApiBase::getServerInventoryMgr(lua_State *L)
|
||||||
|
{
|
||||||
|
return getScriptApiBase(L)->getServer()->getInventoryMgr();
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef SERVER
|
#ifndef SERVER
|
||||||
Client *ModApiBase::getClient(lua_State *L)
|
Client *ModApiBase::getClient(lua_State *L)
|
||||||
{
|
{
|
||||||
|
@ -38,12 +38,14 @@ class GUIEngine;
|
|||||||
class ScriptApiBase;
|
class ScriptApiBase;
|
||||||
class Server;
|
class Server;
|
||||||
class Environment;
|
class Environment;
|
||||||
|
class ServerInventoryManager;
|
||||||
|
|
||||||
class ModApiBase : protected LuaHelper {
|
class ModApiBase : protected LuaHelper {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ScriptApiBase* getScriptApiBase(lua_State *L);
|
static ScriptApiBase* getScriptApiBase(lua_State *L);
|
||||||
static Server* getServer(lua_State *L);
|
static Server* getServer(lua_State *L);
|
||||||
|
static ServerInventoryManager *getServerInventoryMgr(lua_State *L);
|
||||||
#ifndef SERVER
|
#ifndef SERVER
|
||||||
static Client* getClient(lua_State *L);
|
static Client* getClient(lua_State *L);
|
||||||
static GUIEngine* getGuiEngine(lua_State *L);
|
static GUIEngine* getGuiEngine(lua_State *L);
|
||||||
|
@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "common/c_converter.h"
|
#include "common/c_converter.h"
|
||||||
#include "common/c_content.h"
|
#include "common/c_content.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
#include "server/serverinventorymgr.h"
|
||||||
#include "remoteplayer.h"
|
#include "remoteplayer.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -38,7 +39,7 @@ InvRef* InvRef::checkobject(lua_State *L, int narg)
|
|||||||
|
|
||||||
Inventory* InvRef::getinv(lua_State *L, InvRef *ref)
|
Inventory* InvRef::getinv(lua_State *L, InvRef *ref)
|
||||||
{
|
{
|
||||||
return getServer(L)->getInventory(ref->m_loc);
|
return getServerInventoryMgr(L)->getInventory(ref->m_loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
|
InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
|
||||||
@ -54,7 +55,7 @@ InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
|
|||||||
void InvRef::reportInventoryChange(lua_State *L, InvRef *ref)
|
void InvRef::reportInventoryChange(lua_State *L, InvRef *ref)
|
||||||
{
|
{
|
||||||
// Inform other things that the inventory has changed
|
// Inform other things that the inventory has changed
|
||||||
getServer(L)->setInventoryModified(ref->m_loc);
|
getServerInventoryMgr(L)->setInventoryModified(ref->m_loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exported functions
|
// Exported functions
|
||||||
@ -497,7 +498,7 @@ int ModApiInventory::l_get_inventory(lua_State *L)
|
|||||||
v3s16 pos = check_v3s16(L, -1);
|
v3s16 pos = check_v3s16(L, -1);
|
||||||
loc.setNodeMeta(pos);
|
loc.setNodeMeta(pos);
|
||||||
|
|
||||||
if (getServer(L)->getInventory(loc) != NULL)
|
if (getServerInventoryMgr(L)->getInventory(loc) != NULL)
|
||||||
InvRef::create(L, loc);
|
InvRef::create(L, loc);
|
||||||
else
|
else
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
@ -515,7 +516,7 @@ int ModApiInventory::l_get_inventory(lua_State *L)
|
|||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getServer(L)->getInventory(loc) != NULL)
|
if (getServerInventoryMgr(L)->getInventory(loc) != NULL)
|
||||||
InvRef::create(L, loc);
|
InvRef::create(L, loc);
|
||||||
else
|
else
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
@ -530,7 +531,7 @@ int ModApiInventory::l_create_detached_inventory_raw(lua_State *L)
|
|||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
const char *name = luaL_checkstring(L, 1);
|
const char *name = luaL_checkstring(L, 1);
|
||||||
std::string player = readParam<std::string>(L, 2, "");
|
std::string player = readParam<std::string>(L, 2, "");
|
||||||
if (getServer(L)->createDetachedInventory(name, player) != NULL) {
|
if (getServerInventoryMgr(L)->createDetachedInventory(name, getServer(L)->idef(), player) != NULL) {
|
||||||
InventoryLocation loc;
|
InventoryLocation loc;
|
||||||
loc.setDetached(name);
|
loc.setDetached(name);
|
||||||
InvRef::create(L, loc);
|
InvRef::create(L, loc);
|
||||||
@ -545,7 +546,7 @@ int ModApiInventory::l_remove_detached_inventory_raw(lua_State *L)
|
|||||||
{
|
{
|
||||||
NO_MAP_LOCK_REQUIRED;
|
NO_MAP_LOCK_REQUIRED;
|
||||||
const std::string &name = luaL_checkstring(L, 1);
|
const std::string &name = luaL_checkstring(L, 1);
|
||||||
lua_pushboolean(L, getServer(L)->removeDetachedInventory(name));
|
lua_pushboolean(L, getServerInventoryMgr(L)->removeDetachedInventory(name));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "scripting_server.h"
|
#include "scripting_server.h"
|
||||||
#include "server/luaentity_sao.h"
|
#include "server/luaentity_sao.h"
|
||||||
#include "server/player_sao.h"
|
#include "server/player_sao.h"
|
||||||
|
#include "server/serverinventorymgr.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ObjectRef
|
ObjectRef
|
||||||
@ -289,7 +290,7 @@ int ObjectRef::l_get_inventory(lua_State *L)
|
|||||||
if (co == NULL) return 0;
|
if (co == NULL) return 0;
|
||||||
// Do it
|
// Do it
|
||||||
InventoryLocation loc = co->getInventoryLocation();
|
InventoryLocation loc = co->getInventoryLocation();
|
||||||
if (getServer(L)->getInventory(loc) != NULL)
|
if (getServerInventoryMgr(L)->getInventory(loc) != NULL)
|
||||||
InvRef::create(L, loc);
|
InvRef::create(L, loc);
|
||||||
else
|
else
|
||||||
lua_pushnil(L); // An object may have no inventory (nil)
|
lua_pushnil(L); // An object may have no inventory (nil)
|
||||||
@ -2172,9 +2173,7 @@ int ObjectRef::l_override_day_night_ratio(lua_State *L)
|
|||||||
ratio = readParam<float>(L, 2);
|
ratio = readParam<float>(L, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getServer(L)->overrideDayNightRatio(player, do_override, ratio))
|
getServer(L)->overrideDayNightRatio(player, do_override, ratio);
|
||||||
return 0;
|
|
||||||
|
|
||||||
lua_pushboolean(L, true);
|
lua_pushboolean(L, true);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
190
src/server.cpp
190
src/server.cpp
@ -64,6 +64,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "chat_interface.h"
|
#include "chat_interface.h"
|
||||||
#include "remoteplayer.h"
|
#include "remoteplayer.h"
|
||||||
#include "server/player_sao.h"
|
#include "server/player_sao.h"
|
||||||
|
#include "server/serverinventorymgr.h"
|
||||||
#include "translation.h"
|
#include "translation.h"
|
||||||
|
|
||||||
class ClientNotFoundException : public BaseException
|
class ClientNotFoundException : public BaseException
|
||||||
@ -338,11 +339,6 @@ Server::~Server()
|
|||||||
infostream << "Server: Deinitializing scripting" << std::endl;
|
infostream << "Server: Deinitializing scripting" << std::endl;
|
||||||
delete m_script;
|
delete m_script;
|
||||||
|
|
||||||
// Delete detached inventories
|
|
||||||
for (auto &detached_inventory : m_detached_inventories) {
|
|
||||||
delete detached_inventory.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!m_unsent_map_edit_queue.empty()) {
|
while (!m_unsent_map_edit_queue.empty()) {
|
||||||
delete m_unsent_map_edit_queue.front();
|
delete m_unsent_map_edit_queue.front();
|
||||||
m_unsent_map_edit_queue.pop();
|
m_unsent_map_edit_queue.pop();
|
||||||
@ -388,6 +384,9 @@ void Server::init()
|
|||||||
|
|
||||||
m_script = new ServerScripting(this);
|
m_script = new ServerScripting(this);
|
||||||
|
|
||||||
|
// Must be created before mod loading because we have some inventory creation
|
||||||
|
m_inventory_mgr = std::unique_ptr<ServerInventoryManager>(new ServerInventoryManager());
|
||||||
|
|
||||||
m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
|
m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
|
||||||
|
|
||||||
m_modmgr->loadMods(m_script);
|
m_modmgr->loadMods(m_script);
|
||||||
@ -422,6 +421,7 @@ void Server::init()
|
|||||||
// Initialize Environment
|
// Initialize Environment
|
||||||
m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
|
m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
|
||||||
|
|
||||||
|
m_inventory_mgr->setEnv(m_env);
|
||||||
m_clients.setEnv(m_env);
|
m_clients.setEnv(m_env);
|
||||||
|
|
||||||
if (!servermap->settings_mgr.makeMapgenParams())
|
if (!servermap->settings_mgr.makeMapgenParams())
|
||||||
@ -443,6 +443,8 @@ void Server::init()
|
|||||||
|
|
||||||
m_env->loadMeta();
|
m_env->loadMeta();
|
||||||
|
|
||||||
|
// Those settings can be overwritten in world.mt, they are
|
||||||
|
// intended to be cached after environment loading.
|
||||||
m_liquid_transform_every = g_settings->getFloat("liquid_update");
|
m_liquid_transform_every = g_settings->getFloat("liquid_update");
|
||||||
m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
|
m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
|
||||||
m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
|
m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
|
||||||
@ -451,6 +453,8 @@ void Server::init()
|
|||||||
|
|
||||||
void Server::start()
|
void Server::start()
|
||||||
{
|
{
|
||||||
|
init();
|
||||||
|
|
||||||
infostream << "Starting server on " << m_bind_addr.serializeString()
|
infostream << "Starting server on " << m_bind_addr.serializeString()
|
||||||
<< "..." << std::endl;
|
<< "..." << std::endl;
|
||||||
|
|
||||||
@ -1180,82 +1184,6 @@ void Server::onMapEditEvent(const MapEditEvent &event)
|
|||||||
m_unsent_map_edit_queue.push(new MapEditEvent(event));
|
m_unsent_map_edit_queue.push(new MapEditEvent(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
Inventory* Server::getInventory(const InventoryLocation &loc)
|
|
||||||
{
|
|
||||||
switch (loc.type) {
|
|
||||||
case InventoryLocation::UNDEFINED:
|
|
||||||
case InventoryLocation::CURRENT_PLAYER:
|
|
||||||
break;
|
|
||||||
case InventoryLocation::PLAYER:
|
|
||||||
{
|
|
||||||
RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
|
|
||||||
if(!player)
|
|
||||||
return NULL;
|
|
||||||
PlayerSAO *playersao = player->getPlayerSAO();
|
|
||||||
if(!playersao)
|
|
||||||
return NULL;
|
|
||||||
return playersao->getInventory();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case InventoryLocation::NODEMETA:
|
|
||||||
{
|
|
||||||
NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
|
|
||||||
if(!meta)
|
|
||||||
return NULL;
|
|
||||||
return meta->getInventory();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case InventoryLocation::DETACHED:
|
|
||||||
{
|
|
||||||
if(m_detached_inventories.count(loc.name) == 0)
|
|
||||||
return NULL;
|
|
||||||
return m_detached_inventories[loc.name];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sanity_check(false); // abort
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::setInventoryModified(const InventoryLocation &loc)
|
|
||||||
{
|
|
||||||
switch(loc.type){
|
|
||||||
case InventoryLocation::UNDEFINED:
|
|
||||||
break;
|
|
||||||
case InventoryLocation::PLAYER:
|
|
||||||
{
|
|
||||||
|
|
||||||
RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
|
|
||||||
|
|
||||||
if (!player)
|
|
||||||
return;
|
|
||||||
|
|
||||||
player->setModified(true);
|
|
||||||
player->inventory.setModified(true);
|
|
||||||
// Updates are sent in ServerEnvironment::step()
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case InventoryLocation::NODEMETA:
|
|
||||||
{
|
|
||||||
MapEditEvent event;
|
|
||||||
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
|
|
||||||
event.p = loc.p;
|
|
||||||
m_env->getMap().dispatchEvent(event);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case InventoryLocation::DETACHED:
|
|
||||||
{
|
|
||||||
// Updates are sent in ServerEnvironment::step()
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sanity_check(false); // abort
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
|
void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
|
||||||
{
|
{
|
||||||
std::vector<session_t> clients = m_clients.getClientIDs();
|
std::vector<session_t> clients = m_clients.getClientIDs();
|
||||||
@ -2712,40 +2640,20 @@ void Server::sendRequestedMedia(session_t peer_id,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
|
void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
|
||||||
{
|
{
|
||||||
const auto &inv_it = m_detached_inventories.find(name);
|
|
||||||
const auto &player_it = m_detached_inventories_player.find(name);
|
|
||||||
|
|
||||||
if (player_it == m_detached_inventories_player.end() ||
|
|
||||||
player_it->second.empty()) {
|
|
||||||
// OK. Send to everyone
|
|
||||||
} else {
|
|
||||||
if (!m_env)
|
|
||||||
return; // Mods are not done loading
|
|
||||||
|
|
||||||
RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
|
|
||||||
if (!p)
|
|
||||||
return; // Player is offline
|
|
||||||
|
|
||||||
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);
|
NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
|
||||||
pkt << name;
|
pkt << name;
|
||||||
|
|
||||||
if (inv_it == m_detached_inventories.end()) {
|
if (!inventory) {
|
||||||
pkt << false; // Remove inventory
|
pkt << false; // Remove inventory
|
||||||
} else {
|
} else {
|
||||||
pkt << true; // Update inventory
|
pkt << true; // Update inventory
|
||||||
|
|
||||||
// Serialization & NetworkPacket isn't a love story
|
// Serialization & NetworkPacket isn't a love story
|
||||||
std::ostringstream os(std::ios_base::binary);
|
std::ostringstream os(std::ios_base::binary);
|
||||||
inv_it->second->serialize(os);
|
inventory->serialize(os);
|
||||||
inv_it->second->setModified(false);
|
inventory->setModified(false);
|
||||||
|
|
||||||
const std::string &os_str = os.str();
|
const std::string &os_str = os.str();
|
||||||
pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
|
pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
|
||||||
@ -2760,16 +2668,17 @@ void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
|
|||||||
|
|
||||||
void Server::sendDetachedInventories(session_t peer_id, bool incremental)
|
void Server::sendDetachedInventories(session_t peer_id, bool incremental)
|
||||||
{
|
{
|
||||||
for (const auto &detached_inventory : m_detached_inventories) {
|
// Lookup player name, to filter detached inventories just after
|
||||||
const std::string &name = detached_inventory.first;
|
std::string peer_name;
|
||||||
if (incremental) {
|
if (peer_id != PEER_ID_INEXISTENT) {
|
||||||
Inventory *inv = detached_inventory.second;
|
peer_name = getClient(peer_id, CS_Created)->getName();
|
||||||
if (!inv || !inv->checkModified())
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sendDetachedInventory(name, peer_id);
|
auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
|
||||||
}
|
sendDetachedInventory(inv, name, peer_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3442,15 +3351,12 @@ void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
|
|||||||
SendCloudParams(player->getPeerId(), params);
|
SendCloudParams(player->getPeerId(), params);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
|
void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
|
||||||
float ratio)
|
float ratio)
|
||||||
{
|
{
|
||||||
if (!player)
|
sanity_check(player);
|
||||||
return false;
|
|
||||||
|
|
||||||
player->overrideDayNightRatio(do_override, ratio);
|
player->overrideDayNightRatio(do_override, ratio);
|
||||||
SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
|
SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::notifyPlayers(const std::wstring &msg)
|
void Server::notifyPlayers(const std::wstring &msg)
|
||||||
@ -3541,52 +3447,6 @@ void Server::deleteParticleSpawner(const std::string &playername, u32 id)
|
|||||||
SendDeleteParticleSpawner(peer_id, id);
|
SendDeleteParticleSpawner(peer_id, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
|
|
||||||
{
|
|
||||||
if(m_detached_inventories.count(name) > 0){
|
|
||||||
infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
|
|
||||||
delete m_detached_inventories[name];
|
|
||||||
} else {
|
|
||||||
infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
|
|
||||||
}
|
|
||||||
Inventory *inv = new Inventory(m_itemdef);
|
|
||||||
sanity_check(inv);
|
|
||||||
m_detached_inventories[name] = inv;
|
|
||||||
if (!player.empty())
|
|
||||||
m_detached_inventories_player[name] = player;
|
|
||||||
|
|
||||||
//TODO find a better way to do this
|
|
||||||
sendDetachedInventory(name,PEER_ID_INEXISTENT);
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (!m_env) // Mods are not done loading
|
|
||||||
return true;
|
|
||||||
|
|
||||||
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
|
// actions: time-reversed list
|
||||||
// Return value: success/failure
|
// Return value: success/failure
|
||||||
bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
|
bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
|
||||||
@ -3607,7 +3467,7 @@ bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
|
|||||||
|
|
||||||
for (const RollbackAction &action : actions) {
|
for (const RollbackAction &action : actions) {
|
||||||
num_tried++;
|
num_tried++;
|
||||||
bool success = action.applyRevert(map, this, this);
|
bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
|
||||||
if(!success){
|
if(!success){
|
||||||
num_failed++;
|
num_failed++;
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
|
33
src/server.h
33
src/server.h
@ -68,6 +68,7 @@ struct MoonParams;
|
|||||||
struct StarParams;
|
struct StarParams;
|
||||||
class ServerThread;
|
class ServerThread;
|
||||||
class ServerModManager;
|
class ServerModManager;
|
||||||
|
class ServerInventoryManager;
|
||||||
|
|
||||||
enum ClientDeletionReason {
|
enum ClientDeletionReason {
|
||||||
CDR_LEAVE,
|
CDR_LEAVE,
|
||||||
@ -116,7 +117,7 @@ struct ServerPlayingSound
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Server : public con::PeerHandler, public MapEventReceiver,
|
class Server : public con::PeerHandler, public MapEventReceiver,
|
||||||
public InventoryManager, public IGameDef
|
public IGameDef
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*
|
/*
|
||||||
@ -134,7 +135,6 @@ public:
|
|||||||
~Server();
|
~Server();
|
||||||
DISABLE_CLASS_COPY(Server);
|
DISABLE_CLASS_COPY(Server);
|
||||||
|
|
||||||
void init();
|
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
// This is mainly a way to pass the time to the server.
|
// This is mainly a way to pass the time to the server.
|
||||||
@ -196,12 +196,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void onMapEditEvent(const MapEditEvent &event);
|
void onMapEditEvent(const MapEditEvent &event);
|
||||||
|
|
||||||
/*
|
|
||||||
Shall be called with the environment and the connection locked.
|
|
||||||
*/
|
|
||||||
Inventory* getInventory(const InventoryLocation &loc);
|
|
||||||
void setInventoryModified(const InventoryLocation &loc);
|
|
||||||
|
|
||||||
// Connection must be locked when called
|
// Connection must be locked when called
|
||||||
std::wstring getStatusString();
|
std::wstring getStatusString();
|
||||||
inline double getUptime() const { return m_uptime_counter->get(); }
|
inline double getUptime() const { return m_uptime_counter->get(); }
|
||||||
@ -253,10 +247,8 @@ public:
|
|||||||
|
|
||||||
void deleteParticleSpawner(const std::string &playername, u32 id);
|
void deleteParticleSpawner(const std::string &playername, u32 id);
|
||||||
|
|
||||||
// Creates or resets inventory
|
ServerInventoryManager *getInventoryMgr() const { return m_inventory_mgr.get(); }
|
||||||
Inventory *createDetachedInventory(const std::string &name,
|
void sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id);
|
||||||
const std::string &player = "");
|
|
||||||
bool removeDetachedInventory(const std::string &name);
|
|
||||||
|
|
||||||
// Envlock and conlock should be locked when using scriptapi
|
// Envlock and conlock should be locked when using scriptapi
|
||||||
ServerScripting *getScriptIface(){ return m_script; }
|
ServerScripting *getScriptIface(){ return m_script; }
|
||||||
@ -318,7 +310,7 @@ public:
|
|||||||
|
|
||||||
void setClouds(RemotePlayer *player, const CloudParams ¶ms);
|
void setClouds(RemotePlayer *player, const CloudParams ¶ms);
|
||||||
|
|
||||||
bool overrideDayNightRatio(RemotePlayer *player, bool do_override, float brightness);
|
void overrideDayNightRatio(RemotePlayer *player, bool do_override, float brightness);
|
||||||
|
|
||||||
/* con::PeerHandler implementation. */
|
/* con::PeerHandler implementation. */
|
||||||
void peerAdded(con::Peer *peer);
|
void peerAdded(con::Peer *peer);
|
||||||
@ -389,6 +381,8 @@ private:
|
|||||||
float m_timer = 0.0f;
|
float m_timer = 0.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
void SendMovement(session_t peer_id);
|
void SendMovement(session_t peer_id);
|
||||||
void SendHP(session_t peer_id, u16 hp);
|
void SendHP(session_t peer_id, u16 hp);
|
||||||
void SendBreath(session_t peer_id, u16 breath);
|
void SendBreath(session_t peer_id, u16 breath);
|
||||||
@ -457,8 +451,6 @@ private:
|
|||||||
void sendRequestedMedia(session_t peer_id,
|
void sendRequestedMedia(session_t peer_id,
|
||||||
const std::vector<std::string> &tosend);
|
const std::vector<std::string> &tosend);
|
||||||
|
|
||||||
void sendDetachedInventory(const std::string &name, session_t peer_id);
|
|
||||||
|
|
||||||
// Adds a ParticleSpawner on peer with peer_id (PEER_ID_INEXISTENT == all)
|
// Adds a ParticleSpawner on peer with peer_id (PEER_ID_INEXISTENT == all)
|
||||||
void SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
|
void SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
|
||||||
u16 amount, float spawntime,
|
u16 amount, float spawntime,
|
||||||
@ -656,14 +648,6 @@ private:
|
|||||||
s32 m_next_sound_id = 0; // positive values only
|
s32 m_next_sound_id = 0; // positive values only
|
||||||
s32 nextSoundId();
|
s32 nextSoundId();
|
||||||
|
|
||||||
/*
|
|
||||||
Detached inventories (behind m_env_mutex)
|
|
||||||
*/
|
|
||||||
// key = name
|
|
||||||
std::map<std::string, Inventory*> m_detached_inventories;
|
|
||||||
// value = "" (visible to all players) or player name
|
|
||||||
std::map<std::string, std::string> m_detached_inventories_player;
|
|
||||||
|
|
||||||
std::unordered_map<std::string, ModMetadata *> m_mod_storages;
|
std::unordered_map<std::string, ModMetadata *> m_mod_storages;
|
||||||
float m_mod_storage_save_timer = 10.0f;
|
float m_mod_storage_save_timer = 10.0f;
|
||||||
|
|
||||||
@ -674,6 +658,9 @@ private:
|
|||||||
// ModChannel manager
|
// ModChannel manager
|
||||||
std::unique_ptr<ModChannelMgr> m_modchannel_mgr;
|
std::unique_ptr<ModChannelMgr> m_modchannel_mgr;
|
||||||
|
|
||||||
|
// Inventory manager
|
||||||
|
std::unique_ptr<ServerInventoryManager> m_inventory_mgr;
|
||||||
|
|
||||||
// Global server metrics backend
|
// Global server metrics backend
|
||||||
std::unique_ptr<MetricsBackend> m_metrics_backend;
|
std::unique_ptr<MetricsBackend> m_metrics_backend;
|
||||||
|
|
||||||
|
@ -4,5 +4,6 @@ set(server_SRCS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/mods.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/mods.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/player_sao.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/player_sao.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/serveractiveobject.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/serveractiveobject.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/serverinventorymgr.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/unit_sao.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/unit_sao.cpp
|
||||||
PARENT_SCOPE)
|
PARENT_SCOPE)
|
||||||
|
192
src/server/serverinventorymgr.cpp
Normal file
192
src/server/serverinventorymgr.cpp
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2010-2020 Minetest core development team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "serverinventorymgr.h"
|
||||||
|
#include "map.h"
|
||||||
|
#include "nodemetadata.h"
|
||||||
|
#include "player_sao.h"
|
||||||
|
#include "remoteplayer.h"
|
||||||
|
#include "server.h"
|
||||||
|
#include "serverenvironment.h"
|
||||||
|
|
||||||
|
ServerInventoryManager::ServerInventoryManager() : InventoryManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInventoryManager::~ServerInventoryManager()
|
||||||
|
{
|
||||||
|
// Delete detached inventories
|
||||||
|
for (auto &detached_inventory : m_detached_inventories) {
|
||||||
|
delete detached_inventory.second.inventory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Inventory *ServerInventoryManager::getInventory(const InventoryLocation &loc)
|
||||||
|
{
|
||||||
|
switch (loc.type) {
|
||||||
|
case InventoryLocation::UNDEFINED:
|
||||||
|
case InventoryLocation::CURRENT_PLAYER:
|
||||||
|
break;
|
||||||
|
case InventoryLocation::PLAYER: {
|
||||||
|
RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
|
||||||
|
if (!player)
|
||||||
|
return NULL;
|
||||||
|
PlayerSAO *playersao = player->getPlayerSAO();
|
||||||
|
if (!playersao)
|
||||||
|
return NULL;
|
||||||
|
return playersao->getInventory();
|
||||||
|
} break;
|
||||||
|
case InventoryLocation::NODEMETA: {
|
||||||
|
NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
|
||||||
|
if (!meta)
|
||||||
|
return NULL;
|
||||||
|
return meta->getInventory();
|
||||||
|
} break;
|
||||||
|
case InventoryLocation::DETACHED: {
|
||||||
|
auto it = m_detached_inventories.find(loc.name);
|
||||||
|
if (it == m_detached_inventories.end())
|
||||||
|
return nullptr;
|
||||||
|
return it->second.inventory;
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
sanity_check(false); // abort
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerInventoryManager::setInventoryModified(const InventoryLocation &loc)
|
||||||
|
{
|
||||||
|
switch (loc.type) {
|
||||||
|
case InventoryLocation::UNDEFINED:
|
||||||
|
break;
|
||||||
|
case InventoryLocation::PLAYER: {
|
||||||
|
|
||||||
|
RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
|
||||||
|
|
||||||
|
if (!player)
|
||||||
|
return;
|
||||||
|
|
||||||
|
player->setModified(true);
|
||||||
|
player->inventory.setModified(true);
|
||||||
|
// Updates are sent in ServerEnvironment::step()
|
||||||
|
} break;
|
||||||
|
case InventoryLocation::NODEMETA: {
|
||||||
|
MapEditEvent event;
|
||||||
|
event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
|
||||||
|
event.p = loc.p;
|
||||||
|
m_env->getMap().dispatchEvent(event);
|
||||||
|
} break;
|
||||||
|
case InventoryLocation::DETACHED: {
|
||||||
|
// Updates are sent in ServerEnvironment::step()
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
sanity_check(false); // abort
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Inventory *ServerInventoryManager::createDetachedInventory(
|
||||||
|
const std::string &name, IItemDefManager *idef, const std::string &player)
|
||||||
|
{
|
||||||
|
if (m_detached_inventories.count(name) > 0) {
|
||||||
|
infostream << "Server clearing detached inventory \"" << name << "\""
|
||||||
|
<< std::endl;
|
||||||
|
delete m_detached_inventories[name].inventory;
|
||||||
|
} else {
|
||||||
|
infostream << "Server creating detached inventory \"" << name << "\""
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inventory *inv = new Inventory(idef);
|
||||||
|
sanity_check(inv);
|
||||||
|
m_detached_inventories[name].inventory = inv;
|
||||||
|
if (!player.empty()) {
|
||||||
|
m_detached_inventories[name].owner = player;
|
||||||
|
|
||||||
|
if (!m_env)
|
||||||
|
return inv; // Mods are not loaded yet, ignore
|
||||||
|
|
||||||
|
RemotePlayer *p = m_env->getPlayer(name.c_str());
|
||||||
|
|
||||||
|
// if player is connected, send him the inventory
|
||||||
|
if (p && p->getPeerId() != PEER_ID_INEXISTENT) {
|
||||||
|
m_env->getGameDef()->sendDetachedInventory(
|
||||||
|
inv, name, p->getPeerId());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!m_env)
|
||||||
|
return inv; // Mods are not loaded yet, don't send
|
||||||
|
|
||||||
|
// Inventory is for everybody, broadcast
|
||||||
|
m_env->getGameDef()->sendDetachedInventory(inv, name, PEER_ID_INEXISTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return inv;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ServerInventoryManager::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.inventory;
|
||||||
|
const std::string &owner = inv_it->second.owner;
|
||||||
|
|
||||||
|
if (!owner.empty()) {
|
||||||
|
RemotePlayer *player = m_env->getPlayer(owner.c_str());
|
||||||
|
|
||||||
|
if (player && player->getPeerId() != PEER_ID_INEXISTENT)
|
||||||
|
m_env->getGameDef()->sendDetachedInventory(
|
||||||
|
nullptr, name, player->getPeerId());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Notify all players about the change
|
||||||
|
m_env->getGameDef()->sendDetachedInventory(
|
||||||
|
nullptr, name, PEER_ID_INEXISTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_detached_inventories.erase(inv_it);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerInventoryManager::sendDetachedInventories(const std::string &peer_name,
|
||||||
|
bool incremental,
|
||||||
|
std::function<void(const std::string &, Inventory *)> apply_cb)
|
||||||
|
{
|
||||||
|
for (const auto &detached_inventory : m_detached_inventories) {
|
||||||
|
const DetachedInventory &dinv = detached_inventory.second;
|
||||||
|
if (incremental) {
|
||||||
|
if (!dinv.inventory || !dinv.inventory->checkModified())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are pushing inventories to a specific player
|
||||||
|
// we should filter to send only the right inventories
|
||||||
|
if (!peer_name.empty()) {
|
||||||
|
const std::string &attached_player = dinv.owner;
|
||||||
|
if (!attached_player.empty() && peer_name != attached_player)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_cb(detached_inventory.first, detached_inventory.second.inventory);
|
||||||
|
}
|
||||||
|
}
|
60
src/server/serverinventorymgr.h
Normal file
60
src/server/serverinventorymgr.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2010-2020 Minetest core development team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "inventorymanager.h"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
class ServerEnvironment;
|
||||||
|
|
||||||
|
class ServerInventoryManager : public InventoryManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ServerInventoryManager();
|
||||||
|
virtual ~ServerInventoryManager();
|
||||||
|
|
||||||
|
void setEnv(ServerEnvironment *env)
|
||||||
|
{
|
||||||
|
assert(!m_env);
|
||||||
|
m_env = env;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inventory *getInventory(const InventoryLocation &loc);
|
||||||
|
void setInventoryModified(const InventoryLocation &loc);
|
||||||
|
|
||||||
|
// Creates or resets inventory
|
||||||
|
Inventory *createDetachedInventory(const std::string &name, IItemDefManager *idef,
|
||||||
|
const std::string &player = "");
|
||||||
|
bool removeDetachedInventory(const std::string &name);
|
||||||
|
|
||||||
|
void sendDetachedInventories(const std::string &peer_name, bool incremental,
|
||||||
|
std::function<void(const std::string &, Inventory *)> apply_cb);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct DetachedInventory
|
||||||
|
{
|
||||||
|
Inventory *inventory;
|
||||||
|
std::string owner;
|
||||||
|
};
|
||||||
|
|
||||||
|
ServerEnvironment *m_env = nullptr;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, DetachedInventory> m_detached_inventories;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user