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