mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
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
12 changed files with 312 additions and 207 deletions
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);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue