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