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