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