LCOV - code coverage report
Current view: top level - src - server.cpp (source / functions) Hit Total Coverage
Test: report Lines: 3 1803 0.2 %
Date: 2015-07-11 18:23:49 Functions: 3 146 2.1 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       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 "server.h"
      21             : #include <iostream>
      22             : #include <queue>
      23             : #include <algorithm>
      24             : #include "network/networkprotocol.h"
      25             : #include "network/serveropcodes.h"
      26             : #include "ban.h"
      27             : #include "environment.h"
      28             : #include "map.h"
      29             : #include "jthread/jmutexautolock.h"
      30             : #include "constants.h"
      31             : #include "voxel.h"
      32             : #include "config.h"
      33             : #include "version.h"
      34             : #include "filesys.h"
      35             : #include "mapblock.h"
      36             : #include "serverobject.h"
      37             : #include "genericobject.h"
      38             : #include "settings.h"
      39             : #include "profiler.h"
      40             : #include "log.h"
      41             : #include "scripting_game.h"
      42             : #include "nodedef.h"
      43             : #include "itemdef.h"
      44             : #include "craftdef.h"
      45             : #include "emerge.h"
      46             : #include "mapgen.h"
      47             : #include "mg_biome.h"
      48             : #include "content_mapnode.h"
      49             : #include "content_nodemeta.h"
      50             : #include "content_abm.h"
      51             : #include "content_sao.h"
      52             : #include "mods.h"
      53             : #include "sound.h" // dummySoundManager
      54             : #include "event_manager.h"
      55             : #include "serverlist.h"
      56             : #include "util/string.h"
      57             : #include "util/mathconstants.h"
      58             : #include "rollback.h"
      59             : #include "util/serialize.h"
      60             : #include "util/thread.h"
      61             : #include "defaultsettings.h"
      62             : #include "util/base64.h"
      63             : #include "util/sha1.h"
      64             : #include "util/hex.h"
      65             : 
      66           0 : class ClientNotFoundException : public BaseException
      67             : {
      68             : public:
      69           0 :         ClientNotFoundException(const char *s):
      70           0 :                 BaseException(s)
      71           0 :         {}
      72             : };
      73             : 
      74           0 : class ServerThread : public JThread
      75             : {
      76             :         Server *m_server;
      77             : 
      78             : public:
      79             : 
      80           0 :         ServerThread(Server *server):
      81             :                 JThread(),
      82           0 :                 m_server(server)
      83             :         {
      84           0 :         }
      85             : 
      86             :         void * Thread();
      87             : };
      88             : 
      89           0 : void * ServerThread::Thread()
      90             : {
      91           0 :         log_register_thread("ServerThread");
      92             : 
      93           0 :         DSTACK(__FUNCTION_NAME);
      94             :         BEGIN_DEBUG_EXCEPTION_HANDLER
      95             : 
      96           0 :         m_server->AsyncRunStep(true);
      97             : 
      98           0 :         ThreadStarted();
      99             : 
     100           0 :         porting::setThreadName("ServerThread");
     101             : 
     102           0 :         while(!StopRequested())
     103             :         {
     104             :                 try{
     105             :                         //TimeTaker timer("AsyncRunStep() + Receive()");
     106             : 
     107           0 :                         m_server->AsyncRunStep();
     108             : 
     109           0 :                         m_server->Receive();
     110             : 
     111             :                 }
     112           0 :                 catch(con::NoIncomingDataException &e)
     113             :                 {
     114             :                 }
     115           0 :                 catch(con::PeerNotFoundException &e)
     116             :                 {
     117           0 :                         infostream<<"Server: PeerNotFoundException"<<std::endl;
     118             :                 }
     119           0 :                 catch(ClientNotFoundException &e)
     120             :                 {
     121             :                 }
     122           0 :                 catch(con::ConnectionBindFailed &e)
     123             :                 {
     124           0 :                         m_server->setAsyncFatalError(e.what());
     125             :                 }
     126           0 :                 catch(LuaError &e)
     127             :                 {
     128           0 :                         m_server->setAsyncFatalError(e.what());
     129             :                 }
     130             :         }
     131             : 
     132           0 :         END_DEBUG_EXCEPTION_HANDLER(errorstream)
     133             : 
     134           0 :         return NULL;
     135             : }
     136             : 
     137           0 : v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
     138             : {
     139           0 :         if(pos_exists) *pos_exists = false;
     140           0 :         switch(type){
     141             :         case SSP_LOCAL:
     142           0 :                 return v3f(0,0,0);
     143             :         case SSP_POSITIONAL:
     144           0 :                 if(pos_exists) *pos_exists = true;
     145           0 :                 return pos;
     146             :         case SSP_OBJECT: {
     147           0 :                 if(object == 0)
     148           0 :                         return v3f(0,0,0);
     149           0 :                 ServerActiveObject *sao = env->getActiveObject(object);
     150           0 :                 if(!sao)
     151           0 :                         return v3f(0,0,0);
     152           0 :                 if(pos_exists) *pos_exists = true;
     153           0 :                 return sao->getBasePosition(); }
     154             :         }
     155           0 :         return v3f(0,0,0);
     156             : }
     157             : 
     158             : 
     159             : 
     160             : /*
     161             :         Server
     162             : */
     163             : 
     164           0 : Server::Server(
     165             :                 const std::string &path_world,
     166             :                 const SubgameSpec &gamespec,
     167             :                 bool simple_singleplayer_mode,
     168             :                 bool ipv6
     169             :         ):
     170             :         m_path_world(path_world),
     171             :         m_gamespec(gamespec),
     172             :         m_simple_singleplayer_mode(simple_singleplayer_mode),
     173             :         m_async_fatal_error(""),
     174             :         m_env(NULL),
     175             :         m_con(PROTOCOL_ID,
     176             :                         512,
     177             :                         CONNECTION_TIMEOUT,
     178             :                         ipv6,
     179             :                         this),
     180             :         m_banmanager(NULL),
     181             :         m_rollback(NULL),
     182             :         m_enable_rollback_recording(false),
     183             :         m_emerge(NULL),
     184             :         m_script(NULL),
     185           0 :         m_itemdef(createItemDefManager()),
     186           0 :         m_nodedef(createNodeDefManager()),
     187           0 :         m_craftdef(createCraftDefManager()),
     188           0 :         m_event(new EventManager()),
     189             :         m_thread(NULL),
     190             :         m_time_of_day_send_timer(0),
     191             :         m_uptime(0),
     192             :         m_clients(&m_con),
     193             :         m_shutdown_requested(false),
     194             :         m_ignore_map_edit_events(false),
     195             :         m_ignore_map_edit_events_peer_id(0),
     196           0 :         m_next_sound_id(0)
     197             : 
     198             : {
     199           0 :         m_liquid_transform_timer = 0.0;
     200           0 :         m_liquid_transform_every = 1.0;
     201           0 :         m_print_info_timer = 0.0;
     202           0 :         m_masterserver_timer = 0.0;
     203           0 :         m_objectdata_timer = 0.0;
     204           0 :         m_emergethread_trigger_timer = 0.0;
     205           0 :         m_savemap_timer = 0.0;
     206             : 
     207           0 :         m_step_dtime = 0.0;
     208           0 :         m_lag = g_settings->getFloat("dedicated_server_step");
     209             : 
     210           0 :         if(path_world == "")
     211           0 :                 throw ServerError("Supplied empty world path");
     212             : 
     213           0 :         if(!gamespec.isValid())
     214           0 :                 throw ServerError("Supplied invalid gamespec");
     215             : 
     216           0 :         infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
     217           0 :         if(m_simple_singleplayer_mode)
     218           0 :                 infostream<<" in simple singleplayer mode"<<std::endl;
     219             :         else
     220           0 :                 infostream<<std::endl;
     221           0 :         infostream<<"- world:  "<<m_path_world<<std::endl;
     222           0 :         infostream<<"- game:   "<<m_gamespec.path<<std::endl;
     223             : 
     224             :         // Create world if it doesn't exist
     225           0 :         if(!loadGameConfAndInitWorld(m_path_world, m_gamespec))
     226           0 :                 throw ServerError("Failed to initialize world");
     227             : 
     228             :         // Create server thread
     229           0 :         m_thread = new ServerThread(this);
     230             : 
     231             :         // Create emerge manager
     232           0 :         m_emerge = new EmergeManager(this);
     233             : 
     234             :         // Create ban manager
     235           0 :         std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
     236           0 :         m_banmanager = new BanManager(ban_path);
     237             : 
     238           0 :         ModConfiguration modconf(m_path_world);
     239           0 :         m_mods = modconf.getMods();
     240           0 :         std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
     241             :         // complain about mods with unsatisfied dependencies
     242           0 :         if(!modconf.isConsistent()) {
     243           0 :                 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
     244           0 :                         it != unsatisfied_mods.end(); ++it) {
     245           0 :                         ModSpec mod = *it;
     246           0 :                         errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
     247           0 :                         for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
     248           0 :                                 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
     249           0 :                                 errorstream << " \"" << *dep_it << "\"";
     250           0 :                         errorstream << std::endl;
     251             :                 }
     252             :         }
     253             : 
     254           0 :         Settings worldmt_settings;
     255           0 :         std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
     256           0 :         worldmt_settings.readConfigFile(worldmt.c_str());
     257           0 :         std::vector<std::string> names = worldmt_settings.getNames();
     258           0 :         std::set<std::string> load_mod_names;
     259           0 :         for(std::vector<std::string>::iterator it = names.begin();
     260           0 :                 it != names.end(); ++it) {
     261           0 :                 std::string name = *it;
     262           0 :                 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
     263           0 :                         load_mod_names.insert(name.substr(9));
     264             :         }
     265             :         // complain about mods declared to be loaded, but not found
     266           0 :         for(std::vector<ModSpec>::iterator it = m_mods.begin();
     267           0 :                         it != m_mods.end(); ++it)
     268           0 :                 load_mod_names.erase((*it).name);
     269           0 :         for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
     270           0 :                         it != unsatisfied_mods.end(); ++it)
     271           0 :                 load_mod_names.erase((*it).name);
     272           0 :         if(!load_mod_names.empty()) {
     273           0 :                 errorstream << "The following mods could not be found:";
     274           0 :                 for(std::set<std::string>::iterator it = load_mod_names.begin();
     275           0 :                         it != load_mod_names.end(); ++it)
     276           0 :                         errorstream << " \"" << (*it) << "\"";
     277           0 :                 errorstream << std::endl;
     278             :         }
     279             : 
     280             :         // Lock environment
     281           0 :         JMutexAutoLock envlock(m_env_mutex);
     282             : 
     283             :         // Load mapgen params from Settings
     284           0 :         m_emerge->loadMapgenParams();
     285             : 
     286             :         // Create the Map (loads map_meta.txt, overriding configured mapgen params)
     287           0 :         ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
     288             : 
     289             :         // Initialize scripting
     290           0 :         infostream<<"Server: Initializing Lua"<<std::endl;
     291             : 
     292           0 :         m_script = new GameScripting(this);
     293             : 
     294           0 :         std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua";
     295           0 :         std::string error_msg;
     296             : 
     297           0 :         if (!m_script->loadMod(script_path, BUILTIN_MOD_NAME, &error_msg))
     298           0 :                 throw ModError("Failed to load and run " + script_path
     299           0 :                                 + "\nError from Lua:\n" + error_msg);
     300             : 
     301             :         // Print mods
     302           0 :         infostream << "Server: Loading mods: ";
     303           0 :         for(std::vector<ModSpec>::iterator i = m_mods.begin();
     304           0 :                         i != m_mods.end(); i++) {
     305           0 :                 const ModSpec &mod = *i;
     306           0 :                 infostream << mod.name << " ";
     307             :         }
     308           0 :         infostream << std::endl;
     309             :         // Load and run "mod" scripts
     310           0 :         for (std::vector<ModSpec>::iterator i = m_mods.begin();
     311           0 :                         i != m_mods.end(); i++) {
     312           0 :                 const ModSpec &mod = *i;
     313           0 :                 if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) {
     314           0 :                         std::ostringstream err;
     315           0 :                         err << "Error loading mod \"" << mod.name
     316           0 :                                         << "\": mod_name does not follow naming conventions: "
     317           0 :                                         << "Only chararacters [a-z0-9_] are allowed." << std::endl;
     318           0 :                         errorstream << err.str().c_str();
     319           0 :                         throw ModError(err.str());
     320             :                 }
     321           0 :                 std::string script_path = mod.path + DIR_DELIM "init.lua";
     322           0 :                 infostream << "  [" << padStringRight(mod.name, 12) << "] [\""
     323           0 :                                 << script_path << "\"]" << std::endl;
     324           0 :                 if (!m_script->loadMod(script_path, mod.name, &error_msg)) {
     325           0 :                         errorstream << "Server: Failed to load and run "
     326           0 :                                         << script_path << std::endl;
     327           0 :                         throw ModError("Failed to load and run " + script_path
     328           0 :                                         + "\nError from Lua:\n" + error_msg);
     329             :                 }
     330             :         }
     331             : 
     332             :         // Read Textures and calculate sha1 sums
     333           0 :         fillMediaCache();
     334             : 
     335             :         // Apply item aliases in the node definition manager
     336           0 :         m_nodedef->updateAliases(m_itemdef);
     337             : 
     338             :         // Apply texture overrides from texturepack/override.txt
     339           0 :         std::string texture_path = g_settings->get("texture_path");
     340           0 :         if (texture_path != "" && fs::IsDir(texture_path))
     341           0 :                 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
     342             : 
     343           0 :         m_nodedef->setNodeRegistrationStatus(true);
     344             : 
     345             :         // Perform pending node name resolutions
     346           0 :         m_nodedef->runNodeResolveCallbacks();
     347             : 
     348             :         // init the recipe hashes to speed up crafting
     349           0 :         m_craftdef->initHashes(this);
     350             : 
     351             :         // Initialize Environment
     352           0 :         m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
     353             : 
     354           0 :         m_clients.setEnv(m_env);
     355             : 
     356             :         // Initialize mapgens
     357           0 :         m_emerge->initMapgens();
     358             : 
     359           0 :         m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
     360           0 :         if (m_enable_rollback_recording) {
     361             :                 // Create rollback manager
     362           0 :                 m_rollback = new RollbackManager(m_path_world, this);
     363             :         }
     364             : 
     365             :         // Give environment reference to scripting api
     366           0 :         m_script->initializeEnvironment(m_env);
     367             : 
     368             :         // Register us to receive map edit events
     369           0 :         servermap->addEventReceiver(this);
     370             : 
     371             :         // If file exists, load environment metadata
     372           0 :         if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
     373             :         {
     374           0 :                 infostream<<"Server: Loading environment metadata"<<std::endl;
     375           0 :                 m_env->loadMeta();
     376             :         }
     377             : 
     378             :         // Add some test ActiveBlockModifiers to environment
     379           0 :         add_legacy_abms(m_env, m_nodedef);
     380             : 
     381           0 :         m_liquid_transform_every = g_settings->getFloat("liquid_update");
     382           0 : }
     383             : 
     384           0 : Server::~Server()
     385             : {
     386           0 :         infostream<<"Server destructing"<<std::endl;
     387             : 
     388             :         // Send shutdown message
     389           0 :         SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
     390             : 
     391             :         {
     392           0 :                 JMutexAutoLock envlock(m_env_mutex);
     393             : 
     394             :                 // Execute script shutdown hooks
     395           0 :                 m_script->on_shutdown();
     396             : 
     397           0 :                 infostream<<"Server: Saving players"<<std::endl;
     398           0 :                 m_env->saveLoadedPlayers();
     399             : 
     400           0 :                 infostream<<"Server: Saving environment metadata"<<std::endl;
     401           0 :                 m_env->saveMeta();
     402             :         }
     403             : 
     404             :         // Stop threads
     405           0 :         stop();
     406           0 :         delete m_thread;
     407             : 
     408             :         // stop all emerge threads before deleting players that may have
     409             :         // requested blocks to be emerged
     410           0 :         m_emerge->stopThreads();
     411             : 
     412             :         // Delete things in the reverse order of creation
     413           0 :         delete m_env;
     414             : 
     415             :         // N.B. the EmergeManager should be deleted after the Environment since Map
     416             :         // depends on EmergeManager to write its current params to the map meta
     417           0 :         delete m_emerge;
     418           0 :         delete m_rollback;
     419           0 :         delete m_banmanager;
     420           0 :         delete m_event;
     421           0 :         delete m_itemdef;
     422           0 :         delete m_nodedef;
     423           0 :         delete m_craftdef;
     424             : 
     425             :         // Deinitialize scripting
     426           0 :         infostream<<"Server: Deinitializing scripting"<<std::endl;
     427           0 :         delete m_script;
     428             : 
     429             :         // Delete detached inventories
     430           0 :         for (std::map<std::string, Inventory*>::iterator
     431           0 :                         i = m_detached_inventories.begin();
     432           0 :                         i != m_detached_inventories.end(); i++) {
     433           0 :                 delete i->second;
     434             :         }
     435           0 : }
     436             : 
     437           0 : void Server::start(Address bind_addr)
     438             : {
     439           0 :         DSTACK(__FUNCTION_NAME);
     440             : 
     441           0 :         m_bind_addr = bind_addr;
     442             : 
     443           0 :         infostream<<"Starting server on "
     444           0 :                         << bind_addr.serializeString() <<"..."<<std::endl;
     445             : 
     446             :         // Stop thread if already running
     447           0 :         m_thread->Stop();
     448             : 
     449             :         // Initialize connection
     450           0 :         m_con.SetTimeoutMs(30);
     451           0 :         m_con.Serve(bind_addr);
     452             : 
     453             :         // Start thread
     454           0 :         m_thread->Start();
     455             : 
     456             :         // ASCII art for the win!
     457             :         actionstream
     458           0 :         <<"        .__               __                   __   "<<std::endl
     459           0 :         <<"  _____ |__| ____   _____/  |_  ____   _______/  |_ "<<std::endl
     460           0 :         <<" /     \\|  |/    \\_/ __ \\   __\\/ __ \\ /  ___/\\   __\\"<<std::endl
     461           0 :         <<"|  Y Y  \\  |   |  \\  ___/|  | \\  ___/ \\___ \\  |  |  "<<std::endl
     462           0 :         <<"|__|_|  /__|___|  /\\___  >__|  \\___  >____  > |__|  "<<std::endl
     463           0 :         <<"      \\/        \\/     \\/          \\/     \\/        "<<std::endl;
     464           0 :         actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
     465           0 :         actionstream<<"Server for gameid=\""<<m_gamespec.id
     466           0 :                         <<"\" listening on "<<bind_addr.serializeString()<<":"
     467           0 :                         <<bind_addr.getPort() << "."<<std::endl;
     468           0 : }
     469             : 
     470           0 : void Server::stop()
     471             : {
     472           0 :         DSTACK(__FUNCTION_NAME);
     473             : 
     474           0 :         infostream<<"Server: Stopping and waiting threads"<<std::endl;
     475             : 
     476             :         // Stop threads (set run=false first so both start stopping)
     477           0 :         m_thread->Stop();
     478             :         //m_emergethread.setRun(false);
     479           0 :         m_thread->Wait();
     480             :         //m_emergethread.stop();
     481             : 
     482           0 :         infostream<<"Server: Threads stopped"<<std::endl;
     483           0 : }
     484             : 
     485           0 : void Server::step(float dtime)
     486             : {
     487           0 :         DSTACK(__FUNCTION_NAME);
     488             :         // Limit a bit
     489           0 :         if(dtime > 2.0)
     490           0 :                 dtime = 2.0;
     491             :         {
     492           0 :                 JMutexAutoLock lock(m_step_dtime_mutex);
     493           0 :                 m_step_dtime += dtime;
     494             :         }
     495             :         // Throw if fatal error occurred in thread
     496           0 :         std::string async_err = m_async_fatal_error.get();
     497           0 :         if(async_err != "") {
     498           0 :                 if (m_simple_singleplayer_mode) {
     499           0 :                         throw ServerError(async_err);
     500             :                 }
     501             :                 else {
     502           0 :                         errorstream << "UNRECOVERABLE error occurred. Stopping server. "
     503           0 :                                         << "Please fix the following error:" << std::endl
     504           0 :                                         << async_err << std::endl;
     505           0 :                         FATAL_ERROR(async_err.c_str());
     506             :                 }
     507             :         }
     508           0 : }
     509             : 
     510           0 : void Server::AsyncRunStep(bool initial_step)
     511             : {
     512           0 :         DSTACK(__FUNCTION_NAME);
     513             : 
     514           0 :         g_profiler->add("Server::AsyncRunStep (num)", 1);
     515             : 
     516             :         float dtime;
     517             :         {
     518           0 :                 JMutexAutoLock lock1(m_step_dtime_mutex);
     519           0 :                 dtime = m_step_dtime;
     520             :         }
     521             : 
     522             :         {
     523             :                 // Send blocks to clients
     524           0 :                 SendBlocks(dtime);
     525             :         }
     526             : 
     527           0 :         if((dtime < 0.001) && (initial_step == false))
     528           0 :                 return;
     529             : 
     530           0 :         g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
     531             : 
     532             :         //infostream<<"Server steps "<<dtime<<std::endl;
     533             :         //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
     534             : 
     535             :         {
     536           0 :                 JMutexAutoLock lock1(m_step_dtime_mutex);
     537           0 :                 m_step_dtime -= dtime;
     538             :         }
     539             : 
     540             :         /*
     541             :                 Update uptime
     542             :         */
     543             :         {
     544           0 :                 m_uptime.set(m_uptime.get() + dtime);
     545             :         }
     546             : 
     547           0 :         handlePeerChanges();
     548             : 
     549             :         /*
     550             :                 Update time of day and overall game time
     551             :         */
     552           0 :         m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
     553             : 
     554             :         /*
     555             :                 Send to clients at constant intervals
     556             :         */
     557             : 
     558           0 :         m_time_of_day_send_timer -= dtime;
     559           0 :         if(m_time_of_day_send_timer < 0.0) {
     560           0 :                 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
     561           0 :                 u16 time = m_env->getTimeOfDay();
     562           0 :                 float time_speed = g_settings->getFloat("time_speed");
     563           0 :                 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
     564             :         }
     565             : 
     566             :         {
     567           0 :                 JMutexAutoLock lock(m_env_mutex);
     568             :                 // Figure out and report maximum lag to environment
     569           0 :                 float max_lag = m_env->getMaxLagEstimate();
     570           0 :                 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
     571           0 :                 if(dtime > max_lag){
     572           0 :                         if(dtime > 0.1 && dtime > max_lag * 2.0)
     573           0 :                                 infostream<<"Server: Maximum lag peaked to "<<dtime
     574           0 :                                                 <<" s"<<std::endl;
     575           0 :                         max_lag = dtime;
     576             :                 }
     577           0 :                 m_env->reportMaxLagEstimate(max_lag);
     578             :                 // Step environment
     579           0 :                 ScopeProfiler sp(g_profiler, "SEnv step");
     580           0 :                 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
     581           0 :                 m_env->step(dtime);
     582             :         }
     583             : 
     584             :         static const float map_timer_and_unload_dtime = 2.92;
     585           0 :         if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
     586             :         {
     587           0 :                 JMutexAutoLock lock(m_env_mutex);
     588             :                 // Run Map's timers and unload unused data
     589           0 :                 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
     590           0 :                 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
     591           0 :                                 g_settings->getFloat("server_unload_unused_data_timeout"));
     592             :         }
     593             : 
     594             :         /*
     595             :                 Do background stuff
     596             :         */
     597             : 
     598             :         /* Transform liquids */
     599           0 :         m_liquid_transform_timer += dtime;
     600           0 :         if(m_liquid_transform_timer >= m_liquid_transform_every)
     601             :         {
     602           0 :                 m_liquid_transform_timer -= m_liquid_transform_every;
     603             : 
     604           0 :                 JMutexAutoLock lock(m_env_mutex);
     605             : 
     606           0 :                 ScopeProfiler sp(g_profiler, "Server: liquid transform");
     607             : 
     608           0 :                 std::map<v3s16, MapBlock*> modified_blocks;
     609           0 :                 m_env->getMap().transformLiquids(modified_blocks);
     610             : #if 0
     611             :                 /*
     612             :                         Update lighting
     613             :                 */
     614             :                 core::map<v3s16, MapBlock*> lighting_modified_blocks;
     615             :                 ServerMap &map = ((ServerMap&)m_env->getMap());
     616             :                 map.updateLighting(modified_blocks, lighting_modified_blocks);
     617             : 
     618             :                 // Add blocks modified by lighting to modified_blocks
     619             :                 for(core::map<v3s16, MapBlock*>::Iterator
     620             :                                 i = lighting_modified_blocks.getIterator();
     621             :                                 i.atEnd() == false; i++)
     622             :                 {
     623             :                         MapBlock *block = i.getNode()->getValue();
     624             :                         modified_blocks.insert(block->getPos(), block);
     625             :                 }
     626             : #endif
     627             :                 /*
     628             :                         Set the modified blocks unsent for all the clients
     629             :                 */
     630           0 :                 if(!modified_blocks.empty())
     631             :                 {
     632           0 :                         SetBlocksNotSent(modified_blocks);
     633             :                 }
     634             :         }
     635           0 :         m_clients.step(dtime);
     636             : 
     637           0 :         m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
     638             : #if USE_CURL
     639             :         // send masterserver announce
     640             :         {
     641           0 :                 float &counter = m_masterserver_timer;
     642           0 :                 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
     643           0 :                                 g_settings->getBool("server_announce"))
     644             :                 {
     645           0 :                         ServerList::sendAnnounce(counter ? "update" : "start",
     646           0 :                                         m_bind_addr.getPort(),
     647           0 :                                         m_clients.getPlayerNames(),
     648             :                                         m_uptime.get(),
     649           0 :                                         m_env->getGameTime(),
     650             :                                         m_lag,
     651             :                                         m_gamespec.id,
     652           0 :                                         m_emerge->params.mg_name,
     653           0 :                                         m_mods);
     654           0 :                         counter = 0.01;
     655             :                 }
     656           0 :                 counter += dtime;
     657             :         }
     658             : #endif
     659             : 
     660             :         /*
     661             :                 Check added and deleted active objects
     662             :         */
     663             :         {
     664             :                 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
     665           0 :                 JMutexAutoLock envlock(m_env_mutex);
     666             : 
     667           0 :                 m_clients.Lock();
     668           0 :                 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
     669           0 :                 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
     670             : 
     671             :                 // Radius inside which objects are active
     672           0 :                 s16 radius = g_settings->getS16("active_object_send_range_blocks");
     673           0 :                 s16 player_radius = g_settings->getS16("player_transfer_distance");
     674             : 
     675           0 :                 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
     676           0 :                                 !g_settings->getBool("unlimited_player_transfer_distance"))
     677           0 :                         player_radius = radius;
     678             : 
     679           0 :                 radius *= MAP_BLOCKSIZE;
     680           0 :                 player_radius *= MAP_BLOCKSIZE;
     681             : 
     682           0 :                 for(std::map<u16, RemoteClient*>::iterator
     683           0 :                         i = clients.begin();
     684           0 :                         i != clients.end(); ++i)
     685             :                 {
     686           0 :                         RemoteClient *client = i->second;
     687             : 
     688             :                         // If definitions and textures have not been sent, don't
     689             :                         // send objects either
     690           0 :                         if (client->getState() < CS_DefinitionsSent)
     691           0 :                                 continue;
     692             : 
     693           0 :                         Player *player = m_env->getPlayer(client->peer_id);
     694           0 :                         if(player==NULL)
     695             :                         {
     696             :                                 // This can happen if the client timeouts somehow
     697             :                                 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
     698             :                                                 <<client->peer_id
     699             :                                                 <<" has no associated player"<<std::endl;*/
     700           0 :                                 continue;
     701             :                         }
     702           0 :                         v3s16 pos = floatToInt(player->getPosition(), BS);
     703             : 
     704           0 :                         std::set<u16> removed_objects;
     705           0 :                         std::set<u16> added_objects;
     706           0 :                         m_env->getRemovedActiveObjects(pos, radius, player_radius,
     707           0 :                                         client->m_known_objects, removed_objects);
     708           0 :                         m_env->getAddedActiveObjects(pos, radius, player_radius,
     709           0 :                                         client->m_known_objects, added_objects);
     710             : 
     711             :                         // Ignore if nothing happened
     712           0 :                         if(removed_objects.empty() && added_objects.empty())
     713             :                         {
     714             :                                 //infostream<<"active objects: none changed"<<std::endl;
     715           0 :                                 continue;
     716             :                         }
     717             : 
     718           0 :                         std::string data_buffer;
     719             : 
     720             :                         char buf[4];
     721             : 
     722             :                         // Handle removed objects
     723           0 :                         writeU16((u8*)buf, removed_objects.size());
     724           0 :                         data_buffer.append(buf, 2);
     725           0 :                         for(std::set<u16>::iterator
     726           0 :                                         i = removed_objects.begin();
     727           0 :                                         i != removed_objects.end(); ++i)
     728             :                         {
     729             :                                 // Get object
     730           0 :                                 u16 id = *i;
     731           0 :                                 ServerActiveObject* obj = m_env->getActiveObject(id);
     732             : 
     733             :                                 // Add to data buffer for sending
     734           0 :                                 writeU16((u8*)buf, id);
     735           0 :                                 data_buffer.append(buf, 2);
     736             : 
     737             :                                 // Remove from known objects
     738           0 :                                 client->m_known_objects.erase(id);
     739             : 
     740           0 :                                 if(obj && obj->m_known_by_count > 0)
     741           0 :                                         obj->m_known_by_count--;
     742             :                         }
     743             : 
     744             :                         // Handle added objects
     745           0 :                         writeU16((u8*)buf, added_objects.size());
     746           0 :                         data_buffer.append(buf, 2);
     747           0 :                         for(std::set<u16>::iterator
     748           0 :                                         i = added_objects.begin();
     749           0 :                                         i != added_objects.end(); ++i)
     750             :                         {
     751             :                                 // Get object
     752           0 :                                 u16 id = *i;
     753           0 :                                 ServerActiveObject* obj = m_env->getActiveObject(id);
     754             : 
     755             :                                 // Get object type
     756           0 :                                 u8 type = ACTIVEOBJECT_TYPE_INVALID;
     757           0 :                                 if(obj == NULL)
     758           0 :                                         infostream<<"WARNING: "<<__FUNCTION_NAME
     759           0 :                                                         <<": NULL object"<<std::endl;
     760             :                                 else
     761           0 :                                         type = obj->getSendType();
     762             : 
     763             :                                 // Add to data buffer for sending
     764           0 :                                 writeU16((u8*)buf, id);
     765           0 :                                 data_buffer.append(buf, 2);
     766           0 :                                 writeU8((u8*)buf, type);
     767           0 :                                 data_buffer.append(buf, 1);
     768             : 
     769           0 :                                 if(obj)
     770           0 :                                         data_buffer.append(serializeLongString(
     771           0 :                                                         obj->getClientInitializationData(client->net_proto_version)));
     772             :                                 else
     773           0 :                                         data_buffer.append(serializeLongString(""));
     774             : 
     775             :                                 // Add to known objects
     776           0 :                                 client->m_known_objects.insert(id);
     777             : 
     778           0 :                                 if(obj)
     779           0 :                                         obj->m_known_by_count++;
     780             :                         }
     781             : 
     782           0 :                         u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
     783           0 :                         verbosestream << "Server: Sent object remove/add: "
     784           0 :                                         << removed_objects.size() << " removed, "
     785           0 :                                         << added_objects.size() << " added, "
     786           0 :                                         << "packet size is " << pktSize << std::endl;
     787             :                 }
     788           0 :                 m_clients.Unlock();
     789             :         }
     790             : 
     791             :         /*
     792             :                 Send object messages
     793             :         */
     794             :         {
     795           0 :                 JMutexAutoLock envlock(m_env_mutex);
     796           0 :                 ScopeProfiler sp(g_profiler, "Server: sending object messages");
     797             : 
     798             :                 // Key = object id
     799             :                 // Value = data sent by object
     800           0 :                 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
     801             : 
     802             :                 // Get active object messages from environment
     803           0 :                 for(;;) {
     804           0 :                         ActiveObjectMessage aom = m_env->getActiveObjectMessage();
     805           0 :                         if (aom.id == 0)
     806           0 :                                 break;
     807             : 
     808           0 :                         std::vector<ActiveObjectMessage>* message_list = NULL;
     809           0 :                         std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
     810           0 :                         n = buffered_messages.find(aom.id);
     811           0 :                         if (n == buffered_messages.end()) {
     812           0 :                                 message_list = new std::vector<ActiveObjectMessage>;
     813           0 :                                 buffered_messages[aom.id] = message_list;
     814             :                         }
     815             :                         else {
     816           0 :                                 message_list = n->second;
     817             :                         }
     818           0 :                         message_list->push_back(aom);
     819             :                 }
     820             : 
     821           0 :                 m_clients.Lock();
     822           0 :                 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
     823             :                 // Route data to every client
     824           0 :                 for (std::map<u16, RemoteClient*>::iterator
     825           0 :                         i = clients.begin();
     826           0 :                         i != clients.end(); ++i) {
     827           0 :                         RemoteClient *client = i->second;
     828           0 :                         std::string reliable_data;
     829           0 :                         std::string unreliable_data;
     830             :                         // Go through all objects in message buffer
     831           0 :                         for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
     832           0 :                                         j = buffered_messages.begin();
     833           0 :                                         j != buffered_messages.end(); ++j) {
     834             :                                 // If object is not known by client, skip it
     835           0 :                                 u16 id = j->first;
     836           0 :                                 if (client->m_known_objects.find(id) == client->m_known_objects.end())
     837           0 :                                         continue;
     838             : 
     839             :                                 // Get message list of object
     840           0 :                                 std::vector<ActiveObjectMessage>* list = j->second;
     841             :                                 // Go through every message
     842           0 :                                 for (std::vector<ActiveObjectMessage>::iterator
     843           0 :                                                 k = list->begin(); k != list->end(); ++k) {
     844             :                                         // Compose the full new data with header
     845           0 :                                         ActiveObjectMessage aom = *k;
     846           0 :                                         std::string new_data;
     847             :                                         // Add object id
     848             :                                         char buf[2];
     849           0 :                                         writeU16((u8*)&buf[0], aom.id);
     850           0 :                                         new_data.append(buf, 2);
     851             :                                         // Add data
     852           0 :                                         new_data += serializeString(aom.datastring);
     853             :                                         // Add data to buffer
     854           0 :                                         if(aom.reliable)
     855           0 :                                                 reliable_data += new_data;
     856             :                                         else
     857           0 :                                                 unreliable_data += new_data;
     858             :                                 }
     859             :                         }
     860             :                         /*
     861             :                                 reliable_data and unreliable_data are now ready.
     862             :                                 Send them.
     863             :                         */
     864           0 :                         if(reliable_data.size() > 0) {
     865           0 :                                 SendActiveObjectMessages(client->peer_id, reliable_data);
     866             :                         }
     867             : 
     868           0 :                         if(unreliable_data.size() > 0) {
     869           0 :                                 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
     870             :                         }
     871             :                 }
     872           0 :                 m_clients.Unlock();
     873             : 
     874             :                 // Clear buffered_messages
     875           0 :                 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
     876           0 :                                 i = buffered_messages.begin();
     877           0 :                                 i != buffered_messages.end(); ++i) {
     878           0 :                         delete i->second;
     879             :                 }
     880             :         }
     881             : 
     882             :         /*
     883             :                 Send queued-for-sending map edit events.
     884             :         */
     885             :         {
     886             :                 // We will be accessing the environment
     887           0 :                 JMutexAutoLock lock(m_env_mutex);
     888             : 
     889             :                 // Don't send too many at a time
     890             :                 //u32 count = 0;
     891             : 
     892             :                 // Single change sending is disabled if queue size is not small
     893           0 :                 bool disable_single_change_sending = false;
     894           0 :                 if(m_unsent_map_edit_queue.size() >= 4)
     895           0 :                         disable_single_change_sending = true;
     896             : 
     897           0 :                 int event_count = m_unsent_map_edit_queue.size();
     898             : 
     899             :                 // We'll log the amount of each
     900           0 :                 Profiler prof;
     901             : 
     902           0 :                 while(m_unsent_map_edit_queue.size() != 0)
     903             :                 {
     904           0 :                         MapEditEvent* event = m_unsent_map_edit_queue.front();
     905           0 :                         m_unsent_map_edit_queue.pop();
     906             : 
     907             :                         // Players far away from the change are stored here.
     908             :                         // Instead of sending the changes, MapBlocks are set not sent
     909             :                         // for them.
     910           0 :                         std::vector<u16> far_players;
     911             : 
     912           0 :                         switch (event->type) {
     913             :                         case MEET_ADDNODE:
     914             :                         case MEET_SWAPNODE:
     915           0 :                                 prof.add("MEET_ADDNODE", 1);
     916           0 :                                 sendAddNode(event->p, event->n, event->already_known_by_peer,
     917             :                                                 &far_players, disable_single_change_sending ? 5 : 30,
     918           0 :                                                 event->type == MEET_ADDNODE);
     919           0 :                                 break;
     920             :                         case MEET_REMOVENODE:
     921           0 :                                 prof.add("MEET_REMOVENODE", 1);
     922           0 :                                 sendRemoveNode(event->p, event->already_known_by_peer,
     923           0 :                                                 &far_players, disable_single_change_sending ? 5 : 30);
     924           0 :                                 break;
     925             :                         case MEET_BLOCK_NODE_METADATA_CHANGED:
     926           0 :                                 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
     927           0 :                                                 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
     928           0 :                                                 setBlockNotSent(event->p);
     929           0 :                                 break;
     930             :                         case MEET_OTHER:
     931           0 :                                 infostream << "Server: MEET_OTHER" << std::endl;
     932           0 :                                 prof.add("MEET_OTHER", 1);
     933           0 :                                 for(std::set<v3s16>::iterator
     934           0 :                                                 i = event->modified_blocks.begin();
     935           0 :                                                 i != event->modified_blocks.end(); ++i) {
     936           0 :                                         setBlockNotSent(*i);
     937             :                                 }
     938           0 :                                 break;
     939             :                         default:
     940           0 :                                 prof.add("unknown", 1);
     941           0 :                                 infostream << "WARNING: Server: Unknown MapEditEvent "
     942           0 :                                                 << ((u32)event->type) << std::endl;
     943           0 :                                 break;
     944             :                         }
     945             : 
     946             :                         /*
     947             :                                 Set blocks not sent to far players
     948             :                         */
     949           0 :                         if(!far_players.empty()) {
     950             :                                 // Convert list format to that wanted by SetBlocksNotSent
     951           0 :                                 std::map<v3s16, MapBlock*> modified_blocks2;
     952           0 :                                 for(std::set<v3s16>::iterator
     953           0 :                                                 i = event->modified_blocks.begin();
     954           0 :                                                 i != event->modified_blocks.end(); ++i) {
     955           0 :                                         modified_blocks2[*i] =
     956           0 :                                                         m_env->getMap().getBlockNoCreateNoEx(*i);
     957             :                                 }
     958             : 
     959             :                                 // Set blocks not sent
     960           0 :                                 for(std::vector<u16>::iterator
     961           0 :                                                 i = far_players.begin();
     962           0 :                                                 i != far_players.end(); ++i) {
     963           0 :                                         if(RemoteClient *client = getClient(*i))
     964           0 :                                                 client->SetBlocksNotSent(modified_blocks2);
     965             :                                 }
     966             :                         }
     967             : 
     968           0 :                         delete event;
     969             : 
     970             :                         /*// Don't send too many at a time
     971             :                         count++;
     972             :                         if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
     973             :                                 break;*/
     974             :                 }
     975             : 
     976           0 :                 if(event_count >= 5){
     977           0 :                         infostream<<"Server: MapEditEvents:"<<std::endl;
     978           0 :                         prof.print(infostream);
     979           0 :                 } else if(event_count != 0){
     980           0 :                         verbosestream<<"Server: MapEditEvents:"<<std::endl;
     981           0 :                         prof.print(verbosestream);
     982             :                 }
     983             : 
     984             :         }
     985             : 
     986             :         /*
     987             :                 Trigger emergethread (it somehow gets to a non-triggered but
     988             :                 bysy state sometimes)
     989             :         */
     990             :         {
     991           0 :                 float &counter = m_emergethread_trigger_timer;
     992           0 :                 counter += dtime;
     993           0 :                 if(counter >= 2.0)
     994             :                 {
     995           0 :                         counter = 0.0;
     996             : 
     997           0 :                         m_emerge->startThreads();
     998             :                 }
     999             :         }
    1000             : 
    1001             :         // Save map, players and auth stuff
    1002             :         {
    1003           0 :                 float &counter = m_savemap_timer;
    1004           0 :                 counter += dtime;
    1005           0 :                 if(counter >= g_settings->getFloat("server_map_save_interval"))
    1006             :                 {
    1007           0 :                         counter = 0.0;
    1008           0 :                         JMutexAutoLock lock(m_env_mutex);
    1009             : 
    1010           0 :                         ScopeProfiler sp(g_profiler, "Server: saving stuff");
    1011             : 
    1012             :                         // Save ban file
    1013           0 :                         if (m_banmanager->isModified()) {
    1014           0 :                                 m_banmanager->save();
    1015             :                         }
    1016             : 
    1017             :                         // Save changed parts of map
    1018           0 :                         m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
    1019             : 
    1020             :                         // Save players
    1021           0 :                         m_env->saveLoadedPlayers();
    1022             : 
    1023             :                         // Save environment metadata
    1024           0 :                         m_env->saveMeta();
    1025             :                 }
    1026             :         }
    1027             : }
    1028             : 
    1029           0 : void Server::Receive()
    1030             : {
    1031           0 :         DSTACK(__FUNCTION_NAME);
    1032           0 :         SharedBuffer<u8> data;
    1033             :         u16 peer_id;
    1034             :         try {
    1035           0 :                 NetworkPacket pkt;
    1036           0 :                 m_con.Receive(&pkt);
    1037           0 :                 peer_id = pkt.getPeerId();
    1038           0 :                 ProcessData(&pkt);
    1039             :         }
    1040           0 :         catch(con::InvalidIncomingDataException &e) {
    1041             :                 infostream<<"Server::Receive(): "
    1042           0 :                                 "InvalidIncomingDataException: what()="
    1043           0 :                                 <<e.what()<<std::endl;
    1044             :         }
    1045           0 :         catch(SerializationError &e) {
    1046             :                 infostream<<"Server::Receive(): "
    1047           0 :                                 "SerializationError: what()="
    1048           0 :                                 <<e.what()<<std::endl;
    1049             :         }
    1050           0 :         catch(ClientStateError &e) {
    1051           0 :                 errorstream << "ProcessData: peer=" << peer_id  << e.what() << std::endl;
    1052           0 :                 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
    1053           0 :                                 L"Try reconnecting or updating your client");
    1054             :         }
    1055           0 :         catch(con::PeerNotFoundException &e) {
    1056             :                 // Do nothing
    1057             :         }
    1058           0 : }
    1059             : 
    1060           0 : PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
    1061             : {
    1062           0 :         std::string playername = "";
    1063           0 :         PlayerSAO *playersao = NULL;
    1064           0 :         m_clients.Lock();
    1065             :         try {
    1066           0 :                 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
    1067           0 :                 if (client != NULL) {
    1068           0 :                         playername = client->getName();
    1069           0 :                         playersao = emergePlayer(playername.c_str(), peer_id);
    1070             :                 }
    1071           0 :         } catch (std::exception &e) {
    1072           0 :                 m_clients.Unlock();
    1073           0 :                 throw;
    1074             :         }
    1075           0 :         m_clients.Unlock();
    1076             : 
    1077             :         RemotePlayer *player =
    1078           0 :                 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
    1079             : 
    1080             :         // If failed, cancel
    1081           0 :         if ((playersao == NULL) || (player == NULL)) {
    1082           0 :                 if (player && player->peer_id != 0) {
    1083           0 :                         actionstream << "Server: Failed to emerge player \"" << playername
    1084           0 :                                         << "\" (player allocated to an another client)" << std::endl;
    1085           0 :                         DenyAccess_Legacy(peer_id, L"Another client is connected with this "
    1086             :                                         L"name. If your client closed unexpectedly, try again in "
    1087           0 :                                         L"a minute.");
    1088             :                 } else {
    1089           0 :                         errorstream << "Server: " << playername << ": Failed to emerge player"
    1090           0 :                                         << std::endl;
    1091           0 :                         DenyAccess_Legacy(peer_id, L"Could not allocate player.");
    1092             :                 }
    1093           0 :                 return NULL;
    1094             :         }
    1095             : 
    1096             :         /*
    1097             :                 Send complete position information
    1098             :         */
    1099           0 :         SendMovePlayer(peer_id);
    1100             : 
    1101             :         // Send privileges
    1102           0 :         SendPlayerPrivileges(peer_id);
    1103             : 
    1104             :         // Send inventory formspec
    1105           0 :         SendPlayerInventoryFormspec(peer_id);
    1106             : 
    1107             :         // Send inventory
    1108           0 :         SendInventory(playersao);
    1109             : 
    1110             :         // Send HP
    1111           0 :         SendPlayerHPOrDie(peer_id, playersao->getHP() == 0);
    1112             : 
    1113             :         // Send Breath
    1114           0 :         SendPlayerBreath(peer_id);
    1115             : 
    1116             :         // Show death screen if necessary
    1117           0 :         if(player->isDead())
    1118           0 :                 SendDeathscreen(peer_id, false, v3f(0,0,0));
    1119             : 
    1120             :         // Note things in chat if not in simple singleplayer mode
    1121           0 :         if(!m_simple_singleplayer_mode) {
    1122             :                 // Send information about server to player in chat
    1123           0 :                 SendChatMessage(peer_id, getStatusString());
    1124             : 
    1125             :                 // Send information about joining in chat
    1126             :                 {
    1127           0 :                         std::wstring name = L"unknown";
    1128           0 :                         Player *player = m_env->getPlayer(peer_id);
    1129           0 :                         if(player != NULL)
    1130           0 :                                 name = narrow_to_wide(player->getName());
    1131             : 
    1132           0 :                         std::wstring message;
    1133           0 :                         message += L"*** ";
    1134           0 :                         message += name;
    1135           0 :                         message += L" joined the game.";
    1136           0 :                         SendChatMessage(PEER_ID_INEXISTENT,message);
    1137             :                 }
    1138             :         }
    1139           0 :         Address addr = getPeerAddress(player->peer_id);
    1140           0 :         std::string ip_str = addr.serializeString();
    1141           0 :         actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
    1142             :         /*
    1143             :                 Print out action
    1144             :         */
    1145             :         {
    1146           0 :                 std::vector<std::string> names = m_clients.getPlayerNames();
    1147             : 
    1148           0 :                 actionstream<<player->getName() <<" joins game. List of players: ";
    1149             : 
    1150           0 :                 for (std::vector<std::string>::iterator i = names.begin();
    1151           0 :                                 i != names.end(); i++) {
    1152           0 :                         actionstream << *i << " ";
    1153             :                 }
    1154             : 
    1155           0 :                 actionstream << player->getName() <<std::endl;
    1156             :         }
    1157           0 :         return playersao;
    1158             : }
    1159             : 
    1160           0 : inline void Server::handleCommand(NetworkPacket* pkt)
    1161             : {
    1162           0 :         const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
    1163           0 :         (this->*opHandle.handler)(pkt);
    1164           0 : }
    1165             : 
    1166           0 : void Server::ProcessData(NetworkPacket *pkt)
    1167             : {
    1168           0 :         DSTACK(__FUNCTION_NAME);
    1169             :         // Environment is locked first.
    1170           0 :         JMutexAutoLock envlock(m_env_mutex);
    1171             : 
    1172           0 :         ScopeProfiler sp(g_profiler, "Server::ProcessData");
    1173           0 :         u32 peer_id = pkt->getPeerId();
    1174             : 
    1175             :         try {
    1176           0 :                 Address address = getPeerAddress(peer_id);
    1177           0 :                 std::string addr_s = address.serializeString();
    1178             : 
    1179           0 :                 if(m_banmanager->isIpBanned(addr_s)) {
    1180           0 :                         std::string ban_name = m_banmanager->getBanName(addr_s);
    1181           0 :                         infostream << "Server: A banned client tried to connect from "
    1182           0 :                                         << addr_s << "; banned name was "
    1183           0 :                                         << ban_name << std::endl;
    1184             :                         // This actually doesn't seem to transfer to the client
    1185           0 :                         DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
    1186           0 :                                         + narrow_to_wide(ban_name));
    1187           0 :                         return;
    1188             :                 }
    1189             :         }
    1190           0 :         catch(con::PeerNotFoundException &e) {
    1191             :                 /*
    1192             :                  * no peer for this packet found
    1193             :                  * most common reason is peer timeout, e.g. peer didn't
    1194             :                  * respond for some time, your server was overloaded or
    1195             :                  * things like that.
    1196             :                  */
    1197           0 :                 infostream << "Server::ProcessData(): Canceling: peer "
    1198           0 :                                 << peer_id << " not found" << std::endl;
    1199           0 :                 return;
    1200             :         }
    1201             : 
    1202             :         try {
    1203           0 :                 ToServerCommand command = (ToServerCommand) pkt->getCommand();
    1204             : 
    1205             :                 // Command must be handled into ToServerCommandHandler
    1206           0 :                 if (command >= TOSERVER_NUM_MSG_TYPES) {
    1207           0 :                         infostream << "Server: Ignoring unknown command "
    1208           0 :                                          << command << std::endl;
    1209           0 :                         return;
    1210             :                 }
    1211             : 
    1212           0 :                 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
    1213           0 :                         handleCommand(pkt);
    1214           0 :                         return;
    1215             :                 }
    1216             : 
    1217           0 :                 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
    1218             : 
    1219           0 :                 if(peer_ser_ver == SER_FMT_VER_INVALID) {
    1220             :                         errorstream << "Server::ProcessData(): Cancelling: Peer"
    1221             :                                         " serialization format invalid or not initialized."
    1222           0 :                                         " Skipping incoming command=" << command << std::endl;
    1223           0 :                         return;
    1224             :                 }
    1225             : 
    1226             :                 /* Handle commands related to client startup */
    1227           0 :                 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
    1228           0 :                         handleCommand(pkt);
    1229           0 :                         return;
    1230             :                 }
    1231             : 
    1232           0 :                 if (m_clients.getClientState(peer_id) < CS_Active) {
    1233           0 :                         if (command == TOSERVER_PLAYERPOS) return;
    1234             : 
    1235           0 :                         errorstream << "Got packet command: " << command << " for peer id "
    1236           0 :                                         << peer_id << " but client isn't active yet. Dropping packet "
    1237           0 :                                         << std::endl;
    1238           0 :                         return;
    1239             :                 }
    1240             : 
    1241           0 :                 handleCommand(pkt);
    1242           0 :         } catch (SendFailedException &e) {
    1243           0 :                 errorstream << "Server::ProcessData(): SendFailedException: "
    1244           0 :                                 << "what=" << e.what()
    1245           0 :                                 << std::endl;
    1246           0 :         } catch (PacketError &e) {
    1247           0 :                 actionstream << "Server::ProcessData(): PacketError: "
    1248           0 :                                 << "what=" << e.what()
    1249           0 :                                 << std::endl;
    1250             :         }
    1251             : }
    1252             : 
    1253           0 : void Server::setTimeOfDay(u32 time)
    1254             : {
    1255           0 :         m_env->setTimeOfDay(time);
    1256           0 :         m_time_of_day_send_timer = 0;
    1257           0 : }
    1258             : 
    1259           0 : void Server::onMapEditEvent(MapEditEvent *event)
    1260             : {
    1261           0 :         if(m_ignore_map_edit_events)
    1262           0 :                 return;
    1263           0 :         if(m_ignore_map_edit_events_area.contains(event->getArea()))
    1264           0 :                 return;
    1265           0 :         MapEditEvent *e = event->clone();
    1266           0 :         m_unsent_map_edit_queue.push(e);
    1267             : }
    1268             : 
    1269           0 : Inventory* Server::getInventory(const InventoryLocation &loc)
    1270             : {
    1271           0 :         switch (loc.type) {
    1272             :         case InventoryLocation::UNDEFINED:
    1273             :         case InventoryLocation::CURRENT_PLAYER:
    1274           0 :                 break;
    1275             :         case InventoryLocation::PLAYER:
    1276             :         {
    1277           0 :                 Player *player = m_env->getPlayer(loc.name.c_str());
    1278           0 :                 if(!player)
    1279           0 :                         return NULL;
    1280           0 :                 PlayerSAO *playersao = player->getPlayerSAO();
    1281           0 :                 if(!playersao)
    1282           0 :                         return NULL;
    1283           0 :                 return playersao->getInventory();
    1284             :         }
    1285             :                 break;
    1286             :         case InventoryLocation::NODEMETA:
    1287             :         {
    1288           0 :                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
    1289           0 :                 if(!meta)
    1290           0 :                         return NULL;
    1291           0 :                 return meta->getInventory();
    1292             :         }
    1293             :                 break;
    1294             :         case InventoryLocation::DETACHED:
    1295             :         {
    1296           0 :                 if(m_detached_inventories.count(loc.name) == 0)
    1297           0 :                         return NULL;
    1298           0 :                 return m_detached_inventories[loc.name];
    1299             :         }
    1300             :                 break;
    1301             :         default:
    1302           0 :                 sanity_check(false); // abort
    1303             :                 break;
    1304             :         }
    1305           0 :         return NULL;
    1306             : }
    1307           0 : void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
    1308             : {
    1309           0 :         switch(loc.type){
    1310             :         case InventoryLocation::UNDEFINED:
    1311           0 :                 break;
    1312             :         case InventoryLocation::PLAYER:
    1313             :         {
    1314           0 :                 if (!playerSend)
    1315           0 :                         return;
    1316             : 
    1317           0 :                 Player *player = m_env->getPlayer(loc.name.c_str());
    1318           0 :                 if(!player)
    1319           0 :                         return;
    1320           0 :                 PlayerSAO *playersao = player->getPlayerSAO();
    1321           0 :                 if(!playersao)
    1322           0 :                         return;
    1323             : 
    1324           0 :                 SendInventory(playersao);
    1325             :         }
    1326           0 :                 break;
    1327             :         case InventoryLocation::NODEMETA:
    1328             :         {
    1329           0 :                 v3s16 blockpos = getNodeBlockPos(loc.p);
    1330             : 
    1331           0 :                 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
    1332           0 :                 if(block)
    1333           0 :                         block->raiseModified(MOD_STATE_WRITE_NEEDED);
    1334             : 
    1335           0 :                 setBlockNotSent(blockpos);
    1336             :         }
    1337           0 :                 break;
    1338             :         case InventoryLocation::DETACHED:
    1339             :         {
    1340           0 :                 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
    1341             :         }
    1342           0 :                 break;
    1343             :         default:
    1344           0 :                 sanity_check(false); // abort
    1345             :                 break;
    1346             :         }
    1347             : }
    1348             : 
    1349           0 : void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
    1350             : {
    1351           0 :         std::vector<u16> clients = m_clients.getClientIDs();
    1352           0 :         m_clients.Lock();
    1353             :         // Set the modified blocks unsent for all the clients
    1354           0 :         for (std::vector<u16>::iterator i = clients.begin();
    1355           0 :                  i != clients.end(); ++i) {
    1356           0 :                         if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
    1357           0 :                                 client->SetBlocksNotSent(block);
    1358             :         }
    1359           0 :         m_clients.Unlock();
    1360           0 : }
    1361             : 
    1362           0 : void Server::peerAdded(con::Peer *peer)
    1363             : {
    1364           0 :         DSTACK(__FUNCTION_NAME);
    1365           0 :         verbosestream<<"Server::peerAdded(): peer->id="
    1366           0 :                         <<peer->id<<std::endl;
    1367             : 
    1368             :         con::PeerChange c;
    1369           0 :         c.type = con::PEER_ADDED;
    1370           0 :         c.peer_id = peer->id;
    1371           0 :         c.timeout = false;
    1372           0 :         m_peer_change_queue.push(c);
    1373           0 : }
    1374             : 
    1375           0 : void Server::deletingPeer(con::Peer *peer, bool timeout)
    1376             : {
    1377           0 :         DSTACK(__FUNCTION_NAME);
    1378           0 :         verbosestream<<"Server::deletingPeer(): peer->id="
    1379           0 :                         <<peer->id<<", timeout="<<timeout<<std::endl;
    1380             : 
    1381           0 :         m_clients.event(peer->id, CSE_Disconnect);
    1382             :         con::PeerChange c;
    1383           0 :         c.type = con::PEER_REMOVED;
    1384           0 :         c.peer_id = peer->id;
    1385           0 :         c.timeout = timeout;
    1386           0 :         m_peer_change_queue.push(c);
    1387           0 : }
    1388             : 
    1389           0 : bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
    1390             : {
    1391           0 :         *retval = m_con.getPeerStat(peer_id,type);
    1392           0 :         if (*retval == -1) return false;
    1393           0 :         return true;
    1394             : }
    1395             : 
    1396           0 : bool Server::getClientInfo(
    1397             :                 u16          peer_id,
    1398             :                 ClientState* state,
    1399             :                 u32*         uptime,
    1400             :                 u8*          ser_vers,
    1401             :                 u16*         prot_vers,
    1402             :                 u8*          major,
    1403             :                 u8*          minor,
    1404             :                 u8*          patch,
    1405             :                 std::string* vers_string
    1406             :         )
    1407             : {
    1408           0 :         *state = m_clients.getClientState(peer_id);
    1409           0 :         m_clients.Lock();
    1410           0 :         RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
    1411             : 
    1412           0 :         if (client == NULL) {
    1413           0 :                 m_clients.Unlock();
    1414           0 :                 return false;
    1415             :         }
    1416             : 
    1417           0 :         *uptime = client->uptime();
    1418           0 :         *ser_vers = client->serialization_version;
    1419           0 :         *prot_vers = client->net_proto_version;
    1420             : 
    1421           0 :         *major = client->getMajor();
    1422           0 :         *minor = client->getMinor();
    1423           0 :         *patch = client->getPatch();
    1424           0 :         *vers_string = client->getPatch();
    1425             : 
    1426           0 :         m_clients.Unlock();
    1427             : 
    1428           0 :         return true;
    1429             : }
    1430             : 
    1431           0 : void Server::handlePeerChanges()
    1432             : {
    1433           0 :         while(m_peer_change_queue.size() > 0)
    1434             :         {
    1435           0 :                 con::PeerChange c = m_peer_change_queue.front();
    1436           0 :                 m_peer_change_queue.pop();
    1437             : 
    1438           0 :                 verbosestream<<"Server: Handling peer change: "
    1439           0 :                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
    1440           0 :                                 <<std::endl;
    1441             : 
    1442           0 :                 switch(c.type)
    1443             :                 {
    1444             :                 case con::PEER_ADDED:
    1445           0 :                         m_clients.CreateClient(c.peer_id);
    1446           0 :                         break;
    1447             : 
    1448             :                 case con::PEER_REMOVED:
    1449           0 :                         DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
    1450           0 :                         break;
    1451             : 
    1452             :                 default:
    1453           0 :                         FATAL_ERROR("Invalid peer change event received!");
    1454             :                         break;
    1455             :                 }
    1456             :         }
    1457           0 : }
    1458             : 
    1459           0 : void Server::Send(NetworkPacket* pkt)
    1460             : {
    1461           0 :         m_clients.send(pkt->getPeerId(),
    1462           0 :                 clientCommandFactoryTable[pkt->getCommand()].channel,
    1463             :                 pkt,
    1464           0 :                 clientCommandFactoryTable[pkt->getCommand()].reliable);
    1465           0 : }
    1466             : 
    1467           0 : void Server::SendMovement(u16 peer_id)
    1468             : {
    1469           0 :         DSTACK(__FUNCTION_NAME);
    1470           0 :         std::ostringstream os(std::ios_base::binary);
    1471             : 
    1472           0 :         NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
    1473             : 
    1474           0 :         pkt << g_settings->getFloat("movement_acceleration_default");
    1475           0 :         pkt << g_settings->getFloat("movement_acceleration_air");
    1476           0 :         pkt << g_settings->getFloat("movement_acceleration_fast");
    1477           0 :         pkt << g_settings->getFloat("movement_speed_walk");
    1478           0 :         pkt << g_settings->getFloat("movement_speed_crouch");
    1479           0 :         pkt << g_settings->getFloat("movement_speed_fast");
    1480           0 :         pkt << g_settings->getFloat("movement_speed_climb");
    1481           0 :         pkt << g_settings->getFloat("movement_speed_jump");
    1482           0 :         pkt << g_settings->getFloat("movement_liquid_fluidity");
    1483           0 :         pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
    1484           0 :         pkt << g_settings->getFloat("movement_liquid_sink");
    1485           0 :         pkt << g_settings->getFloat("movement_gravity");
    1486             : 
    1487           0 :         Send(&pkt);
    1488           0 : }
    1489             : 
    1490           0 : void Server::SendHP(u16 peer_id, u8 hp)
    1491             : {
    1492           0 :         DSTACK(__FUNCTION_NAME);
    1493             : 
    1494           0 :         NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
    1495           0 :         pkt << hp;
    1496           0 :         Send(&pkt);
    1497           0 : }
    1498             : 
    1499           0 : void Server::SendBreath(u16 peer_id, u16 breath)
    1500             : {
    1501           0 :         DSTACK(__FUNCTION_NAME);
    1502             : 
    1503           0 :         NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
    1504           0 :         pkt << (u16) breath;
    1505           0 :         Send(&pkt);
    1506           0 : }
    1507             : 
    1508           0 : void Server::SendAccessDenied(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
    1509             : {
    1510           0 :         DSTACK(__FUNCTION_NAME);
    1511             : 
    1512           0 :         NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
    1513           0 :         pkt << (u8) reason;
    1514             : 
    1515           0 :         if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING) {
    1516           0 :                 pkt << custom_reason;
    1517             :         }
    1518           0 :         Send(&pkt);
    1519           0 : }
    1520             : 
    1521           0 : void Server::SendAccessDenied_Legacy(u16 peer_id,const std::wstring &reason)
    1522             : {
    1523           0 :         DSTACK(__FUNCTION_NAME);
    1524             : 
    1525           0 :         NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
    1526           0 :         pkt << reason;
    1527           0 :         Send(&pkt);
    1528           0 : }
    1529             : 
    1530           0 : void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
    1531             :                 v3f camera_point_target)
    1532             : {
    1533           0 :         DSTACK(__FUNCTION_NAME);
    1534             : 
    1535           0 :         NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
    1536           0 :         pkt << set_camera_point_target << camera_point_target;
    1537           0 :         Send(&pkt);
    1538           0 : }
    1539             : 
    1540           0 : void Server::SendItemDef(u16 peer_id,
    1541             :                 IItemDefManager *itemdef, u16 protocol_version)
    1542             : {
    1543           0 :         DSTACK(__FUNCTION_NAME);
    1544             : 
    1545           0 :         NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
    1546             : 
    1547             :         /*
    1548             :                 u16 command
    1549             :                 u32 length of the next item
    1550             :                 zlib-compressed serialized ItemDefManager
    1551             :         */
    1552           0 :         std::ostringstream tmp_os(std::ios::binary);
    1553           0 :         itemdef->serialize(tmp_os, protocol_version);
    1554           0 :         std::ostringstream tmp_os2(std::ios::binary);
    1555           0 :         compressZlib(tmp_os.str(), tmp_os2);
    1556           0 :         pkt.putLongString(tmp_os2.str());
    1557             : 
    1558             :         // Make data buffer
    1559           0 :         verbosestream << "Server: Sending item definitions to id(" << peer_id
    1560           0 :                         << "): size=" << pkt.getSize() << std::endl;
    1561             : 
    1562           0 :         Send(&pkt);
    1563           0 : }
    1564             : 
    1565           0 : void Server::SendNodeDef(u16 peer_id,
    1566             :                 INodeDefManager *nodedef, u16 protocol_version)
    1567             : {
    1568           0 :         DSTACK(__FUNCTION_NAME);
    1569             : 
    1570           0 :         NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
    1571             : 
    1572             :         /*
    1573             :                 u16 command
    1574             :                 u32 length of the next item
    1575             :                 zlib-compressed serialized NodeDefManager
    1576             :         */
    1577           0 :         std::ostringstream tmp_os(std::ios::binary);
    1578           0 :         nodedef->serialize(tmp_os, protocol_version);
    1579           0 :         std::ostringstream tmp_os2(std::ios::binary);
    1580           0 :         compressZlib(tmp_os.str(), tmp_os2);
    1581             : 
    1582           0 :         pkt.putLongString(tmp_os2.str());
    1583             : 
    1584             :         // Make data buffer
    1585           0 :         verbosestream << "Server: Sending node definitions to id(" << peer_id
    1586           0 :                         << "): size=" << pkt.getSize() << std::endl;
    1587             : 
    1588           0 :         Send(&pkt);
    1589           0 : }
    1590             : 
    1591             : /*
    1592             :         Non-static send methods
    1593             : */
    1594             : 
    1595           0 : void Server::SendInventory(PlayerSAO* playerSAO)
    1596             : {
    1597           0 :         DSTACK(__FUNCTION_NAME);
    1598             : 
    1599           0 :         UpdateCrafting(playerSAO->getPlayer());
    1600             : 
    1601             :         /*
    1602             :                 Serialize it
    1603             :         */
    1604             : 
    1605           0 :         NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
    1606             : 
    1607           0 :         std::ostringstream os;
    1608           0 :         playerSAO->getInventory()->serialize(os);
    1609             : 
    1610           0 :         std::string s = os.str();
    1611             : 
    1612           0 :         pkt.putRawString(s.c_str(), s.size());
    1613           0 :         Send(&pkt);
    1614           0 : }
    1615             : 
    1616           0 : void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
    1617             : {
    1618           0 :         DSTACK(__FUNCTION_NAME);
    1619             : 
    1620           0 :         NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
    1621           0 :         pkt << message;
    1622             : 
    1623           0 :         if (peer_id != PEER_ID_INEXISTENT) {
    1624           0 :                 Send(&pkt);
    1625             :         }
    1626             :         else {
    1627           0 :                 m_clients.sendToAll(0, &pkt, true);
    1628             :         }
    1629           0 : }
    1630             : 
    1631           0 : void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
    1632             :                                      const std::string &formname)
    1633             : {
    1634           0 :         DSTACK(__FUNCTION_NAME);
    1635             : 
    1636           0 :         NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
    1637             : 
    1638           0 :         pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
    1639           0 :         pkt << formname;
    1640             : 
    1641           0 :         Send(&pkt);
    1642           0 : }
    1643             : 
    1644             : // Spawns a particle on peer with peer_id
    1645           0 : void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
    1646             :                                 float expirationtime, float size, bool collisiondetection,
    1647             :                                 bool vertical, std::string texture)
    1648             : {
    1649           0 :         DSTACK(__FUNCTION_NAME);
    1650             : 
    1651           0 :         NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
    1652             : 
    1653           0 :         pkt << pos << velocity << acceleration << expirationtime
    1654           0 :                         << size << collisiondetection;
    1655           0 :         pkt.putLongString(texture);
    1656           0 :         pkt << vertical;
    1657             : 
    1658           0 :         if (peer_id != PEER_ID_INEXISTENT) {
    1659           0 :                 Send(&pkt);
    1660             :         }
    1661             :         else {
    1662           0 :                 m_clients.sendToAll(0, &pkt, true);
    1663             :         }
    1664           0 : }
    1665             : 
    1666             : // Adds a ParticleSpawner on peer with peer_id
    1667           0 : void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
    1668             :         v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
    1669             :         float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
    1670             : {
    1671           0 :         DSTACK(__FUNCTION_NAME);
    1672             : 
    1673           0 :         NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
    1674             : 
    1675           0 :         pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
    1676           0 :                         << minacc << maxacc << minexptime << maxexptime << minsize
    1677           0 :                         << maxsize << collisiondetection;
    1678             : 
    1679           0 :         pkt.putLongString(texture);
    1680             : 
    1681           0 :         pkt << id << vertical;
    1682             : 
    1683           0 :         if (peer_id != PEER_ID_INEXISTENT) {
    1684           0 :                 Send(&pkt);
    1685             :         }
    1686             :         else {
    1687           0 :                 m_clients.sendToAll(0, &pkt, true);
    1688             :         }
    1689           0 : }
    1690             : 
    1691           0 : void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
    1692             : {
    1693           0 :         DSTACK(__FUNCTION_NAME);
    1694             : 
    1695           0 :         NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY, 2, peer_id);
    1696             : 
    1697             :         // Ugly error in this packet
    1698           0 :         pkt << (u16) id;
    1699             : 
    1700           0 :         if (peer_id != PEER_ID_INEXISTENT) {
    1701           0 :                 Send(&pkt);
    1702             :         }
    1703             :         else {
    1704           0 :                 m_clients.sendToAll(0, &pkt, true);
    1705             :         }
    1706             : 
    1707           0 : }
    1708             : 
    1709           0 : void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
    1710             : {
    1711           0 :         NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
    1712             : 
    1713           0 :         pkt << id << (u8) form->type << form->pos << form->name << form->scale
    1714           0 :                         << form->text << form->number << form->item << form->dir
    1715           0 :                         << form->align << form->offset << form->world_pos << form->size;
    1716             : 
    1717           0 :         Send(&pkt);
    1718           0 : }
    1719             : 
    1720           0 : void Server::SendHUDRemove(u16 peer_id, u32 id)
    1721             : {
    1722           0 :         NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
    1723           0 :         pkt << id;
    1724           0 :         Send(&pkt);
    1725           0 : }
    1726             : 
    1727           0 : void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
    1728             : {
    1729           0 :         NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
    1730           0 :         pkt << id << (u8) stat;
    1731             : 
    1732           0 :         switch (stat) {
    1733             :                 case HUD_STAT_POS:
    1734             :                 case HUD_STAT_SCALE:
    1735             :                 case HUD_STAT_ALIGN:
    1736             :                 case HUD_STAT_OFFSET:
    1737           0 :                         pkt << *(v2f *) value;
    1738           0 :                         break;
    1739             :                 case HUD_STAT_NAME:
    1740             :                 case HUD_STAT_TEXT:
    1741           0 :                         pkt << *(std::string *) value;
    1742           0 :                         break;
    1743             :                 case HUD_STAT_WORLD_POS:
    1744           0 :                         pkt << *(v3f *) value;
    1745           0 :                         break;
    1746             :                 case HUD_STAT_SIZE:
    1747           0 :                         pkt << *(v2s32 *) value;
    1748           0 :                         break;
    1749             :                 case HUD_STAT_NUMBER:
    1750             :                 case HUD_STAT_ITEM:
    1751             :                 case HUD_STAT_DIR:
    1752             :                 default:
    1753           0 :                         pkt << *(u32 *) value;
    1754           0 :                         break;
    1755             :         }
    1756             : 
    1757           0 :         Send(&pkt);
    1758           0 : }
    1759             : 
    1760           0 : void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
    1761             : {
    1762           0 :         NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
    1763             : 
    1764           0 :         flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
    1765             : 
    1766           0 :         pkt << flags << mask;
    1767             : 
    1768           0 :         Send(&pkt);
    1769           0 : }
    1770             : 
    1771           0 : void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
    1772             : {
    1773           0 :         NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
    1774           0 :         pkt << param << value;
    1775           0 :         Send(&pkt);
    1776           0 : }
    1777             : 
    1778           0 : void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
    1779             :                 const std::string &type, const std::vector<std::string> &params)
    1780             : {
    1781           0 :         NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
    1782           0 :         pkt << bgcolor << type << (u16) params.size();
    1783             : 
    1784           0 :         for(size_t i=0; i<params.size(); i++)
    1785           0 :                 pkt << params[i];
    1786             : 
    1787           0 :         Send(&pkt);
    1788           0 : }
    1789             : 
    1790           0 : void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
    1791             :                 float ratio)
    1792             : {
    1793             :         NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
    1794           0 :                         1 + 2, peer_id);
    1795             : 
    1796           0 :         pkt << do_override << (u16) (ratio * 65535);
    1797             : 
    1798           0 :         Send(&pkt);
    1799           0 : }
    1800             : 
    1801           0 : void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
    1802             : {
    1803           0 :         DSTACK(__FUNCTION_NAME);
    1804             : 
    1805           0 :         NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
    1806           0 :         pkt << time << time_speed;
    1807             : 
    1808           0 :         if (peer_id == PEER_ID_INEXISTENT) {
    1809           0 :                 m_clients.sendToAll(0, &pkt, true);
    1810             :         }
    1811             :         else {
    1812           0 :                 Send(&pkt);
    1813             :         }
    1814           0 : }
    1815             : 
    1816           0 : void Server::SendPlayerHP(u16 peer_id)
    1817             : {
    1818           0 :         DSTACK(__FUNCTION_NAME);
    1819           0 :         PlayerSAO *playersao = getPlayerSAO(peer_id);
    1820             :         // In some rare case, if the player is disconnected
    1821             :         // while Lua call l_punch, for example, this can be NULL
    1822           0 :         if (!playersao)
    1823           0 :                 return;
    1824             : 
    1825           0 :         SendHP(peer_id, playersao->getHP());
    1826           0 :         m_script->player_event(playersao,"health_changed");
    1827             : 
    1828             :         // Send to other clients
    1829           0 :         std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
    1830           0 :         ActiveObjectMessage aom(playersao->getId(), true, str);
    1831           0 :         playersao->m_messages_out.push(aom);
    1832             : }
    1833             : 
    1834           0 : void Server::SendPlayerBreath(u16 peer_id)
    1835             : {
    1836           0 :         DSTACK(__FUNCTION_NAME);
    1837           0 :         PlayerSAO *playersao = getPlayerSAO(peer_id);
    1838             :         assert(playersao);
    1839             : 
    1840           0 :         m_script->player_event(playersao, "breath_changed");
    1841           0 :         SendBreath(peer_id, playersao->getBreath());
    1842           0 : }
    1843             : 
    1844           0 : void Server::SendMovePlayer(u16 peer_id)
    1845             : {
    1846           0 :         DSTACK(__FUNCTION_NAME);
    1847           0 :         Player *player = m_env->getPlayer(peer_id);
    1848             :         assert(player);
    1849             : 
    1850           0 :         NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
    1851           0 :         pkt << player->getPosition() << player->getPitch() << player->getYaw();
    1852             : 
    1853             :         {
    1854           0 :                 v3f pos = player->getPosition();
    1855           0 :                 f32 pitch = player->getPitch();
    1856           0 :                 f32 yaw = player->getYaw();
    1857           0 :                 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
    1858           0 :                                 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
    1859           0 :                                 << " pitch=" << pitch
    1860           0 :                                 << " yaw=" << yaw
    1861           0 :                                 << std::endl;
    1862             :         }
    1863             : 
    1864           0 :         Send(&pkt);
    1865           0 : }
    1866             : 
    1867           0 : void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
    1868             : {
    1869             :         NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
    1870           0 :                 peer_id);
    1871             : 
    1872           0 :         pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
    1873           0 :                         << animation_frames[3] << animation_speed;
    1874             : 
    1875           0 :         Send(&pkt);
    1876           0 : }
    1877             : 
    1878           0 : void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
    1879             : {
    1880           0 :         NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
    1881           0 :         pkt << first << third;
    1882           0 :         Send(&pkt);
    1883           0 : }
    1884           0 : void Server::SendPlayerPrivileges(u16 peer_id)
    1885             : {
    1886           0 :         Player *player = m_env->getPlayer(peer_id);
    1887             :         assert(player);
    1888           0 :         if(player->peer_id == PEER_ID_INEXISTENT)
    1889           0 :                 return;
    1890             : 
    1891           0 :         std::set<std::string> privs;
    1892           0 :         m_script->getAuth(player->getName(), NULL, &privs);
    1893             : 
    1894           0 :         NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
    1895           0 :         pkt << (u16) privs.size();
    1896             : 
    1897           0 :         for(std::set<std::string>::const_iterator i = privs.begin();
    1898           0 :                         i != privs.end(); i++) {
    1899           0 :                 pkt << (*i);
    1900             :         }
    1901             : 
    1902           0 :         Send(&pkt);
    1903             : }
    1904             : 
    1905           0 : void Server::SendPlayerInventoryFormspec(u16 peer_id)
    1906             : {
    1907           0 :         Player *player = m_env->getPlayer(peer_id);
    1908             :         assert(player);
    1909           0 :         if(player->peer_id == PEER_ID_INEXISTENT)
    1910           0 :                 return;
    1911             : 
    1912           0 :         NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
    1913           0 :         pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
    1914           0 :         Send(&pkt);
    1915             : }
    1916             : 
    1917           0 : u32 Server::SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas)
    1918             : {
    1919           0 :         NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
    1920           0 :         pkt.putRawString(datas.c_str(), datas.size());
    1921           0 :         Send(&pkt);
    1922           0 :         return pkt.getSize();
    1923             : }
    1924             : 
    1925           0 : void Server::SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable)
    1926             : {
    1927             :         NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
    1928           0 :                         datas.size(), peer_id);
    1929             : 
    1930           0 :         pkt.putRawString(datas.c_str(), datas.size());
    1931             : 
    1932           0 :         m_clients.send(pkt.getPeerId(),
    1933           0 :                         reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
    1934           0 :                         &pkt, reliable);
    1935             : 
    1936           0 : }
    1937             : 
    1938           0 : s32 Server::playSound(const SimpleSoundSpec &spec,
    1939             :                 const ServerSoundParams &params)
    1940             : {
    1941             :         // Find out initial position of sound
    1942           0 :         bool pos_exists = false;
    1943           0 :         v3f pos = params.getPos(m_env, &pos_exists);
    1944             :         // If position is not found while it should be, cancel sound
    1945           0 :         if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
    1946           0 :                 return -1;
    1947             : 
    1948             :         // Filter destination clients
    1949           0 :         std::vector<u16> dst_clients;
    1950           0 :         if(params.to_player != "")
    1951             :         {
    1952           0 :                 Player *player = m_env->getPlayer(params.to_player.c_str());
    1953           0 :                 if(!player){
    1954           0 :                         infostream<<"Server::playSound: Player \""<<params.to_player
    1955           0 :                                         <<"\" not found"<<std::endl;
    1956           0 :                         return -1;
    1957             :                 }
    1958           0 :                 if(player->peer_id == PEER_ID_INEXISTENT){
    1959           0 :                         infostream<<"Server::playSound: Player \""<<params.to_player
    1960           0 :                                         <<"\" not connected"<<std::endl;
    1961           0 :                         return -1;
    1962             :                 }
    1963           0 :                 dst_clients.push_back(player->peer_id);
    1964             :         }
    1965             :         else {
    1966           0 :                 std::vector<u16> clients = m_clients.getClientIDs();
    1967             : 
    1968           0 :                 for(std::vector<u16>::iterator
    1969           0 :                                 i = clients.begin(); i != clients.end(); ++i) {
    1970           0 :                         Player *player = m_env->getPlayer(*i);
    1971           0 :                         if(!player)
    1972           0 :                                 continue;
    1973             : 
    1974           0 :                         if(pos_exists) {
    1975           0 :                                 if(player->getPosition().getDistanceFrom(pos) >
    1976           0 :                                                 params.max_hear_distance)
    1977           0 :                                         continue;
    1978             :                         }
    1979           0 :                         dst_clients.push_back(*i);
    1980             :                 }
    1981             :         }
    1982             : 
    1983           0 :         if(dst_clients.empty())
    1984           0 :                 return -1;
    1985             : 
    1986             :         // Create the sound
    1987           0 :         s32 id = m_next_sound_id++;
    1988             :         // The sound will exist as a reference in m_playing_sounds
    1989           0 :         m_playing_sounds[id] = ServerPlayingSound();
    1990           0 :         ServerPlayingSound &psound = m_playing_sounds[id];
    1991           0 :         psound.params = params;
    1992             : 
    1993           0 :         NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
    1994           0 :         pkt << id << spec.name << (float) (spec.gain * params.gain)
    1995           0 :                         << (u8) params.type << pos << params.object << params.loop;
    1996             : 
    1997           0 :         for(std::vector<u16>::iterator i = dst_clients.begin();
    1998           0 :                         i != dst_clients.end(); i++) {
    1999           0 :                 psound.clients.insert(*i);
    2000           0 :                 m_clients.send(*i, 0, &pkt, true);
    2001             :         }
    2002           0 :         return id;
    2003             : }
    2004           0 : void Server::stopSound(s32 handle)
    2005             : {
    2006             :         // Get sound reference
    2007             :         std::map<s32, ServerPlayingSound>::iterator i =
    2008           0 :                         m_playing_sounds.find(handle);
    2009           0 :         if(i == m_playing_sounds.end())
    2010           0 :                 return;
    2011           0 :         ServerPlayingSound &psound = i->second;
    2012             : 
    2013           0 :         NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
    2014           0 :         pkt << handle;
    2015             : 
    2016           0 :         for(std::set<u16>::iterator i = psound.clients.begin();
    2017           0 :                         i != psound.clients.end(); i++) {
    2018             :                 // Send as reliable
    2019           0 :                 m_clients.send(*i, 0, &pkt, true);
    2020             :         }
    2021             :         // Remove sound reference
    2022           0 :         m_playing_sounds.erase(i);
    2023             : }
    2024             : 
    2025           0 : void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
    2026             :         std::vector<u16> *far_players, float far_d_nodes)
    2027             : {
    2028           0 :         float maxd = far_d_nodes*BS;
    2029           0 :         v3f p_f = intToFloat(p, BS);
    2030             : 
    2031           0 :         NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
    2032           0 :         pkt << p;
    2033             : 
    2034           0 :         std::vector<u16> clients = m_clients.getClientIDs();
    2035           0 :         for(std::vector<u16>::iterator i = clients.begin();
    2036           0 :                 i != clients.end(); ++i) {
    2037           0 :                 if (far_players) {
    2038             :                         // Get player
    2039           0 :                         if(Player *player = m_env->getPlayer(*i)) {
    2040             :                                 // If player is far away, only set modified blocks not sent
    2041           0 :                                 v3f player_pos = player->getPosition();
    2042           0 :                                 if(player_pos.getDistanceFrom(p_f) > maxd) {
    2043           0 :                                         far_players->push_back(*i);
    2044           0 :                                         continue;
    2045             :                                 }
    2046             :                         }
    2047             :                 }
    2048             : 
    2049             :                 // Send as reliable
    2050           0 :                 m_clients.send(*i, 0, &pkt, true);
    2051             :         }
    2052           0 : }
    2053             : 
    2054           0 : void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
    2055             :                 std::vector<u16> *far_players, float far_d_nodes,
    2056             :                 bool remove_metadata)
    2057             : {
    2058           0 :         float maxd = far_d_nodes*BS;
    2059           0 :         v3f p_f = intToFloat(p, BS);
    2060             : 
    2061           0 :         std::vector<u16> clients = m_clients.getClientIDs();
    2062           0 :         for(std::vector<u16>::iterator i = clients.begin();
    2063           0 :                         i != clients.end(); ++i) {
    2064             : 
    2065           0 :                 if(far_players) {
    2066             :                         // Get player
    2067           0 :                         if(Player *player = m_env->getPlayer(*i)) {
    2068             :                                 // If player is far away, only set modified blocks not sent
    2069           0 :                                 v3f player_pos = player->getPosition();
    2070           0 :                                 if(player_pos.getDistanceFrom(p_f) > maxd) {
    2071           0 :                                         far_players->push_back(*i);
    2072           0 :                                         continue;
    2073             :                                 }
    2074             :                         }
    2075             :                 }
    2076             : 
    2077           0 :                 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
    2078           0 :                 m_clients.Lock();
    2079           0 :                 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
    2080           0 :                 if (client != 0) {
    2081           0 :                         pkt << p << n.param0 << n.param1 << n.param2
    2082           0 :                                         << (u8) (remove_metadata ? 0 : 1);
    2083             : 
    2084           0 :                         if (!remove_metadata) {
    2085           0 :                                 if (client->net_proto_version <= 21) {
    2086             :                                         // Old clients always clear metadata; fix it
    2087             :                                         // by sending the full block again.
    2088           0 :                                         client->SetBlockNotSent(p);
    2089             :                                 }
    2090             :                         }
    2091             :                 }
    2092           0 :                 m_clients.Unlock();
    2093             : 
    2094             :                 // Send as reliable
    2095           0 :                 if (pkt.getSize() > 0)
    2096           0 :                         m_clients.send(*i, 0, &pkt, true);
    2097             :         }
    2098           0 : }
    2099             : 
    2100           0 : void Server::setBlockNotSent(v3s16 p)
    2101             : {
    2102           0 :         std::vector<u16> clients = m_clients.getClientIDs();
    2103           0 :         m_clients.Lock();
    2104           0 :         for(std::vector<u16>::iterator i = clients.begin();
    2105           0 :                 i != clients.end(); ++i) {
    2106           0 :                 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
    2107           0 :                 client->SetBlockNotSent(p);
    2108             :         }
    2109           0 :         m_clients.Unlock();
    2110           0 : }
    2111             : 
    2112           0 : void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
    2113             : {
    2114           0 :         DSTACK(__FUNCTION_NAME);
    2115             : 
    2116           0 :         v3s16 p = block->getPos();
    2117             : 
    2118             :         /*
    2119             :                 Create a packet with the block in the right format
    2120             :         */
    2121             : 
    2122           0 :         std::ostringstream os(std::ios_base::binary);
    2123           0 :         block->serialize(os, ver, false);
    2124           0 :         block->serializeNetworkSpecific(os, net_proto_version);
    2125           0 :         std::string s = os.str();
    2126             : 
    2127           0 :         NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
    2128             : 
    2129           0 :         pkt << p;
    2130           0 :         pkt.putRawString(s.c_str(), s.size());
    2131           0 :         Send(&pkt);
    2132           0 : }
    2133             : 
    2134           0 : void Server::SendBlocks(float dtime)
    2135             : {
    2136           0 :         DSTACK(__FUNCTION_NAME);
    2137             : 
    2138           0 :         JMutexAutoLock envlock(m_env_mutex);
    2139             :         //TODO check if one big lock could be faster then multiple small ones
    2140             : 
    2141           0 :         ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
    2142             : 
    2143           0 :         std::vector<PrioritySortedBlockTransfer> queue;
    2144             : 
    2145           0 :         s32 total_sending = 0;
    2146             : 
    2147             :         {
    2148           0 :                 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
    2149             : 
    2150           0 :                 std::vector<u16> clients = m_clients.getClientIDs();
    2151             : 
    2152           0 :                 m_clients.Lock();
    2153           0 :                 for(std::vector<u16>::iterator i = clients.begin();
    2154           0 :                         i != clients.end(); ++i) {
    2155           0 :                         RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
    2156             : 
    2157           0 :                         if (client == NULL)
    2158           0 :                                 continue;
    2159             : 
    2160           0 :                         total_sending += client->SendingCount();
    2161           0 :                         client->GetNextBlocks(m_env,m_emerge, dtime, queue);
    2162             :                 }
    2163           0 :                 m_clients.Unlock();
    2164             :         }
    2165             : 
    2166             :         // Sort.
    2167             :         // Lowest priority number comes first.
    2168             :         // Lowest is most important.
    2169           0 :         std::sort(queue.begin(), queue.end());
    2170             : 
    2171           0 :         m_clients.Lock();
    2172           0 :         for(u32 i=0; i<queue.size(); i++)
    2173             :         {
    2174             :                 //TODO: Calculate limit dynamically
    2175           0 :                 if(total_sending >= g_settings->getS32
    2176           0 :                                 ("max_simultaneous_block_sends_server_total"))
    2177           0 :                         break;
    2178             : 
    2179           0 :                 PrioritySortedBlockTransfer q = queue[i];
    2180             : 
    2181           0 :                 MapBlock *block = NULL;
    2182             :                 try
    2183             :                 {
    2184           0 :                         block = m_env->getMap().getBlockNoCreate(q.pos);
    2185             :                 }
    2186           0 :                 catch(InvalidPositionException &e)
    2187             :                 {
    2188           0 :                         continue;
    2189             :                 }
    2190             : 
    2191           0 :                 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
    2192             : 
    2193           0 :                 if(!client)
    2194           0 :                         continue;
    2195             : 
    2196           0 :                 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
    2197             : 
    2198           0 :                 client->SentBlock(q.pos);
    2199           0 :                 total_sending++;
    2200             :         }
    2201           0 :         m_clients.Unlock();
    2202           0 : }
    2203             : 
    2204           0 : void Server::fillMediaCache()
    2205             : {
    2206           0 :         DSTACK(__FUNCTION_NAME);
    2207             : 
    2208           0 :         infostream<<"Server: Calculating media file checksums"<<std::endl;
    2209             : 
    2210             :         // Collect all media file paths
    2211           0 :         std::vector<std::string> paths;
    2212           0 :         for(std::vector<ModSpec>::iterator i = m_mods.begin();
    2213           0 :                         i != m_mods.end(); i++) {
    2214           0 :                 const ModSpec &mod = *i;
    2215           0 :                 paths.push_back(mod.path + DIR_DELIM + "textures");
    2216           0 :                 paths.push_back(mod.path + DIR_DELIM + "sounds");
    2217           0 :                 paths.push_back(mod.path + DIR_DELIM + "media");
    2218           0 :                 paths.push_back(mod.path + DIR_DELIM + "models");
    2219             :         }
    2220           0 :         paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
    2221             : 
    2222             :         // Collect media file information from paths into cache
    2223           0 :         for(std::vector<std::string>::iterator i = paths.begin();
    2224           0 :                         i != paths.end(); i++) {
    2225           0 :                 std::string mediapath = *i;
    2226           0 :                 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
    2227           0 :                 for (u32 j = 0; j < dirlist.size(); j++) {
    2228           0 :                         if (dirlist[j].dir) // Ignode dirs
    2229           0 :                                 continue;
    2230           0 :                         std::string filename = dirlist[j].name;
    2231             :                         // If name contains illegal characters, ignore the file
    2232           0 :                         if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
    2233           0 :                                 infostream<<"Server: ignoring illegal file name: \""
    2234           0 :                                                 << filename << "\"" << std::endl;
    2235           0 :                                 continue;
    2236             :                         }
    2237             :                         // If name is not in a supported format, ignore it
    2238             :                         const char *supported_ext[] = {
    2239             :                                 ".png", ".jpg", ".bmp", ".tga",
    2240             :                                 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
    2241             :                                 ".ogg",
    2242             :                                 ".x", ".b3d", ".md2", ".obj",
    2243             :                                 NULL
    2244           0 :                         };
    2245           0 :                         if (removeStringEnd(filename, supported_ext) == ""){
    2246           0 :                                 infostream << "Server: ignoring unsupported file extension: \""
    2247           0 :                                                 << filename << "\"" << std::endl;
    2248           0 :                                 continue;
    2249             :                         }
    2250             :                         // Ok, attempt to load the file and add to cache
    2251           0 :                         std::string filepath = mediapath + DIR_DELIM + filename;
    2252             :                         // Read data
    2253           0 :                         std::ifstream fis(filepath.c_str(), std::ios_base::binary);
    2254           0 :                         if (!fis.good()) {
    2255           0 :                                 errorstream << "Server::fillMediaCache(): Could not open \""
    2256           0 :                                                 << filename << "\" for reading" << std::endl;
    2257           0 :                                 continue;
    2258             :                         }
    2259           0 :                         std::ostringstream tmp_os(std::ios_base::binary);
    2260           0 :                         bool bad = false;
    2261           0 :                         for(;;) {
    2262             :                                 char buf[1024];
    2263           0 :                                 fis.read(buf, 1024);
    2264           0 :                                 std::streamsize len = fis.gcount();
    2265           0 :                                 tmp_os.write(buf, len);
    2266           0 :                                 if (fis.eof())
    2267           0 :                                         break;
    2268           0 :                                 if (!fis.good()) {
    2269           0 :                                         bad = true;
    2270           0 :                                         break;
    2271             :                                 }
    2272             :                         }
    2273           0 :                         if(bad) {
    2274           0 :                                 errorstream<<"Server::fillMediaCache(): Failed to read \""
    2275           0 :                                                 << filename << "\"" << std::endl;
    2276           0 :                                 continue;
    2277             :                         }
    2278           0 :                         if(tmp_os.str().length() == 0) {
    2279           0 :                                 errorstream << "Server::fillMediaCache(): Empty file \""
    2280           0 :                                                 << filepath << "\"" << std::endl;
    2281           0 :                                 continue;
    2282             :                         }
    2283             : 
    2284           0 :                         SHA1 sha1;
    2285           0 :                         sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
    2286             : 
    2287           0 :                         unsigned char *digest = sha1.getDigest();
    2288           0 :                         std::string sha1_base64 = base64_encode(digest, 20);
    2289           0 :                         std::string sha1_hex = hex_encode((char*)digest, 20);
    2290           0 :                         free(digest);
    2291             : 
    2292             :                         // Put in list
    2293           0 :                         m_media[filename] = MediaInfo(filepath, sha1_base64);
    2294           0 :                         verbosestream << "Server: " << sha1_hex << " is " << filename
    2295           0 :                                         << std::endl;
    2296             :                 }
    2297             :         }
    2298           0 : }
    2299             : 
    2300           0 : struct SendableMediaAnnouncement
    2301             : {
    2302             :         std::string name;
    2303             :         std::string sha1_digest;
    2304             : 
    2305           0 :         SendableMediaAnnouncement(const std::string &name_="",
    2306             :                                   const std::string &sha1_digest_=""):
    2307             :                 name(name_),
    2308           0 :                 sha1_digest(sha1_digest_)
    2309           0 :         {}
    2310             : };
    2311             : 
    2312           0 : void Server::sendMediaAnnouncement(u16 peer_id)
    2313             : {
    2314           0 :         DSTACK(__FUNCTION_NAME);
    2315             : 
    2316           0 :         verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
    2317           0 :                         <<std::endl;
    2318             : 
    2319           0 :         std::vector<SendableMediaAnnouncement> file_announcements;
    2320             : 
    2321           0 :         for (std::map<std::string, MediaInfo>::iterator i = m_media.begin();
    2322           0 :                         i != m_media.end(); i++){
    2323             :                 // Put in list
    2324           0 :                 file_announcements.push_back(
    2325           0 :                                 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
    2326             :         }
    2327             : 
    2328             :         // Make packet
    2329           0 :         std::ostringstream os(std::ios_base::binary);
    2330             : 
    2331           0 :         NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
    2332           0 :         pkt << (u16) file_announcements.size();
    2333             : 
    2334           0 :         for (std::vector<SendableMediaAnnouncement>::iterator
    2335           0 :                         j = file_announcements.begin();
    2336           0 :                         j != file_announcements.end(); ++j) {
    2337           0 :                 pkt << j->name << j->sha1_digest;
    2338             :         }
    2339             : 
    2340           0 :         pkt << g_settings->get("remote_media");
    2341           0 :         Send(&pkt);
    2342           0 : }
    2343             : 
    2344           0 : struct SendableMedia
    2345             : {
    2346             :         std::string name;
    2347             :         std::string path;
    2348             :         std::string data;
    2349             : 
    2350           0 :         SendableMedia(const std::string &name_="", const std::string &path_="",
    2351             :                       const std::string &data_=""):
    2352             :                 name(name_),
    2353             :                 path(path_),
    2354           0 :                 data(data_)
    2355           0 :         {}
    2356             : };
    2357             : 
    2358           0 : void Server::sendRequestedMedia(u16 peer_id,
    2359             :                 const std::vector<std::string> &tosend)
    2360             : {
    2361           0 :         DSTACK(__FUNCTION_NAME);
    2362             : 
    2363           0 :         verbosestream<<"Server::sendRequestedMedia(): "
    2364           0 :                         <<"Sending files to client"<<std::endl;
    2365             : 
    2366             :         /* Read files */
    2367             : 
    2368             :         // Put 5kB in one bunch (this is not accurate)
    2369           0 :         u32 bytes_per_bunch = 5000;
    2370             : 
    2371           0 :         std::vector< std::vector<SendableMedia> > file_bunches;
    2372           0 :         file_bunches.push_back(std::vector<SendableMedia>());
    2373             : 
    2374           0 :         u32 file_size_bunch_total = 0;
    2375             : 
    2376           0 :         for(std::vector<std::string>::const_iterator i = tosend.begin();
    2377           0 :                         i != tosend.end(); ++i) {
    2378           0 :                 const std::string &name = *i;
    2379             : 
    2380           0 :                 if(m_media.find(name) == m_media.end()) {
    2381           0 :                         errorstream<<"Server::sendRequestedMedia(): Client asked for "
    2382           0 :                                         <<"unknown file \""<<(name)<<"\""<<std::endl;
    2383           0 :                         continue;
    2384             :                 }
    2385             : 
    2386             :                 //TODO get path + name
    2387           0 :                 std::string tpath = m_media[name].path;
    2388             : 
    2389             :                 // Read data
    2390           0 :                 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
    2391           0 :                 if(fis.good() == false){
    2392           0 :                         errorstream<<"Server::sendRequestedMedia(): Could not open \""
    2393           0 :                                         <<tpath<<"\" for reading"<<std::endl;
    2394           0 :                         continue;
    2395             :                 }
    2396           0 :                 std::ostringstream tmp_os(std::ios_base::binary);
    2397           0 :                 bool bad = false;
    2398           0 :                 for(;;) {
    2399             :                         char buf[1024];
    2400           0 :                         fis.read(buf, 1024);
    2401           0 :                         std::streamsize len = fis.gcount();
    2402           0 :                         tmp_os.write(buf, len);
    2403           0 :                         file_size_bunch_total += len;
    2404           0 :                         if(fis.eof())
    2405           0 :                                 break;
    2406           0 :                         if(!fis.good()) {
    2407           0 :                                 bad = true;
    2408           0 :                                 break;
    2409             :                         }
    2410             :                 }
    2411           0 :                 if(bad) {
    2412           0 :                         errorstream<<"Server::sendRequestedMedia(): Failed to read \""
    2413           0 :                                         <<name<<"\""<<std::endl;
    2414           0 :                         continue;
    2415             :                 }
    2416             :                 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
    2417             :                                 <<tname<<"\""<<std::endl;*/
    2418             :                 // Put in list
    2419           0 :                 file_bunches[file_bunches.size()-1].push_back(
    2420           0 :                                 SendableMedia(name, tpath, tmp_os.str()));
    2421             : 
    2422             :                 // Start next bunch if got enough data
    2423           0 :                 if(file_size_bunch_total >= bytes_per_bunch) {
    2424           0 :                         file_bunches.push_back(std::vector<SendableMedia>());
    2425           0 :                         file_size_bunch_total = 0;
    2426             :                 }
    2427             : 
    2428             :         }
    2429             : 
    2430             :         /* Create and send packets */
    2431             : 
    2432           0 :         u16 num_bunches = file_bunches.size();
    2433           0 :         for(u16 i = 0; i < num_bunches; i++) {
    2434             :                 /*
    2435             :                         u16 command
    2436             :                         u16 total number of texture bunches
    2437             :                         u16 index of this bunch
    2438             :                         u32 number of files in this bunch
    2439             :                         for each file {
    2440             :                                 u16 length of name
    2441             :                                 string name
    2442             :                                 u32 length of data
    2443             :                                 data
    2444             :                         }
    2445             :                 */
    2446             : 
    2447           0 :                 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
    2448           0 :                 pkt << num_bunches << i << (u32) file_bunches[i].size();
    2449             : 
    2450           0 :                 for(std::vector<SendableMedia>::iterator
    2451           0 :                                 j = file_bunches[i].begin();
    2452           0 :                                 j != file_bunches[i].end(); ++j) {
    2453           0 :                         pkt << j->name;
    2454           0 :                         pkt.putLongString(j->data);
    2455             :                 }
    2456             : 
    2457           0 :                 verbosestream << "Server::sendRequestedMedia(): bunch "
    2458           0 :                                 << i << "/" << num_bunches
    2459           0 :                                 << " files=" << file_bunches[i].size()
    2460           0 :                                 << " size="  << pkt.getSize() << std::endl;
    2461           0 :                 Send(&pkt);
    2462             :         }
    2463           0 : }
    2464             : 
    2465           0 : void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
    2466             : {
    2467           0 :         if(m_detached_inventories.count(name) == 0) {
    2468           0 :                 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
    2469           0 :                 return;
    2470             :         }
    2471           0 :         Inventory *inv = m_detached_inventories[name];
    2472           0 :         std::ostringstream os(std::ios_base::binary);
    2473             : 
    2474           0 :         os << serializeString(name);
    2475           0 :         inv->serialize(os);
    2476             : 
    2477             :         // Make data buffer
    2478           0 :         std::string s = os.str();
    2479             : 
    2480           0 :         NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
    2481           0 :         pkt.putRawString(s.c_str(), s.size());
    2482             : 
    2483           0 :         if (peer_id != PEER_ID_INEXISTENT) {
    2484           0 :                 Send(&pkt);
    2485             :         }
    2486             :         else {
    2487           0 :                 m_clients.sendToAll(0, &pkt, true);
    2488             :         }
    2489             : }
    2490             : 
    2491           0 : void Server::sendDetachedInventories(u16 peer_id)
    2492             : {
    2493           0 :         DSTACK(__FUNCTION_NAME);
    2494             : 
    2495           0 :         for(std::map<std::string, Inventory*>::iterator
    2496           0 :                         i = m_detached_inventories.begin();
    2497           0 :                         i != m_detached_inventories.end(); i++) {
    2498           0 :                 const std::string &name = i->first;
    2499             :                 //Inventory *inv = i->second;
    2500           0 :                 sendDetachedInventory(name, peer_id);
    2501             :         }
    2502           0 : }
    2503             : 
    2504             : /*
    2505             :         Something random
    2506             : */
    2507             : 
    2508           0 : void Server::DiePlayer(u16 peer_id)
    2509             : {
    2510           0 :         DSTACK(__FUNCTION_NAME);
    2511             : 
    2512           0 :         PlayerSAO *playersao = getPlayerSAO(peer_id);
    2513             :         assert(playersao);
    2514             : 
    2515           0 :         infostream << "Server::DiePlayer(): Player "
    2516           0 :                         << playersao->getPlayer()->getName()
    2517           0 :                         << " dies" << std::endl;
    2518             : 
    2519           0 :         playersao->setHP(0);
    2520             : 
    2521             :         // Trigger scripted stuff
    2522           0 :         m_script->on_dieplayer(playersao);
    2523             : 
    2524           0 :         SendPlayerHP(peer_id);
    2525           0 :         SendDeathscreen(peer_id, false, v3f(0,0,0));
    2526           0 : }
    2527             : 
    2528           0 : void Server::RespawnPlayer(u16 peer_id)
    2529             : {
    2530           0 :         DSTACK(__FUNCTION_NAME);
    2531             : 
    2532           0 :         PlayerSAO *playersao = getPlayerSAO(peer_id);
    2533             :         assert(playersao);
    2534             : 
    2535           0 :         infostream << "Server::RespawnPlayer(): Player "
    2536           0 :                         << playersao->getPlayer()->getName()
    2537           0 :                         << " respawns" << std::endl;
    2538             : 
    2539           0 :         playersao->setHP(PLAYER_MAX_HP);
    2540           0 :         playersao->setBreath(PLAYER_MAX_BREATH);
    2541             : 
    2542           0 :         SendPlayerHP(peer_id);
    2543           0 :         SendPlayerBreath(peer_id);
    2544             : 
    2545           0 :         bool repositioned = m_script->on_respawnplayer(playersao);
    2546           0 :         if(!repositioned){
    2547           0 :                 v3f pos = findSpawnPos();
    2548             :                 // setPos will send the new position to client
    2549           0 :                 playersao->setPos(pos);
    2550             :         }
    2551           0 : }
    2552           0 : void Server::DenySudoAccess(u16 peer_id)
    2553             : {
    2554           0 :         DSTACK(__FUNCTION_NAME);
    2555             : 
    2556           0 :         NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
    2557           0 :         Send(&pkt);
    2558           0 : }
    2559             : 
    2560           0 : void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
    2561             : {
    2562           0 :         DSTACK(__FUNCTION_NAME);
    2563             : 
    2564           0 :         SendAccessDenied(peer_id, reason, custom_reason);
    2565           0 :         m_clients.event(peer_id, CSE_SetDenied);
    2566           0 :         m_con.DisconnectPeer(peer_id);
    2567           0 : }
    2568             : 
    2569             : // 13/03/15: remove this function when protocol version 25 will become
    2570             : // the minimum version for MT users, maybe in 1 year
    2571           0 : void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
    2572             : {
    2573           0 :         DSTACK(__FUNCTION_NAME);
    2574             : 
    2575           0 :         SendAccessDenied_Legacy(peer_id, reason);
    2576           0 :         m_clients.event(peer_id, CSE_SetDenied);
    2577           0 :         m_con.DisconnectPeer(peer_id);
    2578           0 : }
    2579             : 
    2580           0 : void Server::acceptAuth(u16 peer_id, bool forSudoMode)
    2581             : {
    2582           0 :         DSTACK(__FUNCTION_NAME);
    2583             : 
    2584           0 :         if (!forSudoMode) {
    2585           0 :                 RemoteClient* client = getClient(peer_id, CS_Invalid);
    2586             : 
    2587           0 :                 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
    2588             : 
    2589             :                 // Right now, the auth mechs don't change between login and sudo mode.
    2590           0 :                 u32 sudo_auth_mechs = client->allowed_auth_mechs;
    2591           0 :                 client->allowed_sudo_mechs = sudo_auth_mechs;
    2592             : 
    2593           0 :                 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
    2594           0 :                                 << g_settings->getFloat("dedicated_server_step")
    2595           0 :                                 << sudo_auth_mechs;
    2596             : 
    2597           0 :                 Send(&resp_pkt);
    2598           0 :                 m_clients.event(peer_id, CSE_AuthAccept);
    2599             :         } else {
    2600           0 :                 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
    2601             : 
    2602             :                 // We only support SRP right now
    2603           0 :                 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
    2604             : 
    2605           0 :                 resp_pkt << sudo_auth_mechs;
    2606           0 :                 Send(&resp_pkt);
    2607           0 :                 m_clients.event(peer_id, CSE_SudoSuccess);
    2608             :         }
    2609           0 : }
    2610             : 
    2611           0 : void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
    2612             : {
    2613           0 :         DSTACK(__FUNCTION_NAME);
    2614           0 :         std::wstring message;
    2615             :         {
    2616             :                 /*
    2617             :                         Clear references to playing sounds
    2618             :                 */
    2619           0 :                 for(std::map<s32, ServerPlayingSound>::iterator
    2620           0 :                                 i = m_playing_sounds.begin();
    2621           0 :                                 i != m_playing_sounds.end();)
    2622             :                 {
    2623           0 :                         ServerPlayingSound &psound = i->second;
    2624           0 :                         psound.clients.erase(peer_id);
    2625           0 :                         if(psound.clients.empty())
    2626           0 :                                 m_playing_sounds.erase(i++);
    2627             :                         else
    2628           0 :                                 i++;
    2629             :                 }
    2630             : 
    2631           0 :                 Player *player = m_env->getPlayer(peer_id);
    2632             : 
    2633             :                 // Collect information about leaving in chat
    2634             :                 {
    2635           0 :                         if(player != NULL && reason != CDR_DENY)
    2636             :                         {
    2637           0 :                                 std::wstring name = narrow_to_wide(player->getName());
    2638           0 :                                 message += L"*** ";
    2639           0 :                                 message += name;
    2640           0 :                                 message += L" left the game.";
    2641           0 :                                 if(reason == CDR_TIMEOUT)
    2642           0 :                                         message += L" (timed out)";
    2643             :                         }
    2644             :                 }
    2645             : 
    2646             :                 /* Run scripts and remove from environment */
    2647             :                 {
    2648           0 :                         if(player != NULL)
    2649             :                         {
    2650           0 :                                 PlayerSAO *playersao = player->getPlayerSAO();
    2651             :                                 assert(playersao);
    2652             : 
    2653           0 :                                 m_script->on_leaveplayer(playersao);
    2654             : 
    2655           0 :                                 playersao->disconnected();
    2656             :                         }
    2657             :                 }
    2658             : 
    2659             :                 /*
    2660             :                         Print out action
    2661             :                 */
    2662             :                 {
    2663           0 :                         if(player != NULL && reason != CDR_DENY) {
    2664           0 :                                 std::ostringstream os(std::ios_base::binary);
    2665           0 :                                 std::vector<u16> clients = m_clients.getClientIDs();
    2666             : 
    2667           0 :                                 for(std::vector<u16>::iterator i = clients.begin();
    2668           0 :                                         i != clients.end(); ++i) {
    2669             :                                         // Get player
    2670           0 :                                         Player *player = m_env->getPlayer(*i);
    2671           0 :                                         if(!player)
    2672           0 :                                                 continue;
    2673             : 
    2674             :                                         // Get name of player
    2675           0 :                                         os << player->getName() << " ";
    2676             :                                 }
    2677             : 
    2678           0 :                                 actionstream << player->getName() << " "
    2679           0 :                                                 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
    2680           0 :                                                 << " List of players: " << os.str() << std::endl;
    2681             :                         }
    2682             :                 }
    2683             :                 {
    2684           0 :                         JMutexAutoLock env_lock(m_env_mutex);
    2685           0 :                         m_clients.DeleteClient(peer_id);
    2686             :                 }
    2687             :         }
    2688             : 
    2689             :         // Send leave chat message to all remaining clients
    2690           0 :         if(message.length() != 0)
    2691           0 :                 SendChatMessage(PEER_ID_INEXISTENT,message);
    2692           0 : }
    2693             : 
    2694           0 : void Server::UpdateCrafting(Player* player)
    2695             : {
    2696           0 :         DSTACK(__FUNCTION_NAME);
    2697             : 
    2698             :         // Get a preview for crafting
    2699           0 :         ItemStack preview;
    2700           0 :         InventoryLocation loc;
    2701           0 :         loc.setPlayer(player->getName());
    2702           0 :         std::vector<ItemStack> output_replacements;
    2703           0 :         getCraftingResult(&player->inventory, preview, output_replacements, false, this);
    2704           0 :         m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
    2705             : 
    2706             :         // Put the new preview in
    2707           0 :         InventoryList *plist = player->inventory.getList("craftpreview");
    2708           0 :         sanity_check(plist);
    2709           0 :         sanity_check(plist->getSize() >= 1);
    2710           0 :         plist->changeItem(0, preview);
    2711           0 : }
    2712             : 
    2713           0 : RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
    2714             : {
    2715           0 :         RemoteClient *client = getClientNoEx(peer_id,state_min);
    2716           0 :         if(!client)
    2717           0 :                 throw ClientNotFoundException("Client not found");
    2718             : 
    2719           0 :         return client;
    2720             : }
    2721           0 : RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
    2722             : {
    2723           0 :         return m_clients.getClientNoEx(peer_id, state_min);
    2724             : }
    2725             : 
    2726           0 : std::string Server::getPlayerName(u16 peer_id)
    2727             : {
    2728           0 :         Player *player = m_env->getPlayer(peer_id);
    2729           0 :         if(player == NULL)
    2730           0 :                 return "[id="+itos(peer_id)+"]";
    2731           0 :         return player->getName();
    2732             : }
    2733             : 
    2734           0 : PlayerSAO* Server::getPlayerSAO(u16 peer_id)
    2735             : {
    2736           0 :         Player *player = m_env->getPlayer(peer_id);
    2737           0 :         if(player == NULL)
    2738           0 :                 return NULL;
    2739           0 :         return player->getPlayerSAO();
    2740             : }
    2741             : 
    2742           0 : std::wstring Server::getStatusString()
    2743             : {
    2744           0 :         std::wostringstream os(std::ios_base::binary);
    2745           0 :         os<<L"# Server: ";
    2746             :         // Version
    2747           0 :         os<<L"version="<<narrow_to_wide(g_version_string);
    2748             :         // Uptime
    2749           0 :         os<<L", uptime="<<m_uptime.get();
    2750             :         // Max lag estimate
    2751           0 :         os<<L", max_lag="<<m_env->getMaxLagEstimate();
    2752             :         // Information about clients
    2753           0 :         bool first = true;
    2754           0 :         os<<L", clients={";
    2755           0 :         std::vector<u16> clients = m_clients.getClientIDs();
    2756           0 :         for(std::vector<u16>::iterator i = clients.begin();
    2757           0 :                 i != clients.end(); ++i) {
    2758             :                 // Get player
    2759           0 :                 Player *player = m_env->getPlayer(*i);
    2760             :                 // Get name of player
    2761           0 :                 std::wstring name = L"unknown";
    2762           0 :                 if(player != NULL)
    2763           0 :                         name = narrow_to_wide(player->getName());
    2764             :                 // Add name to information string
    2765           0 :                 if(!first)
    2766           0 :                         os << L", ";
    2767             :                 else
    2768           0 :                         first = false;
    2769           0 :                 os << name;
    2770             :         }
    2771           0 :         os << L"}";
    2772           0 :         if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
    2773           0 :                 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
    2774           0 :         if(g_settings->get("motd") != "")
    2775           0 :                 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
    2776           0 :         return os.str();
    2777             : }
    2778             : 
    2779           0 : std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
    2780             : {
    2781           0 :         std::set<std::string> privs;
    2782           0 :         m_script->getAuth(name, NULL, &privs);
    2783           0 :         return privs;
    2784             : }
    2785             : 
    2786           0 : bool Server::checkPriv(const std::string &name, const std::string &priv)
    2787             : {
    2788           0 :         std::set<std::string> privs = getPlayerEffectivePrivs(name);
    2789           0 :         return (privs.count(priv) != 0);
    2790             : }
    2791             : 
    2792           0 : void Server::reportPrivsModified(const std::string &name)
    2793             : {
    2794           0 :         if(name == "") {
    2795           0 :                 std::vector<u16> clients = m_clients.getClientIDs();
    2796           0 :                 for(std::vector<u16>::iterator i = clients.begin();
    2797           0 :                                 i != clients.end(); ++i) {
    2798           0 :                         Player *player = m_env->getPlayer(*i);
    2799           0 :                         reportPrivsModified(player->getName());
    2800             :                 }
    2801             :         } else {
    2802           0 :                 Player *player = m_env->getPlayer(name.c_str());
    2803           0 :                 if(!player)
    2804           0 :                         return;
    2805           0 :                 SendPlayerPrivileges(player->peer_id);
    2806           0 :                 PlayerSAO *sao = player->getPlayerSAO();
    2807           0 :                 if(!sao)
    2808           0 :                         return;
    2809           0 :                 sao->updatePrivileges(
    2810           0 :                                 getPlayerEffectivePrivs(name),
    2811           0 :                                 isSingleplayer());
    2812             :         }
    2813             : }
    2814             : 
    2815           0 : void Server::reportInventoryFormspecModified(const std::string &name)
    2816             : {
    2817           0 :         Player *player = m_env->getPlayer(name.c_str());
    2818           0 :         if(!player)
    2819           0 :                 return;
    2820           0 :         SendPlayerInventoryFormspec(player->peer_id);
    2821             : }
    2822             : 
    2823           0 : void Server::setIpBanned(const std::string &ip, const std::string &name)
    2824             : {
    2825           0 :         m_banmanager->add(ip, name);
    2826           0 : }
    2827             : 
    2828           0 : void Server::unsetIpBanned(const std::string &ip_or_name)
    2829             : {
    2830           0 :         m_banmanager->remove(ip_or_name);
    2831           0 : }
    2832             : 
    2833           0 : std::string Server::getBanDescription(const std::string &ip_or_name)
    2834             : {
    2835           0 :         return m_banmanager->getBanDescription(ip_or_name);
    2836             : }
    2837             : 
    2838           0 : void Server::notifyPlayer(const char *name, const std::wstring &msg)
    2839             : {
    2840           0 :         Player *player = m_env->getPlayer(name);
    2841           0 :         if(!player)
    2842           0 :                 return;
    2843             : 
    2844           0 :         if (player->peer_id == PEER_ID_INEXISTENT)
    2845           0 :                 return;
    2846             : 
    2847           0 :         SendChatMessage(player->peer_id, msg);
    2848             : }
    2849             : 
    2850           0 : bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
    2851             : {
    2852           0 :         Player *player = m_env->getPlayer(playername);
    2853             : 
    2854           0 :         if(!player)
    2855             :         {
    2856           0 :                 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
    2857           0 :                 return false;
    2858             :         }
    2859             : 
    2860           0 :         SendShowFormspecMessage(player->peer_id, formspec, formname);
    2861           0 :         return true;
    2862             : }
    2863             : 
    2864           0 : u32 Server::hudAdd(Player *player, HudElement *form) {
    2865           0 :         if (!player)
    2866           0 :                 return -1;
    2867             : 
    2868           0 :         u32 id = player->addHud(form);
    2869             : 
    2870           0 :         SendHUDAdd(player->peer_id, id, form);
    2871             : 
    2872           0 :         return id;
    2873             : }
    2874             : 
    2875           0 : bool Server::hudRemove(Player *player, u32 id) {
    2876           0 :         if (!player)
    2877           0 :                 return false;
    2878             : 
    2879           0 :         HudElement* todel = player->removeHud(id);
    2880             : 
    2881           0 :         if (!todel)
    2882           0 :                 return false;
    2883             : 
    2884           0 :         delete todel;
    2885             : 
    2886           0 :         SendHUDRemove(player->peer_id, id);
    2887           0 :         return true;
    2888             : }
    2889             : 
    2890           0 : bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
    2891           0 :         if (!player)
    2892           0 :                 return false;
    2893             : 
    2894           0 :         SendHUDChange(player->peer_id, id, stat, data);
    2895           0 :         return true;
    2896             : }
    2897             : 
    2898           0 : bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
    2899           0 :         if (!player)
    2900           0 :                 return false;
    2901             : 
    2902           0 :         SendHUDSetFlags(player->peer_id, flags, mask);
    2903           0 :         player->hud_flags = flags;
    2904             : 
    2905           0 :         PlayerSAO* playersao = player->getPlayerSAO();
    2906             : 
    2907           0 :         if (playersao == NULL)
    2908           0 :                 return false;
    2909             : 
    2910           0 :         m_script->player_event(playersao, "hud_changed");
    2911           0 :         return true;
    2912             : }
    2913             : 
    2914           0 : bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
    2915           0 :         if (!player)
    2916           0 :                 return false;
    2917           0 :         if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
    2918           0 :                 return false;
    2919             : 
    2920           0 :         player->setHotbarItemcount(hotbar_itemcount);
    2921           0 :         std::ostringstream os(std::ios::binary);
    2922           0 :         writeS32(os, hotbar_itemcount);
    2923           0 :         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
    2924           0 :         return true;
    2925             : }
    2926             : 
    2927           0 : s32 Server::hudGetHotbarItemcount(Player *player) {
    2928           0 :         if (!player)
    2929           0 :                 return 0;
    2930           0 :         return player->getHotbarItemcount();
    2931             : }
    2932             : 
    2933           0 : void Server::hudSetHotbarImage(Player *player, std::string name) {
    2934           0 :         if (!player)
    2935           0 :                 return;
    2936             : 
    2937           0 :         player->setHotbarImage(name);
    2938           0 :         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
    2939             : }
    2940             : 
    2941           0 : std::string Server::hudGetHotbarImage(Player *player) {
    2942           0 :         if (!player)
    2943           0 :                 return "";
    2944           0 :         return player->getHotbarImage();
    2945             : }
    2946             : 
    2947           0 : void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
    2948           0 :         if (!player)
    2949           0 :                 return;
    2950             : 
    2951           0 :         player->setHotbarSelectedImage(name);
    2952           0 :         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
    2953             : }
    2954             : 
    2955           0 : std::string Server::hudGetHotbarSelectedImage(Player *player) {
    2956           0 :         if (!player)
    2957           0 :                 return "";
    2958             : 
    2959           0 :         return player->getHotbarSelectedImage();
    2960             : }
    2961             : 
    2962           0 : bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
    2963             : {
    2964           0 :         if (!player)
    2965           0 :                 return false;
    2966             : 
    2967           0 :         player->setLocalAnimations(animation_frames, frame_speed);
    2968           0 :         SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
    2969           0 :         return true;
    2970             : }
    2971             : 
    2972           0 : bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
    2973             : {
    2974           0 :         if (!player)
    2975           0 :                 return false;
    2976             : 
    2977           0 :         player->eye_offset_first = first;
    2978           0 :         player->eye_offset_third = third;
    2979           0 :         SendEyeOffset(player->peer_id, first, third);
    2980           0 :         return true;
    2981             : }
    2982             : 
    2983           0 : bool Server::setSky(Player *player, const video::SColor &bgcolor,
    2984             :                 const std::string &type, const std::vector<std::string> &params)
    2985             : {
    2986           0 :         if (!player)
    2987           0 :                 return false;
    2988             : 
    2989           0 :         player->setSky(bgcolor, type, params);
    2990           0 :         SendSetSky(player->peer_id, bgcolor, type, params);
    2991           0 :         return true;
    2992             : }
    2993             : 
    2994           0 : bool Server::overrideDayNightRatio(Player *player, bool do_override,
    2995             :                 float ratio)
    2996             : {
    2997           0 :         if (!player)
    2998           0 :                 return false;
    2999             : 
    3000           0 :         player->overrideDayNightRatio(do_override, ratio);
    3001           0 :         SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
    3002           0 :         return true;
    3003             : }
    3004             : 
    3005           0 : void Server::notifyPlayers(const std::wstring &msg)
    3006             : {
    3007           0 :         SendChatMessage(PEER_ID_INEXISTENT,msg);
    3008           0 : }
    3009             : 
    3010           0 : void Server::spawnParticle(const char *playername, v3f pos,
    3011             :                 v3f velocity, v3f acceleration,
    3012             :                 float expirationtime, float size, bool
    3013             :                 collisiondetection, bool vertical, std::string texture)
    3014             : {
    3015           0 :         Player *player = m_env->getPlayer(playername);
    3016           0 :         if(!player)
    3017           0 :                 return;
    3018           0 :         SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
    3019           0 :                         expirationtime, size, collisiondetection, vertical, texture);
    3020             : }
    3021             : 
    3022           0 : void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
    3023             :                 float expirationtime, float size,
    3024             :                 bool collisiondetection, bool vertical, std::string texture)
    3025             : {
    3026           0 :         SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
    3027           0 :                         expirationtime, size, collisiondetection, vertical, texture);
    3028           0 : }
    3029             : 
    3030           0 : u32 Server::addParticleSpawner(const char *playername,
    3031             :                 u16 amount, float spawntime,
    3032             :                 v3f minpos, v3f maxpos,
    3033             :                 v3f minvel, v3f maxvel,
    3034             :                 v3f minacc, v3f maxacc,
    3035             :                 float minexptime, float maxexptime,
    3036             :                 float minsize, float maxsize,
    3037             :                 bool collisiondetection, bool vertical, std::string texture)
    3038             : {
    3039           0 :         Player *player = m_env->getPlayer(playername);
    3040           0 :         if(!player)
    3041           0 :                 return -1;
    3042             : 
    3043           0 :         u32 id = 0;
    3044           0 :         for(;;) // look for unused particlespawner id
    3045             :         {
    3046           0 :                 id++;
    3047           0 :                 if (std::find(m_particlespawner_ids.begin(),
    3048           0 :                                 m_particlespawner_ids.end(), id)
    3049           0 :                                 == m_particlespawner_ids.end())
    3050             :                 {
    3051           0 :                         m_particlespawner_ids.push_back(id);
    3052           0 :                         break;
    3053             :                 }
    3054             :         }
    3055             : 
    3056           0 :         SendAddParticleSpawner(player->peer_id, amount, spawntime,
    3057             :                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
    3058             :                 minexptime, maxexptime, minsize, maxsize,
    3059           0 :                 collisiondetection, vertical, texture, id);
    3060             : 
    3061           0 :         return id;
    3062             : }
    3063             : 
    3064           0 : u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
    3065             :                 v3f minpos, v3f maxpos,
    3066             :                 v3f minvel, v3f maxvel,
    3067             :                 v3f minacc, v3f maxacc,
    3068             :                 float minexptime, float maxexptime,
    3069             :                 float minsize, float maxsize,
    3070             :                 bool collisiondetection, bool vertical, std::string texture)
    3071             : {
    3072           0 :         u32 id = 0;
    3073           0 :         for(;;) // look for unused particlespawner id
    3074             :         {
    3075           0 :                 id++;
    3076           0 :                 if (std::find(m_particlespawner_ids.begin(),
    3077           0 :                                 m_particlespawner_ids.end(), id)
    3078           0 :                                 == m_particlespawner_ids.end())
    3079             :                 {
    3080           0 :                         m_particlespawner_ids.push_back(id);
    3081           0 :                         break;
    3082             :                 }
    3083             :         }
    3084             : 
    3085           0 :         SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
    3086             :                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
    3087             :                 minexptime, maxexptime, minsize, maxsize,
    3088           0 :                 collisiondetection, vertical, texture, id);
    3089             : 
    3090           0 :         return id;
    3091             : }
    3092             : 
    3093           0 : void Server::deleteParticleSpawner(const char *playername, u32 id)
    3094             : {
    3095           0 :         Player *player = m_env->getPlayer(playername);
    3096           0 :         if(!player)
    3097           0 :                 return;
    3098             : 
    3099             :         m_particlespawner_ids.erase(
    3100             :                         std::remove(m_particlespawner_ids.begin(),
    3101             :                         m_particlespawner_ids.end(), id),
    3102           0 :                         m_particlespawner_ids.end());
    3103           0 :         SendDeleteParticleSpawner(player->peer_id, id);
    3104             : }
    3105             : 
    3106           0 : void Server::deleteParticleSpawnerAll(u32 id)
    3107             : {
    3108             :         m_particlespawner_ids.erase(
    3109             :                         std::remove(m_particlespawner_ids.begin(),
    3110             :                         m_particlespawner_ids.end(), id),
    3111           0 :                         m_particlespawner_ids.end());
    3112           0 :         SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
    3113           0 : }
    3114             : 
    3115           0 : Inventory* Server::createDetachedInventory(const std::string &name)
    3116             : {
    3117           0 :         if(m_detached_inventories.count(name) > 0){
    3118           0 :                 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
    3119           0 :                 delete m_detached_inventories[name];
    3120             :         } else {
    3121           0 :                 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
    3122             :         }
    3123           0 :         Inventory *inv = new Inventory(m_itemdef);
    3124           0 :         sanity_check(inv);
    3125           0 :         m_detached_inventories[name] = inv;
    3126             :         //TODO find a better way to do this
    3127           0 :         sendDetachedInventory(name,PEER_ID_INEXISTENT);
    3128           0 :         return inv;
    3129             : }
    3130             : 
    3131             : class BoolScopeSet
    3132             : {
    3133             : public:
    3134             :         BoolScopeSet(bool *dst, bool val):
    3135             :                 m_dst(dst)
    3136             :         {
    3137             :                 m_orig_state = *m_dst;
    3138             :                 *m_dst = val;
    3139             :         }
    3140             :         ~BoolScopeSet()
    3141             :         {
    3142             :                 *m_dst = m_orig_state;
    3143             :         }
    3144             : private:
    3145             :         bool *m_dst;
    3146             :         bool m_orig_state;
    3147             : };
    3148             : 
    3149             : // actions: time-reversed list
    3150             : // Return value: success/failure
    3151           0 : bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
    3152             :                 std::list<std::string> *log)
    3153             : {
    3154           0 :         infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
    3155           0 :         ServerMap *map = (ServerMap*)(&m_env->getMap());
    3156             : 
    3157             :         // Fail if no actions to handle
    3158           0 :         if(actions.empty()){
    3159           0 :                 log->push_back("Nothing to do.");
    3160           0 :                 return false;
    3161             :         }
    3162             : 
    3163           0 :         int num_tried = 0;
    3164           0 :         int num_failed = 0;
    3165             : 
    3166           0 :         for(std::list<RollbackAction>::const_iterator
    3167           0 :                         i = actions.begin();
    3168           0 :                         i != actions.end(); i++)
    3169             :         {
    3170           0 :                 const RollbackAction &action = *i;
    3171           0 :                 num_tried++;
    3172           0 :                 bool success = action.applyRevert(map, this, this);
    3173           0 :                 if(!success){
    3174           0 :                         num_failed++;
    3175           0 :                         std::ostringstream os;
    3176           0 :                         os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
    3177           0 :                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
    3178           0 :                         if(log)
    3179           0 :                                 log->push_back(os.str());
    3180             :                 }else{
    3181           0 :                         std::ostringstream os;
    3182           0 :                         os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
    3183           0 :                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
    3184           0 :                         if(log)
    3185           0 :                                 log->push_back(os.str());
    3186             :                 }
    3187             :         }
    3188             : 
    3189           0 :         infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
    3190           0 :                         <<" failed"<<std::endl;
    3191             : 
    3192             :         // Call it done if less than half failed
    3193           0 :         return num_failed <= num_tried/2;
    3194             : }
    3195             : 
    3196             : // IGameDef interface
    3197             : // Under envlock
    3198           0 : IItemDefManager* Server::getItemDefManager()
    3199             : {
    3200           0 :         return m_itemdef;
    3201             : }
    3202           0 : INodeDefManager* Server::getNodeDefManager()
    3203             : {
    3204           0 :         return m_nodedef;
    3205             : }
    3206           0 : ICraftDefManager* Server::getCraftDefManager()
    3207             : {
    3208           0 :         return m_craftdef;
    3209             : }
    3210           0 : ITextureSource* Server::getTextureSource()
    3211             : {
    3212           0 :         return NULL;
    3213             : }
    3214           0 : IShaderSource* Server::getShaderSource()
    3215             : {
    3216           0 :         return NULL;
    3217             : }
    3218           0 : scene::ISceneManager* Server::getSceneManager()
    3219             : {
    3220           0 :         return NULL;
    3221             : }
    3222             : 
    3223           0 : u16 Server::allocateUnknownNodeId(const std::string &name)
    3224             : {
    3225           0 :         return m_nodedef->allocateDummy(name);
    3226             : }
    3227           0 : ISoundManager* Server::getSoundManager()
    3228             : {
    3229           0 :         return &dummySoundManager;
    3230             : }
    3231           0 : MtEventManager* Server::getEventManager()
    3232             : {
    3233           0 :         return m_event;
    3234             : }
    3235             : 
    3236           0 : IWritableItemDefManager* Server::getWritableItemDefManager()
    3237             : {
    3238           0 :         return m_itemdef;
    3239             : }
    3240           0 : IWritableNodeDefManager* Server::getWritableNodeDefManager()
    3241             : {
    3242           0 :         return m_nodedef;
    3243             : }
    3244           0 : IWritableCraftDefManager* Server::getWritableCraftDefManager()
    3245             : {
    3246           0 :         return m_craftdef;
    3247             : }
    3248             : 
    3249           0 : const ModSpec* Server::getModSpec(const std::string &modname) const
    3250             : {
    3251           0 :         for(std::vector<ModSpec>::const_iterator i = m_mods.begin();
    3252           0 :                         i != m_mods.end(); i++){
    3253           0 :                 const ModSpec &mod = *i;
    3254           0 :                 if(mod.name == modname)
    3255           0 :                         return &mod;
    3256             :         }
    3257           0 :         return NULL;
    3258             : }
    3259           0 : void Server::getModNames(std::vector<std::string> &modlist)
    3260             : {
    3261           0 :         for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
    3262           0 :                 modlist.push_back(i->name);
    3263             :         }
    3264           0 : }
    3265           4 : std::string Server::getBuiltinLuaPath()
    3266             : {
    3267           4 :         return porting::path_share + DIR_DELIM + "builtin";
    3268             : }
    3269             : 
    3270           0 : v3f Server::findSpawnPos()
    3271             : {
    3272           0 :         ServerMap &map = m_env->getServerMap();
    3273           0 :         v3f nodeposf;
    3274           0 :         if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
    3275           0 :                 return nodeposf * BS;
    3276             :         }
    3277             : 
    3278             :         // Default position is static_spawnpoint
    3279             :         // We will return it if we don't found a good place
    3280           0 :         v3s16 nodepos(nodeposf.X, nodeposf.Y, nodeposf.Z);
    3281             : 
    3282           0 :         s16 water_level = map.getWaterLevel();
    3283             : 
    3284           0 :         bool is_good = false;
    3285             : 
    3286             :         // Try to find a good place a few times
    3287           0 :         for(s32 i = 0; i < 1000 && !is_good; i++) {
    3288           0 :                 s32 range = 1 + i;
    3289             :                 // We're going to try to throw the player to this position
    3290             :                 v2s16 nodepos2d = v2s16(
    3291           0 :                                 -range + (myrand() % (range * 2)),
    3292           0 :                                 -range + (myrand() % (range * 2)));
    3293             : 
    3294             :                 // Get ground height at point
    3295           0 :                 s16 groundheight = map.findGroundLevel(nodepos2d);
    3296           0 :                 if (groundheight <= water_level) // Don't go underwater
    3297           0 :                         continue;
    3298           0 :                 if (groundheight > water_level + 6) // Don't go to high places
    3299           0 :                         continue;
    3300             : 
    3301           0 :                 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
    3302             : 
    3303           0 :                 s32 air_count = 0;
    3304           0 :                 for (s32 i = 0; i < 10; i++) {
    3305           0 :                         v3s16 blockpos = getNodeBlockPos(nodepos);
    3306           0 :                         map.emergeBlock(blockpos, true);
    3307           0 :                         content_t c = map.getNodeNoEx(nodepos).getContent();
    3308           0 :                         if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
    3309           0 :                                 air_count++;
    3310           0 :                                 if (air_count >= 2){
    3311           0 :                                         is_good = true;
    3312           0 :                                         break;
    3313             :                                 }
    3314             :                         }
    3315           0 :                         nodepos.Y++;
    3316             :                 }
    3317             :         }
    3318             : 
    3319           0 :         return intToFloat(nodepos, BS);
    3320             : }
    3321             : 
    3322           0 : PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
    3323             : {
    3324           0 :         bool newplayer = false;
    3325             : 
    3326             :         /*
    3327             :                 Try to get an existing player
    3328             :         */
    3329           0 :         RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
    3330             : 
    3331             :         // If player is already connected, cancel
    3332           0 :         if(player != NULL && player->peer_id != 0)
    3333             :         {
    3334           0 :                 infostream<<"emergePlayer(): Player already connected"<<std::endl;
    3335           0 :                 return NULL;
    3336             :         }
    3337             : 
    3338             :         /*
    3339             :                 If player with the wanted peer_id already exists, cancel.
    3340             :         */
    3341           0 :         if(m_env->getPlayer(peer_id) != NULL)
    3342             :         {
    3343             :                 infostream<<"emergePlayer(): Player with wrong name but same"
    3344           0 :                                 " peer_id already exists"<<std::endl;
    3345           0 :                 return NULL;
    3346             :         }
    3347             : 
    3348             :         // Load player if it isn't already loaded
    3349           0 :         if (!player) {
    3350           0 :                 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
    3351             :         }
    3352             : 
    3353             :         // Create player if it doesn't exist
    3354           0 :         if (!player) {
    3355           0 :                 newplayer = true;
    3356           0 :                 player = new RemotePlayer(this, name);
    3357             :                 // Set player position
    3358           0 :                 infostream<<"Server: Finding spawn place for player \""
    3359           0 :                                 <<name<<"\""<<std::endl;
    3360           0 :                 v3f pos = findSpawnPos();
    3361           0 :                 player->setPosition(pos);
    3362             : 
    3363             :                 // Make sure the player is saved
    3364           0 :                 player->setModified(true);
    3365             : 
    3366             :                 // Add player to environment
    3367           0 :                 m_env->addPlayer(player);
    3368             :         }
    3369             : 
    3370             :         // Create a new player active object
    3371             :         PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
    3372           0 :                         getPlayerEffectivePrivs(player->getName()),
    3373           0 :                         isSingleplayer());
    3374             : 
    3375             :         /* Clean up old HUD elements from previous sessions */
    3376           0 :         player->clearHud();
    3377             : 
    3378             :         /* Add object to environment */
    3379           0 :         m_env->addActiveObject(playersao);
    3380             : 
    3381             :         /* Run scripts */
    3382           0 :         if (newplayer) {
    3383           0 :                 m_script->on_newplayer(playersao);
    3384             :         }
    3385             : 
    3386           0 :         return playersao;
    3387             : }
    3388             : 
    3389           0 : void dedicated_server_loop(Server &server, bool &kill)
    3390             : {
    3391           0 :         DSTACK(__FUNCTION_NAME);
    3392             : 
    3393           0 :         verbosestream<<"dedicated_server_loop()"<<std::endl;
    3394             : 
    3395           0 :         IntervalLimiter m_profiler_interval;
    3396             : 
    3397           0 :         for(;;)
    3398             :         {
    3399           0 :                 float steplen = g_settings->getFloat("dedicated_server_step");
    3400             :                 // This is kind of a hack but can be done like this
    3401             :                 // because server.step() is very light
    3402             :                 {
    3403           0 :                         ScopeProfiler sp(g_profiler, "dedicated server sleep");
    3404           0 :                         sleep_ms((int)(steplen*1000.0));
    3405             :                 }
    3406           0 :                 server.step(steplen);
    3407             : 
    3408           0 :                 if(server.getShutdownRequested() || kill)
    3409             :                 {
    3410           0 :                         infostream<<"Dedicated server quitting"<<std::endl;
    3411             : #if USE_CURL
    3412           0 :                         if(g_settings->getBool("server_announce"))
    3413           0 :                                 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
    3414             : #endif
    3415           0 :                         break;
    3416             :                 }
    3417             : 
    3418             :                 /*
    3419             :                         Profiler
    3420             :                 */
    3421             :                 float profiler_print_interval =
    3422           0 :                                 g_settings->getFloat("profiler_print_interval");
    3423           0 :                 if(profiler_print_interval != 0)
    3424             :                 {
    3425           0 :                         if(m_profiler_interval.step(steplen, profiler_print_interval))
    3426             :                         {
    3427           0 :                                 infostream<<"Profiler:"<<std::endl;
    3428           0 :                                 g_profiler->print(infostream);
    3429           0 :                                 g_profiler->clear();
    3430             :                         }
    3431             :                 }
    3432             :         }
    3433           3 : }

Generated by: LCOV version 1.11