]> git.lizzy.rs Git - dragonfireclient.git/blob - src/server.cpp
Add propper client initialization
[dragonfireclient.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 "clientserver.h"
25 #include "ban.h"
26 #include "environment.h"
27 #include "map.h"
28 #include "jthread/jmutexautolock.h"
29 #include "main.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 "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 "sha1.h"
54 #include "base64.h"
55 #include "tool.h"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
58 #include "hex.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/pointedthing.h"
62 #include "util/mathconstants.h"
63 #include "rollback.h"
64 #include "util/serialize.h"
65 #include "util/thread.h"
66 #include "defaultsettings.h"
67
68 class ClientNotFoundException : public BaseException
69 {
70 public:
71         ClientNotFoundException(const char *s):
72                 BaseException(s)
73         {}
74 };
75
76 class ServerThread : public JThread
77 {
78         Server *m_server;
79
80 public:
81
82         ServerThread(Server *server):
83                 JThread(),
84                 m_server(server)
85         {
86         }
87
88         void * Thread();
89 };
90
91 void * ServerThread::Thread()
92 {
93         log_register_thread("ServerThread");
94
95         DSTACK(__FUNCTION_NAME);
96         BEGIN_DEBUG_EXCEPTION_HANDLER
97
98         m_server->AsyncRunStep(true);
99
100         ThreadStarted();
101
102         while(!StopRequested())
103         {
104                 try{
105                         //TimeTaker timer("AsyncRunStep() + Receive()");
106
107                         m_server->AsyncRunStep();
108
109                         m_server->Receive();
110
111                 }
112                 catch(con::NoIncomingDataException &e)
113                 {
114                 }
115                 catch(con::PeerNotFoundException &e)
116                 {
117                         infostream<<"Server: PeerNotFoundException"<<std::endl;
118                 }
119                 catch(ClientNotFoundException &e)
120                 {
121                 }
122                 catch(con::ConnectionBindFailed &e)
123                 {
124                         m_server->setAsyncFatalError(e.what());
125                 }
126                 catch(LuaError &e)
127                 {
128                         m_server->setAsyncFatalError(e.what());
129                 }
130         }
131
132         END_DEBUG_EXCEPTION_HANDLER(errorstream)
133
134         return NULL;
135 }
136
137 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
138 {
139         if(pos_exists) *pos_exists = false;
140         switch(type){
141         case SSP_LOCAL:
142                 return v3f(0,0,0);
143         case SSP_POSITIONAL:
144                 if(pos_exists) *pos_exists = true;
145                 return pos;
146         case SSP_OBJECT: {
147                 if(object == 0)
148                         return v3f(0,0,0);
149                 ServerActiveObject *sao = env->getActiveObject(object);
150                 if(!sao)
151                         return v3f(0,0,0);
152                 if(pos_exists) *pos_exists = true;
153                 return sao->getBasePosition(); }
154         }
155         return v3f(0,0,0);
156 }
157
158
159
160 /*
161         Server
162 */
163
164 Server::Server(
165                 const std::string &path_world,
166                 const SubgameSpec &gamespec,
167                 bool simple_singleplayer_mode
168         ):
169         m_path_world(path_world),
170         m_gamespec(gamespec),
171         m_simple_singleplayer_mode(simple_singleplayer_mode),
172         m_async_fatal_error(""),
173         m_env(NULL),
174         m_con(PROTOCOL_ID,
175                         512,
176                         CONNECTION_TIMEOUT,
177                         g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"),
178                         this),
179         m_banmanager(NULL),
180         m_rollback(NULL),
181         m_rollback_sink_enabled(true),
182         m_enable_rollback_recording(false),
183         m_emerge(NULL),
184         m_script(NULL),
185         m_itemdef(createItemDefManager()),
186         m_nodedef(createNodeDefManager()),
187         m_craftdef(createCraftDefManager()),
188         m_event(new EventManager()),
189         m_thread(NULL),
190         m_time_of_day_send_timer(0),
191         m_uptime(0),
192         m_clients(&m_con),
193         m_shutdown_requested(false),
194         m_ignore_map_edit_events(false),
195         m_ignore_map_edit_events_peer_id(0)
196
197 {
198         m_liquid_transform_timer = 0.0;
199         m_liquid_transform_every = 1.0;
200         m_print_info_timer = 0.0;
201         m_masterserver_timer = 0.0;
202         m_objectdata_timer = 0.0;
203         m_emergethread_trigger_timer = 0.0;
204         m_savemap_timer = 0.0;
205
206         m_step_dtime = 0.0;
207         m_lag = g_settings->getFloat("dedicated_server_step");
208
209         if(path_world == "")
210                 throw ServerError("Supplied empty world path");
211
212         if(!gamespec.isValid())
213                 throw ServerError("Supplied invalid gamespec");
214
215         infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
216         if(m_simple_singleplayer_mode)
217                 infostream<<" in simple singleplayer mode"<<std::endl;
218         else
219                 infostream<<std::endl;
220         infostream<<"- world:  "<<m_path_world<<std::endl;
221         infostream<<"- game:   "<<m_gamespec.path<<std::endl;
222
223         // Initialize default settings and override defaults with those provided
224         // by the game
225         set_default_settings(g_settings);
226         Settings gamedefaults;
227         getGameMinetestConfig(gamespec.path, gamedefaults);
228         override_default_settings(g_settings, &gamedefaults);
229
230         // Create server thread
231         m_thread = new ServerThread(this);
232
233         // Create emerge manager
234         m_emerge = new EmergeManager(this);
235
236         // Create world if it doesn't exist
237         if(!initializeWorld(m_path_world, m_gamespec.id))
238                 throw ServerError("Failed to initialize world");
239
240         // Create ban manager
241         std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
242         m_banmanager = new BanManager(ban_path);
243
244         // Create rollback manager
245         std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
246         m_rollback = createRollbackManager(rollback_path, this);
247
248         ModConfiguration modconf(m_path_world);
249         m_mods = modconf.getMods();
250         std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
251         // complain about mods with unsatisfied dependencies
252         if(!modconf.isConsistent())
253         {
254                 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
255                         it != unsatisfied_mods.end(); ++it)
256                 {
257                         ModSpec mod = *it;
258                         errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
259                         for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
260                                 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
261                                 errorstream << " \"" << *dep_it << "\"";
262                         errorstream << std::endl;
263                 }
264         }
265
266         Settings worldmt_settings;
267         std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
268         worldmt_settings.readConfigFile(worldmt.c_str());
269         std::vector<std::string> names = worldmt_settings.getNames();
270         std::set<std::string> load_mod_names;
271         for(std::vector<std::string>::iterator it = names.begin();
272                 it != names.end(); ++it)
273         {
274                 std::string name = *it;
275                 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
276                         load_mod_names.insert(name.substr(9));
277         }
278         // complain about mods declared to be loaded, but not found
279         for(std::vector<ModSpec>::iterator it = m_mods.begin();
280                         it != m_mods.end(); ++it)
281                 load_mod_names.erase((*it).name);
282         for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
283                         it != unsatisfied_mods.end(); ++it)
284                 load_mod_names.erase((*it).name);
285         if(!load_mod_names.empty())
286         {
287                 errorstream << "The following mods could not be found:";
288                 for(std::set<std::string>::iterator it = load_mod_names.begin();
289                         it != load_mod_names.end(); ++it)
290                         errorstream << " \"" << (*it) << "\"";
291                 errorstream << std::endl;
292         }
293
294         // Path to builtin.lua
295         std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
296
297         // Lock environment
298         JMutexAutoLock envlock(m_env_mutex);
299
300         // Initialize scripting
301         infostream<<"Server: Initializing Lua"<<std::endl;
302
303         m_script = new GameScripting(this);
304
305
306         // Load and run builtin.lua
307         infostream<<"Server: Loading builtin.lua [\""
308                         <<builtinpath<<"\"]"<<std::endl;
309         bool success = m_script->loadMod(builtinpath, "__builtin");
310         if(!success){
311                 errorstream<<"Server: Failed to load and run "
312                                 <<builtinpath<<std::endl;
313                 throw ModError("Failed to load and run "+builtinpath);
314         }
315         // Print 'em
316         infostream<<"Server: Loading mods: ";
317         for(std::vector<ModSpec>::iterator i = m_mods.begin();
318                         i != m_mods.end(); i++){
319                 const ModSpec &mod = *i;
320                 infostream<<mod.name<<" ";
321         }
322         infostream<<std::endl;
323         // Load and run "mod" scripts
324         for(std::vector<ModSpec>::iterator i = m_mods.begin();
325                         i != m_mods.end(); i++){
326                 const ModSpec &mod = *i;
327                 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
328                 infostream<<"  ["<<padStringRight(mod.name, 12)<<"] [\""
329                                 <<scriptpath<<"\"]"<<std::endl;
330                 bool success = m_script->loadMod(scriptpath, mod.name);
331                 if(!success){
332                         errorstream<<"Server: Failed to load and run "
333                                         <<scriptpath<<std::endl;
334                         throw ModError("Failed to load and run "+scriptpath);
335                 }
336         }
337
338         // Read Textures and calculate sha1 sums
339         fillMediaCache();
340
341         // Apply item aliases in the node definition manager
342         m_nodedef->updateAliases(m_itemdef);
343
344         // Initialize Environment
345         ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
346         m_env = new ServerEnvironment(servermap, m_script, this, m_emerge);
347
348         m_clients.setEnv(m_env);
349
350         // Run some callbacks after the MG params have been set up but before activation
351         MapgenParams *mgparams = servermap->getMapgenParams();
352         m_script->environment_OnMapgenInit(mgparams);
353
354         // Initialize mapgens
355         m_emerge->initMapgens(mgparams);
356         servermap->setMapgenParams(m_emerge->params);
357
358         // Give environment reference to scripting api
359         m_script->initializeEnvironment(m_env);
360
361         // Register us to receive map edit events
362         servermap->addEventReceiver(this);
363
364         // If file exists, load environment metadata
365         if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
366         {
367                 infostream<<"Server: Loading environment metadata"<<std::endl;
368                 m_env->loadMeta(m_path_world);
369         }
370
371         // Load players
372         infostream<<"Server: Loading players"<<std::endl;
373         m_env->deSerializePlayers(m_path_world);
374
375         /*
376                 Add some test ActiveBlockModifiers to environment
377         */
378         add_legacy_abms(m_env, m_nodedef);
379
380         m_liquid_transform_every = g_settings->getFloat("liquid_update");
381 }
382
383 Server::~Server()
384 {
385         infostream<<"Server destructing"<<std::endl;
386
387         /*
388                 Send shutdown message
389         */
390         {
391                 std::wstring line = L"*** Server shutting down";
392                 SendChatMessage(PEER_ID_INEXISTENT, line);
393         }
394
395         {
396                 JMutexAutoLock envlock(m_env_mutex);
397
398                 /*
399                         Execute script shutdown hooks
400                 */
401                 m_script->on_shutdown();
402         }
403
404         {
405                 JMutexAutoLock envlock(m_env_mutex);
406
407                 /*
408                         Save players
409                 */
410                 infostream<<"Server: Saving players"<<std::endl;
411                 m_env->serializePlayers(m_path_world);
412
413                 /*
414                         Save environment metadata
415                 */
416                 infostream<<"Server: Saving environment metadata"<<std::endl;
417                 m_env->saveMeta(m_path_world);
418         }
419
420         /*
421                 Stop threads
422         */
423         stop();
424         delete m_thread;
425
426         // stop all emerge threads before deleting players that may have
427         // requested blocks to be emerged
428         m_emerge->stopThreads();
429
430         // Delete things in the reverse order of creation
431         delete m_env;
432
433         // N.B. the EmergeManager should be deleted after the Environment since Map
434         // depends on EmergeManager to write its current params to the map meta
435         delete m_emerge;
436         delete m_rollback;
437         delete m_banmanager;
438         delete m_event;
439         delete m_itemdef;
440         delete m_nodedef;
441         delete m_craftdef;
442
443         // Deinitialize scripting
444         infostream<<"Server: Deinitializing scripting"<<std::endl;
445         delete m_script;
446
447         // Delete detached inventories
448         {
449                 for(std::map<std::string, Inventory*>::iterator
450                                 i = m_detached_inventories.begin();
451                                 i != m_detached_inventories.end(); i++){
452                         delete i->second;
453                 }
454         }
455 }
456
457 void Server::start(unsigned short port)
458 {
459         DSTACK(__FUNCTION_NAME);
460         infostream<<"Starting server on port "<<port<<"..."<<std::endl;
461
462         // Stop thread if already running
463         m_thread->Stop();
464
465         // Initialize connection
466         m_con.SetTimeoutMs(30);
467         m_con.Serve(port);
468
469         // Start thread
470         m_thread->Start();
471
472         // ASCII art for the win!
473         actionstream
474         <<"        .__               __                   __   "<<std::endl
475         <<"  _____ |__| ____   _____/  |_  ____   _______/  |_ "<<std::endl
476         <<" /     \\|  |/    \\_/ __ \\   __\\/ __ \\ /  ___/\\   __\\"<<std::endl
477         <<"|  Y Y  \\  |   |  \\  ___/|  | \\  ___/ \\___ \\  |  |  "<<std::endl
478         <<"|__|_|  /__|___|  /\\___  >__|  \\___  >____  > |__|  "<<std::endl
479         <<"      \\/        \\/     \\/          \\/     \\/        "<<std::endl;
480         actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
481         actionstream<<"Server for gameid=\""<<m_gamespec.id
482                         <<"\" listening on port "<<port<<"."<<std::endl;
483 }
484
485 void Server::stop()
486 {
487         DSTACK(__FUNCTION_NAME);
488
489         infostream<<"Server: Stopping and waiting threads"<<std::endl;
490
491         // Stop threads (set run=false first so both start stopping)
492         m_thread->Stop();
493         //m_emergethread.setRun(false);
494         m_thread->Wait();
495         //m_emergethread.stop();
496
497         infostream<<"Server: Threads stopped"<<std::endl;
498 }
499
500 void Server::step(float dtime)
501 {
502         DSTACK(__FUNCTION_NAME);
503         // Limit a bit
504         if(dtime > 2.0)
505                 dtime = 2.0;
506         {
507                 JMutexAutoLock lock(m_step_dtime_mutex);
508                 m_step_dtime += dtime;
509         }
510         // Throw if fatal error occurred in thread
511         std::string async_err = m_async_fatal_error.get();
512         if(async_err != ""){
513                 throw ServerError(async_err);
514         }
515 }
516
517 void Server::AsyncRunStep(bool initial_step)
518 {
519         DSTACK(__FUNCTION_NAME);
520
521         g_profiler->add("Server::AsyncRunStep (num)", 1);
522
523         float dtime;
524         {
525                 JMutexAutoLock lock1(m_step_dtime_mutex);
526                 dtime = m_step_dtime;
527         }
528
529         {
530                 // Send blocks to clients
531                 SendBlocks(dtime);
532         }
533
534         if((dtime < 0.001) && (initial_step == false))
535                 return;
536
537         g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
538
539         //infostream<<"Server steps "<<dtime<<std::endl;
540         //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
541
542         {
543                 JMutexAutoLock lock1(m_step_dtime_mutex);
544                 m_step_dtime -= dtime;
545         }
546
547         /*
548                 Update uptime
549         */
550         {
551                 m_uptime.set(m_uptime.get() + dtime);
552         }
553
554         handlePeerChanges();
555
556         /*
557                 Update time of day and overall game time
558         */
559         {
560                 JMutexAutoLock envlock(m_env_mutex);
561
562                 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
563
564                 /*
565                         Send to clients at constant intervals
566                 */
567
568                 m_time_of_day_send_timer -= dtime;
569                 if(m_time_of_day_send_timer < 0.0)
570                 {
571                         m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
572                         u16 time = m_env->getTimeOfDay();
573                         float time_speed = g_settings->getFloat("time_speed");
574                         SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
575                 }
576         }
577
578         {
579                 JMutexAutoLock lock(m_env_mutex);
580                 // Figure out and report maximum lag to environment
581                 float max_lag = m_env->getMaxLagEstimate();
582                 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
583                 if(dtime > max_lag){
584                         if(dtime > 0.1 && dtime > max_lag * 2.0)
585                                 infostream<<"Server: Maximum lag peaked to "<<dtime
586                                                 <<" s"<<std::endl;
587                         max_lag = dtime;
588                 }
589                 m_env->reportMaxLagEstimate(max_lag);
590                 // Step environment
591                 ScopeProfiler sp(g_profiler, "SEnv step");
592                 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
593                 m_env->step(dtime);
594         }
595
596         const float map_timer_and_unload_dtime = 2.92;
597         if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
598         {
599                 JMutexAutoLock lock(m_env_mutex);
600                 // Run Map's timers and unload unused data
601                 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
602                 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
603                                 g_settings->getFloat("server_unload_unused_data_timeout"));
604         }
605
606         /*
607                 Do background stuff
608         */
609
610         /*
611                 Handle players
612         */
613         {
614                 JMutexAutoLock lock(m_env_mutex);
615
616                 std::list<u16> clientids = m_clients.getClientIDs();
617
618                 ScopeProfiler sp(g_profiler, "Server: handle players");
619
620                 for(std::list<u16>::iterator
621                         i = clientids.begin();
622                         i != clientids.end(); ++i)
623                 {
624                         PlayerSAO *playersao = getPlayerSAO(*i);
625                         if(playersao == NULL)
626                                 continue;
627
628                         /*
629                                 Handle player HPs (die if hp=0)
630                         */
631                         if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
632                         {
633                                 if(playersao->getHP() == 0)
634                                         DiePlayer(*i);
635                                 else
636                                         SendPlayerHP(*i);
637                         }
638
639                         /*
640                                 Send player breath if changed
641                         */
642                         if(playersao->m_breath_not_sent){
643                                 SendPlayerBreath(*i);
644                         }
645
646                         /*
647                                 Send player inventories if necessary
648                         */
649                         if(playersao->m_moved){
650                                 SendMovePlayer(*i);
651                                 playersao->m_moved = false;
652                         }
653                         if(playersao->m_inventory_not_sent){
654                                 UpdateCrafting(*i);
655                                 SendInventory(*i);
656                         }
657                 }
658         }
659
660         /* Transform liquids */
661         m_liquid_transform_timer += dtime;
662         if(m_liquid_transform_timer >= m_liquid_transform_every)
663         {
664                 m_liquid_transform_timer -= m_liquid_transform_every;
665
666                 JMutexAutoLock lock(m_env_mutex);
667
668                 ScopeProfiler sp(g_profiler, "Server: liquid transform");
669
670                 std::map<v3s16, MapBlock*> modified_blocks;
671                 m_env->getMap().transformLiquids(modified_blocks);
672 #if 0
673                 /*
674                         Update lighting
675                 */
676                 core::map<v3s16, MapBlock*> lighting_modified_blocks;
677                 ServerMap &map = ((ServerMap&)m_env->getMap());
678                 map.updateLighting(modified_blocks, lighting_modified_blocks);
679
680                 // Add blocks modified by lighting to modified_blocks
681                 for(core::map<v3s16, MapBlock*>::Iterator
682                                 i = lighting_modified_blocks.getIterator();
683                                 i.atEnd() == false; i++)
684                 {
685                         MapBlock *block = i.getNode()->getValue();
686                         modified_blocks.insert(block->getPos(), block);
687                 }
688 #endif
689                 /*
690                         Set the modified blocks unsent for all the clients
691                 */
692                 if(modified_blocks.size() > 0)
693                 {
694                         SetBlocksNotSent(modified_blocks);
695                 }
696         }
697         m_clients.step(dtime);
698
699         m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
700 #if USE_CURL
701         // send masterserver announce
702         {
703                 float &counter = m_masterserver_timer;
704                 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
705                                 g_settings->getBool("server_announce") == true)
706                 {
707                         ServerList::sendAnnounce(!counter ? "start" : "update",
708                                                                                 m_clients.getPlayerNames(),
709                                                                                 m_uptime.get(),
710                                                                                 m_env->getGameTime(),
711                                                                                 m_lag,
712                                                                                 m_gamespec.id,
713                                                                                 m_mods);
714                         counter = 0.01;
715                 }
716                 counter += dtime;
717         }
718 #endif
719
720         /*
721                 Check added and deleted active objects
722         */
723         {
724                 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
725                 JMutexAutoLock envlock(m_env_mutex);
726
727                 m_clients.Lock();
728                 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
729                 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
730
731                 // Radius inside which objects are active
732                 s16 radius = g_settings->getS16("active_object_send_range_blocks");
733                 radius *= MAP_BLOCKSIZE;
734
735                 for(std::map<u16, RemoteClient*>::iterator
736                         i = clients.begin();
737                         i != clients.end(); ++i)
738                 {
739                         RemoteClient *client = i->second;
740
741                         // If definitions and textures have not been sent, don't
742                         // send objects either
743                         if (client->getState() < DefinitionsSent)
744                                 continue;
745
746                         Player *player = m_env->getPlayer(client->peer_id);
747                         if(player==NULL)
748                         {
749                                 // This can happen if the client timeouts somehow
750                                 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
751                                                 <<client->peer_id
752                                                 <<" has no associated player"<<std::endl;*/
753                                 continue;
754                         }
755                         v3s16 pos = floatToInt(player->getPosition(), BS);
756
757                         std::set<u16> removed_objects;
758                         std::set<u16> added_objects;
759                         m_env->getRemovedActiveObjects(pos, radius,
760                                         client->m_known_objects, removed_objects);
761                         m_env->getAddedActiveObjects(pos, radius,
762                                         client->m_known_objects, added_objects);
763
764                         // Ignore if nothing happened
765                         if(removed_objects.size() == 0 && added_objects.size() == 0)
766                         {
767                                 //infostream<<"active objects: none changed"<<std::endl;
768                                 continue;
769                         }
770
771                         std::string data_buffer;
772
773                         char buf[4];
774
775                         // Handle removed objects
776                         writeU16((u8*)buf, removed_objects.size());
777                         data_buffer.append(buf, 2);
778                         for(std::set<u16>::iterator
779                                         i = removed_objects.begin();
780                                         i != removed_objects.end(); ++i)
781                         {
782                                 // Get object
783                                 u16 id = *i;
784                                 ServerActiveObject* obj = m_env->getActiveObject(id);
785
786                                 // Add to data buffer for sending
787                                 writeU16((u8*)buf, id);
788                                 data_buffer.append(buf, 2);
789
790                                 // Remove from known objects
791                                 client->m_known_objects.erase(id);
792
793                                 if(obj && obj->m_known_by_count > 0)
794                                         obj->m_known_by_count--;
795                         }
796
797                         // Handle added objects
798                         writeU16((u8*)buf, added_objects.size());
799                         data_buffer.append(buf, 2);
800                         for(std::set<u16>::iterator
801                                         i = added_objects.begin();
802                                         i != added_objects.end(); ++i)
803                         {
804                                 // Get object
805                                 u16 id = *i;
806                                 ServerActiveObject* obj = m_env->getActiveObject(id);
807
808                                 // Get object type
809                                 u8 type = ACTIVEOBJECT_TYPE_INVALID;
810                                 if(obj == NULL)
811                                         infostream<<"WARNING: "<<__FUNCTION_NAME
812                                                         <<": NULL object"<<std::endl;
813                                 else
814                                         type = obj->getSendType();
815
816                                 // Add to data buffer for sending
817                                 writeU16((u8*)buf, id);
818                                 data_buffer.append(buf, 2);
819                                 writeU8((u8*)buf, type);
820                                 data_buffer.append(buf, 1);
821
822                                 if(obj)
823                                         data_buffer.append(serializeLongString(
824                                                         obj->getClientInitializationData(client->net_proto_version)));
825                                 else
826                                         data_buffer.append(serializeLongString(""));
827
828                                 // Add to known objects
829                                 client->m_known_objects.insert(id);
830
831                                 if(obj)
832                                         obj->m_known_by_count++;
833                         }
834
835                         // Send packet
836                         SharedBuffer<u8> reply(2 + data_buffer.size());
837                         writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
838                         memcpy((char*)&reply[2], data_buffer.c_str(),
839                                         data_buffer.size());
840                         // Send as reliable
841                         m_clients.send(client->peer_id, 0, reply, true);
842
843                         verbosestream<<"Server: Sent object remove/add: "
844                                         <<removed_objects.size()<<" removed, "
845                                         <<added_objects.size()<<" added, "
846                                         <<"packet size is "<<reply.getSize()<<std::endl;
847                 }
848                 m_clients.Unlock();
849 #if 0
850                 /*
851                         Collect a list of all the objects known by the clients
852                         and report it back to the environment.
853                 */
854
855                 core::map<u16, bool> all_known_objects;
856
857                 for(core::map<u16, RemoteClient*>::Iterator
858                         i = m_clients.getIterator();
859                         i.atEnd() == false; i++)
860                 {
861                         RemoteClient *client = i.getNode()->getValue();
862                         // Go through all known objects of client
863                         for(core::map<u16, bool>::Iterator
864                                         i = client->m_known_objects.getIterator();
865                                         i.atEnd()==false; i++)
866                         {
867                                 u16 id = i.getNode()->getKey();
868                                 all_known_objects[id] = true;
869                         }
870                 }
871
872                 m_env->setKnownActiveObjects(whatever);
873 #endif
874
875         }
876
877         /*
878                 Send object messages
879         */
880         {
881                 JMutexAutoLock envlock(m_env_mutex);
882                 ScopeProfiler sp(g_profiler, "Server: sending object messages");
883
884                 // Key = object id
885                 // Value = data sent by object
886                 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
887
888                 // Get active object messages from environment
889                 for(;;)
890                 {
891                         ActiveObjectMessage aom = m_env->getActiveObjectMessage();
892                         if(aom.id == 0)
893                                 break;
894
895                         std::list<ActiveObjectMessage>* message_list = NULL;
896                         std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
897                         n = buffered_messages.find(aom.id);
898                         if(n == buffered_messages.end())
899                         {
900                                 message_list = new std::list<ActiveObjectMessage>;
901                                 buffered_messages[aom.id] = message_list;
902                         }
903                         else
904                         {
905                                 message_list = n->second;
906                         }
907                         message_list->push_back(aom);
908                 }
909
910                 m_clients.Lock();
911                 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
912                 // Route data to every client
913                 for(std::map<u16, RemoteClient*>::iterator
914                         i = clients.begin();
915                         i != clients.end(); ++i)
916                 {
917                         RemoteClient *client = i->second;
918                         std::string reliable_data;
919                         std::string unreliable_data;
920                         // Go through all objects in message buffer
921                         for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
922                                         j = buffered_messages.begin();
923                                         j != buffered_messages.end(); ++j)
924                         {
925                                 // If object is not known by client, skip it
926                                 u16 id = j->first;
927                                 if(client->m_known_objects.find(id) == client->m_known_objects.end())
928                                         continue;
929                                 // Get message list of object
930                                 std::list<ActiveObjectMessage>* list = j->second;
931                                 // Go through every message
932                                 for(std::list<ActiveObjectMessage>::iterator
933                                                 k = list->begin(); k != list->end(); ++k)
934                                 {
935                                         // Compose the full new data with header
936                                         ActiveObjectMessage aom = *k;
937                                         std::string new_data;
938                                         // Add object id
939                                         char buf[2];
940                                         writeU16((u8*)&buf[0], aom.id);
941                                         new_data.append(buf, 2);
942                                         // Add data
943                                         new_data += serializeString(aom.datastring);
944                                         // Add data to buffer
945                                         if(aom.reliable)
946                                                 reliable_data += new_data;
947                                         else
948                                                 unreliable_data += new_data;
949                                 }
950                         }
951                         /*
952                                 reliable_data and unreliable_data are now ready.
953                                 Send them.
954                         */
955                         if(reliable_data.size() > 0)
956                         {
957                                 SharedBuffer<u8> reply(2 + reliable_data.size());
958                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
959                                 memcpy((char*)&reply[2], reliable_data.c_str(),
960                                                 reliable_data.size());
961                                 // Send as reliable
962                                 m_clients.send(client->peer_id, 0, reply, true);
963                         }
964                         if(unreliable_data.size() > 0)
965                         {
966                                 SharedBuffer<u8> reply(2 + unreliable_data.size());
967                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
968                                 memcpy((char*)&reply[2], unreliable_data.c_str(),
969                                                 unreliable_data.size());
970                                 // Send as unreliable
971                                 m_clients.send(client->peer_id, 1, reply, false);
972                         }
973
974                         /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
975                         {
976                                 infostream<<"Server: Size of object message data: "
977                                                 <<"reliable: "<<reliable_data.size()
978                                                 <<", unreliable: "<<unreliable_data.size()
979                                                 <<std::endl;
980                         }*/
981                 }
982                 m_clients.Unlock();
983
984                 // Clear buffered_messages
985                 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
986                                 i = buffered_messages.begin();
987                                 i != buffered_messages.end(); ++i)
988                 {
989                         delete i->second;
990                 }
991         }
992
993         /*
994                 Send queued-for-sending map edit events.
995         */
996         {
997                 // We will be accessing the environment
998                 JMutexAutoLock lock(m_env_mutex);
999
1000                 // Don't send too many at a time
1001                 //u32 count = 0;
1002
1003                 // Single change sending is disabled if queue size is not small
1004                 bool disable_single_change_sending = false;
1005                 if(m_unsent_map_edit_queue.size() >= 4)
1006                         disable_single_change_sending = true;
1007
1008                 int event_count = m_unsent_map_edit_queue.size();
1009
1010                 // We'll log the amount of each
1011                 Profiler prof;
1012
1013                 while(m_unsent_map_edit_queue.size() != 0)
1014                 {
1015                         MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1016
1017                         // Players far away from the change are stored here.
1018                         // Instead of sending the changes, MapBlocks are set not sent
1019                         // for them.
1020                         std::list<u16> far_players;
1021
1022                         if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1023                         {
1024                                 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1025                                 prof.add("MEET_ADDNODE", 1);
1026                                 if(disable_single_change_sending)
1027                                         sendAddNode(event->p, event->n, event->already_known_by_peer,
1028                                                         &far_players, 5, event->type == MEET_ADDNODE);
1029                                 else
1030                                         sendAddNode(event->p, event->n, event->already_known_by_peer,
1031                                                         &far_players, 30, event->type == MEET_ADDNODE);
1032                         }
1033                         else if(event->type == MEET_REMOVENODE)
1034                         {
1035                                 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1036                                 prof.add("MEET_REMOVENODE", 1);
1037                                 if(disable_single_change_sending)
1038                                         sendRemoveNode(event->p, event->already_known_by_peer,
1039                                                         &far_players, 5);
1040                                 else
1041                                         sendRemoveNode(event->p, event->already_known_by_peer,
1042                                                         &far_players, 30);
1043                         }
1044                         else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1045                         {
1046                                 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1047                                 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1048                                 setBlockNotSent(event->p);
1049                         }
1050                         else if(event->type == MEET_OTHER)
1051                         {
1052                                 infostream<<"Server: MEET_OTHER"<<std::endl;
1053                                 prof.add("MEET_OTHER", 1);
1054                                 for(std::set<v3s16>::iterator
1055                                                 i = event->modified_blocks.begin();
1056                                                 i != event->modified_blocks.end(); ++i)
1057                                 {
1058                                         setBlockNotSent(*i);
1059                                 }
1060                         }
1061                         else
1062                         {
1063                                 prof.add("unknown", 1);
1064                                 infostream<<"WARNING: Server: Unknown MapEditEvent "
1065                                                 <<((u32)event->type)<<std::endl;
1066                         }
1067
1068                         /*
1069                                 Set blocks not sent to far players
1070                         */
1071                         if(far_players.size() > 0)
1072                         {
1073                                 // Convert list format to that wanted by SetBlocksNotSent
1074                                 std::map<v3s16, MapBlock*> modified_blocks2;
1075                                 for(std::set<v3s16>::iterator
1076                                                 i = event->modified_blocks.begin();
1077                                                 i != event->modified_blocks.end(); ++i)
1078                                 {
1079                                         modified_blocks2[*i] =
1080                                                         m_env->getMap().getBlockNoCreateNoEx(*i);
1081                                 }
1082                                 // Set blocks not sent
1083                                 for(std::list<u16>::iterator
1084                                                 i = far_players.begin();
1085                                                 i != far_players.end(); ++i)
1086                                 {
1087                                         u16 peer_id = *i;
1088                                         RemoteClient *client = getClient(peer_id);
1089                                         if(client==NULL)
1090                                                 continue;
1091                                         client->SetBlocksNotSent(modified_blocks2);
1092                                 }
1093                         }
1094
1095                         delete event;
1096
1097                         /*// Don't send too many at a time
1098                         count++;
1099                         if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1100                                 break;*/
1101                 }
1102
1103                 if(event_count >= 5){
1104                         infostream<<"Server: MapEditEvents:"<<std::endl;
1105                         prof.print(infostream);
1106                 } else if(event_count != 0){
1107                         verbosestream<<"Server: MapEditEvents:"<<std::endl;
1108                         prof.print(verbosestream);
1109                 }
1110
1111         }
1112
1113         /*
1114                 Trigger emergethread (it somehow gets to a non-triggered but
1115                 bysy state sometimes)
1116         */
1117         {
1118                 float &counter = m_emergethread_trigger_timer;
1119                 counter += dtime;
1120                 if(counter >= 2.0)
1121                 {
1122                         counter = 0.0;
1123
1124                         m_emerge->startThreads();
1125
1126                         // Update m_enable_rollback_recording here too
1127                         m_enable_rollback_recording =
1128                                         g_settings->getBool("enable_rollback_recording");
1129                 }
1130         }
1131
1132         // Save map, players and auth stuff
1133         {
1134                 float &counter = m_savemap_timer;
1135                 counter += dtime;
1136                 if(counter >= g_settings->getFloat("server_map_save_interval"))
1137                 {
1138                         counter = 0.0;
1139                         JMutexAutoLock lock(m_env_mutex);
1140
1141                         ScopeProfiler sp(g_profiler, "Server: saving stuff");
1142
1143                         //Ban stuff
1144                         if(m_banmanager->isModified())
1145                                 m_banmanager->save();
1146
1147                         // Save changed parts of map
1148                         m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1149
1150                         // Save players
1151                         m_env->serializePlayers(m_path_world);
1152
1153                         // Save environment metadata
1154                         m_env->saveMeta(m_path_world);
1155                 }
1156         }
1157 }
1158
1159 void Server::Receive()
1160 {
1161         DSTACK(__FUNCTION_NAME);
1162         SharedBuffer<u8> data;
1163         u16 peer_id;
1164         u32 datasize;
1165         try{
1166                 datasize = m_con.Receive(peer_id,data);
1167                 ProcessData(*data, datasize, peer_id);
1168         }
1169         catch(con::InvalidIncomingDataException &e)
1170         {
1171                 infostream<<"Server::Receive(): "
1172                                 "InvalidIncomingDataException: what()="
1173                                 <<e.what()<<std::endl;
1174         }
1175         catch(con::PeerNotFoundException &e)
1176         {
1177                 //NOTE: This is not needed anymore
1178
1179                 // The peer has been disconnected.
1180                 // Find the associated player and remove it.
1181
1182                 /*JMutexAutoLock envlock(m_env_mutex);
1183
1184                 infostream<<"ServerThread: peer_id="<<peer_id
1185                                 <<" has apparently closed connection. "
1186                                 <<"Removing player."<<std::endl;
1187
1188                 m_env->removePlayer(peer_id);*/
1189         }
1190 }
1191
1192 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1193 {
1194         DSTACK(__FUNCTION_NAME);
1195         // Environment is locked first.
1196         JMutexAutoLock envlock(m_env_mutex);
1197
1198         ScopeProfiler sp(g_profiler, "Server::ProcessData");
1199
1200         std::string addr_s;
1201         try{
1202                 Address address = getPeerAddress(peer_id);
1203                 addr_s = address.serializeString();
1204
1205                 // drop player if is ip is banned
1206                 if(m_banmanager->isIpBanned(addr_s)){
1207                         std::string ban_name = m_banmanager->getBanName(addr_s);
1208                         infostream<<"Server: A banned client tried to connect from "
1209                                         <<addr_s<<"; banned name was "
1210                                         <<ban_name<<std::endl;
1211                         // This actually doesn't seem to transfer to the client
1212                         DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1213                                         +narrow_to_wide(ban_name));
1214                         return;
1215                 }
1216         }
1217         catch(con::PeerNotFoundException &e)
1218         {
1219                 errorstream<<"Server::ProcessData(): Cancelling: peer "
1220                                 <<peer_id<<" not found"<<std::endl;
1221                 return;
1222         }
1223
1224         try
1225         {
1226
1227         if(datasize < 2)
1228                 return;
1229
1230         ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1231
1232         if(command == TOSERVER_INIT)
1233         {
1234                 // [0] u16 TOSERVER_INIT
1235                 // [2] u8 SER_FMT_VER_HIGHEST_READ
1236                 // [3] u8[20] player_name
1237                 // [23] u8[28] password <--- can be sent without this, from old versions
1238
1239                 if(datasize < 2+1+PLAYERNAME_SIZE)
1240                         return;
1241
1242                 RemoteClient* client = getClient(peer_id,Created);
1243
1244                 // If net_proto_version is set, this client has already been handled
1245                 if(client->getState() > Created)
1246                 {
1247                         verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1248                                         <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1249                         return;
1250                 }
1251
1252                 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1253                                 <<peer_id<<")"<<std::endl;
1254
1255                 // Do not allow multiple players in simple singleplayer mode.
1256                 // This isn't a perfect way to do it, but will suffice for now
1257                 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1258                         infostream<<"Server: Not allowing another client ("<<addr_s
1259                                         <<") to connect in simple singleplayer mode"<<std::endl;
1260                         DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1261                         return;
1262                 }
1263
1264                 // First byte after command is maximum supported
1265                 // serialization version
1266                 u8 client_max = data[2];
1267                 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1268                 // Use the highest version supported by both
1269                 u8 deployed = std::min(client_max, our_max);
1270                 // If it's lower than the lowest supported, give up.
1271                 if(deployed < SER_FMT_VER_LOWEST)
1272                         deployed = SER_FMT_VER_INVALID;
1273
1274                 if(deployed == SER_FMT_VER_INVALID)
1275                 {
1276                         actionstream<<"Server: A mismatched client tried to connect from "
1277                                         <<addr_s<<std::endl;
1278                         infostream<<"Server: Cannot negotiate serialization version with "
1279                                         <<addr_s<<std::endl;
1280                         DenyAccess(peer_id, std::wstring(
1281                                         L"Your client's version is not supported.\n"
1282                                         L"Server version is ")
1283                                         + narrow_to_wide(minetest_version_simple) + L"."
1284                         );
1285                         return;
1286                 }
1287
1288                 client->setPendingSerializationVersion(deployed);
1289
1290                 /*
1291                         Read and check network protocol version
1292                 */
1293
1294                 u16 min_net_proto_version = 0;
1295                 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1296                         min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1297
1298                 // Use same version as minimum and maximum if maximum version field
1299                 // doesn't exist (backwards compatibility)
1300                 u16 max_net_proto_version = min_net_proto_version;
1301                 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1302                         max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1303
1304                 // Start with client's maximum version
1305                 u16 net_proto_version = max_net_proto_version;
1306
1307                 // Figure out a working version if it is possible at all
1308                 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1309                                 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1310                 {
1311                         // If maximum is larger than our maximum, go with our maximum
1312                         if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1313                                 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1314                         // Else go with client's maximum
1315                         else
1316                                 net_proto_version = max_net_proto_version;
1317                 }
1318
1319                 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1320                                 <<min_net_proto_version<<", max: "<<max_net_proto_version
1321                                 <<", chosen: "<<net_proto_version<<std::endl;
1322
1323                 client->net_proto_version = net_proto_version;
1324
1325                 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1326                                 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1327                 {
1328                         actionstream<<"Server: A mismatched client tried to connect from "
1329                                         <<addr_s<<std::endl;
1330                         DenyAccess(peer_id, std::wstring(
1331                                         L"Your client's version is not supported.\n"
1332                                         L"Server version is ")
1333                                         + narrow_to_wide(minetest_version_simple) + L",\n"
1334                                         + L"server's PROTOCOL_VERSION is "
1335                                         + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1336                                         + L"..."
1337                                         + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1338                                         + L", client's PROTOCOL_VERSION is "
1339                                         + narrow_to_wide(itos(min_net_proto_version))
1340                                         + L"..."
1341                                         + narrow_to_wide(itos(max_net_proto_version))
1342                         );
1343                         return;
1344                 }
1345
1346                 if(g_settings->getBool("strict_protocol_version_checking"))
1347                 {
1348                         if(net_proto_version != LATEST_PROTOCOL_VERSION)
1349                         {
1350                                 actionstream<<"Server: A mismatched (strict) client tried to "
1351                                                 <<"connect from "<<addr_s<<std::endl;
1352                                 DenyAccess(peer_id, std::wstring(
1353                                                 L"Your client's version is not supported.\n"
1354                                                 L"Server version is ")
1355                                                 + narrow_to_wide(minetest_version_simple) + L",\n"
1356                                                 + L"server's PROTOCOL_VERSION (strict) is "
1357                                                 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1358                                                 + L", client's PROTOCOL_VERSION is "
1359                                                 + narrow_to_wide(itos(min_net_proto_version))
1360                                                 + L"..."
1361                                                 + narrow_to_wide(itos(max_net_proto_version))
1362                                 );
1363                                 return;
1364                         }
1365                 }
1366
1367                 /*
1368                         Set up player
1369                 */
1370
1371                 // Get player name
1372                 char playername[PLAYERNAME_SIZE];
1373                 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1374                 {
1375                         playername[i] = data[3+i];
1376                 }
1377                 playername[PLAYERNAME_SIZE-1] = 0;
1378
1379                 if(playername[0]=='\0')
1380                 {
1381                         actionstream<<"Server: Player with an empty name "
1382                                         <<"tried to connect from "<<addr_s<<std::endl;
1383                         DenyAccess(peer_id, L"Empty name");
1384                         return;
1385                 }
1386
1387                 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1388                 {
1389                         actionstream<<"Server: Player with an invalid name "
1390                                         <<"tried to connect from "<<addr_s<<std::endl;
1391                         DenyAccess(peer_id, L"Name contains unallowed characters");
1392                         return;
1393                 }
1394
1395                 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1396                 {
1397                         actionstream<<"Server: Player with the name \"singleplayer\" "
1398                                         <<"tried to connect from "<<addr_s<<std::endl;
1399                         DenyAccess(peer_id, L"Name is not allowed");
1400                         return;
1401                 }
1402
1403                 {
1404                         std::string reason;
1405                         if(m_script->on_prejoinplayer(playername, addr_s, reason))
1406                         {
1407                                 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1408                                                 <<"tried to connect from "<<addr_s<<" "
1409                                                 <<"but it was disallowed for the following reason: "
1410                                                 <<reason<<std::endl;
1411                                 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1412                                 return;
1413                         }
1414                 }
1415
1416                 infostream<<"Server: New connection: \""<<playername<<"\" from "
1417                                 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1418
1419                 // Get password
1420                 char given_password[PASSWORD_SIZE];
1421                 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1422                 {
1423                         // old version - assume blank password
1424                         given_password[0] = 0;
1425                 }
1426                 else
1427                 {
1428                         for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1429                         {
1430                                 given_password[i] = data[23+i];
1431                         }
1432                         given_password[PASSWORD_SIZE-1] = 0;
1433                 }
1434
1435                 if(!base64_is_valid(given_password)){
1436                         actionstream<<"Server: "<<playername
1437                                         <<" supplied invalid password hash"<<std::endl;
1438                         DenyAccess(peer_id, L"Invalid password hash");
1439                         return;
1440                 }
1441
1442                 // Enforce user limit.
1443                 // Don't enforce for users that have some admin right
1444                 if(m_clients.getClientIDs(Created).size() >= g_settings->getU16("max_users") &&
1445                                 !checkPriv(playername, "server") &&
1446                                 !checkPriv(playername, "ban") &&
1447                                 !checkPriv(playername, "privs") &&
1448                                 !checkPriv(playername, "password") &&
1449                                 playername != g_settings->get("name"))
1450                 {
1451                         actionstream<<"Server: "<<playername<<" tried to join, but there"
1452                                         <<" are already max_users="
1453                                         <<g_settings->getU16("max_users")<<" players."<<std::endl;
1454                         DenyAccess(peer_id, L"Too many users.");
1455                         return;
1456                 }
1457
1458                 std::string checkpwd; // Password hash to check against
1459                 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1460
1461                 // If no authentication info exists for user, create it
1462                 if(!has_auth){
1463                         if(!isSingleplayer() &&
1464                                         g_settings->getBool("disallow_empty_password") &&
1465                                         std::string(given_password) == ""){
1466                                 actionstream<<"Server: "<<playername
1467                                                 <<" supplied empty password"<<std::endl;
1468                                 DenyAccess(peer_id, L"Empty passwords are "
1469                                                 L"disallowed. Set a password and try again.");
1470                                 return;
1471                         }
1472                         std::wstring raw_default_password =
1473                                 narrow_to_wide(g_settings->get("default_password"));
1474                         std::string initial_password =
1475                                 translatePassword(playername, raw_default_password);
1476
1477                         // If default_password is empty, allow any initial password
1478                         if (raw_default_password.length() == 0)
1479                                 initial_password = given_password;
1480
1481                         m_script->createAuth(playername, initial_password);
1482                 }
1483
1484                 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1485
1486                 if(!has_auth){
1487                         actionstream<<"Server: "<<playername<<" cannot be authenticated"
1488                                         <<" (auth handler does not work?)"<<std::endl;
1489                         DenyAccess(peer_id, L"Not allowed to login");
1490                         return;
1491                 }
1492
1493                 if(given_password != checkpwd){
1494                         actionstream<<"Server: "<<playername<<" supplied wrong password"
1495                                         <<std::endl;
1496                         DenyAccess(peer_id, L"Wrong password");
1497                         return;
1498                 }
1499
1500                 RemotePlayer *player =
1501                                 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1502
1503                 if(player && player->peer_id != 0){
1504                         errorstream<<"Server: "<<playername<<": Failed to emerge player"
1505                                         <<" (player allocated to an another client)"<<std::endl;
1506                         DenyAccess(peer_id, L"Another client is connected with this "
1507                                         L"name. If your client closed unexpectedly, try again in "
1508                                         L"a minute.");
1509                 }
1510
1511                 m_clients.setPlayerName(peer_id,playername);
1512
1513                 /*
1514                         Answer with a TOCLIENT_INIT
1515                 */
1516                 {
1517                         SharedBuffer<u8> reply(2+1+6+8+4);
1518                         writeU16(&reply[0], TOCLIENT_INIT);
1519                         writeU8(&reply[2], deployed);
1520                         //send dummy pos for legacy reasons only
1521                         writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1522                         writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1523                         writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1524
1525                         // Send as reliable
1526                         m_clients.send(peer_id, 0, reply, true);
1527                         m_clients.event(peer_id, Init);
1528                 }
1529
1530                 return;
1531         }
1532
1533         if(command == TOSERVER_INIT2)
1534         {
1535
1536                 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1537                                 <<peer_id<<std::endl;
1538
1539                 m_clients.event(peer_id, GotInit2);
1540                 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1541
1542                 /*
1543                         Send some initialization data
1544                 */
1545
1546                 infostream<<"Server: Sending content to "
1547                                 <<getPlayerName(peer_id)<<std::endl;
1548
1549                 // Send player movement settings
1550                 SendMovement(peer_id);
1551
1552                 // Send item definitions
1553                 SendItemDef(peer_id, m_itemdef, protocol_version);
1554
1555                 // Send node definitions
1556                 SendNodeDef(peer_id, m_nodedef, protocol_version);
1557
1558                 m_clients.event(peer_id, SetDefinitionsSent);
1559
1560                 // Send media announcement
1561                 sendMediaAnnouncement(peer_id);
1562
1563                 // Send detached inventories
1564                 sendDetachedInventories(peer_id);
1565
1566                 // Send time of day
1567                 u16 time = m_env->getTimeOfDay();
1568                 float time_speed = g_settings->getFloat("time_speed");
1569                 SendTimeOfDay(peer_id, time, time_speed);
1570
1571                 // Warnings about protocol version can be issued here
1572                 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1573                 {
1574                         SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1575                                         L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1576                 }
1577
1578                 return;
1579         }
1580
1581         u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
1582
1583         if(peer_ser_ver == SER_FMT_VER_INVALID)
1584         {
1585                 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1586                                 " serialization format invalid or not initialized."
1587                                 " Skipping incoming command="<<command<<std::endl;
1588                 return;
1589         }
1590
1591         /* Handle commands relate to client startup */
1592         if(command == TOSERVER_REQUEST_MEDIA) {
1593                 std::string datastring((char*)&data[2], datasize-2);
1594                 std::istringstream is(datastring, std::ios_base::binary);
1595
1596                 std::list<std::string> tosend;
1597                 u16 numfiles = readU16(is);
1598
1599                 infostream<<"Sending "<<numfiles<<" files to "
1600                                 <<getPlayerName(peer_id)<<std::endl;
1601                 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1602
1603                 for(int i = 0; i < numfiles; i++) {
1604                         std::string name = deSerializeString(is);
1605                         tosend.push_back(name);
1606                         verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1607                                         <<name<<std::endl;
1608                 }
1609
1610                 sendRequestedMedia(peer_id, tosend);
1611                 return;
1612         }
1613         else if(command == TOSERVER_RECEIVED_MEDIA) {
1614                 std::string playername = "";
1615                 PlayerSAO *playersao = NULL;
1616                 m_clients.Lock();
1617                 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,DefinitionsSent);
1618                 if (client != NULL) {
1619                         playername = client->getName();
1620                         playersao = emergePlayer(playername.c_str(), peer_id);
1621                 }
1622                 m_clients.Unlock();
1623
1624                 RemotePlayer *player =
1625                         static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1626
1627                 // If failed, cancel
1628                 if((playersao == NULL) || (player == NULL))
1629                 {
1630                         if(player && player->peer_id != 0){
1631                                 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1632                                                 <<" (player allocated to an another client)"<<std::endl;
1633                                 DenyAccess(peer_id, L"Another client is connected with this "
1634                                                 L"name. If your client closed unexpectedly, try again in "
1635                                                 L"a minute.");
1636                         } else {
1637                                 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1638                                                 <<std::endl;
1639                                 DenyAccess(peer_id, L"Could not allocate player.");
1640                         }
1641                         return;
1642                 }
1643
1644                 /*
1645                         Send complete position information
1646                 */
1647                 SendMovePlayer(peer_id);
1648
1649                 // Send privileges
1650                 SendPlayerPrivileges(peer_id);
1651
1652                 // Send inventory formspec
1653                 SendPlayerInventoryFormspec(peer_id);
1654
1655                 // Send inventory
1656                 UpdateCrafting(peer_id);
1657                 SendInventory(peer_id);
1658
1659                 // Send HP
1660                 if(g_settings->getBool("enable_damage"))
1661                         SendPlayerHP(peer_id);
1662
1663                 // Send Breath
1664                 SendPlayerBreath(peer_id);
1665
1666                 // Show death screen if necessary
1667                 if(player->hp == 0)
1668                         SendDeathscreen(peer_id, false, v3f(0,0,0));
1669
1670                 // Note things in chat if not in simple singleplayer mode
1671                 if(!m_simple_singleplayer_mode)
1672                 {
1673                         // Send information about server to player in chat
1674                         SendChatMessage(peer_id, getStatusString());
1675
1676                         // Send information about joining in chat
1677                         {
1678                                 std::wstring name = L"unknown";
1679                                 Player *player = m_env->getPlayer(peer_id);
1680                                 if(player != NULL)
1681                                         name = narrow_to_wide(player->getName());
1682
1683                                 std::wstring message;
1684                                 message += L"*** ";
1685                                 message += name;
1686                                 message += L" joined the game.";
1687                                 SendChatMessage(PEER_ID_INEXISTENT,message);
1688                         }
1689                 }
1690
1691                 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. " << std::endl;
1692                 /*
1693                         Print out action
1694                 */
1695                 {
1696                         std::vector<std::string> names = m_clients.getPlayerNames();
1697
1698                         actionstream<<player->getName()<<" ["<<addr_s<<"] "
1699                                         <<"joins game. List of players: ";
1700
1701                         for (std::vector<std::string>::iterator i = names.begin();
1702                                         i != names.end(); i++)
1703                         {
1704                                 actionstream << *i << " ";
1705                         }
1706
1707                         actionstream<<std::endl;
1708                 }
1709
1710                 m_clients.event(peer_id,SetMediaSent);
1711                 m_script->on_joinplayer(playersao);
1712                 return;
1713         }
1714         else if(command == TOSERVER_GOTBLOCKS)
1715         {
1716                 if(datasize < 2+1)
1717                         return;
1718
1719                 /*
1720                         [0] u16 command
1721                         [2] u8 count
1722                         [3] v3s16 pos_0
1723                         [3+6] v3s16 pos_1
1724                         ...
1725                 */
1726
1727                 u16 count = data[2];
1728                 for(u16 i=0; i<count; i++)
1729                 {
1730                         if((s16)datasize < 2+1+(i+1)*6)
1731                                 throw con::InvalidIncomingDataException
1732                                         ("GOTBLOCKS length is too short");
1733                         v3s16 p = readV3S16(&data[2+1+i*6]);
1734                         /*infostream<<"Server: GOTBLOCKS ("
1735                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1736                         RemoteClient *client = getClient(peer_id);
1737                         client->GotBlock(p);
1738                 }
1739                 return;
1740         }
1741
1742         if (m_clients.getClientState(peer_id) < Active)
1743         {
1744                 if (command == TOSERVER_PLAYERPOS) return;
1745
1746                 errorstream<<"Got packet command: " << command << " for peer id "
1747                                 << peer_id << " but client isn't active yet. Dropping packet "
1748                                 <<std::endl;
1749                 return;
1750         }
1751
1752         Player *player = m_env->getPlayer(peer_id);
1753         if(player == NULL){
1754                 errorstream<<"Server::ProcessData(): Cancelling: "
1755                                 "No player for peer_id="<<peer_id
1756                                 <<std::endl;
1757                 return;
1758         }
1759
1760         PlayerSAO *playersao = player->getPlayerSAO();
1761         if(playersao == NULL){
1762                 errorstream<<"Server::ProcessData(): Cancelling: "
1763                                 "No player object for peer_id="<<peer_id
1764                                 <<std::endl;
1765                 return;
1766         }
1767
1768         if(command == TOSERVER_PLAYERPOS)
1769         {
1770                 if(datasize < 2+12+12+4+4)
1771                         return;
1772
1773                 u32 start = 0;
1774                 v3s32 ps = readV3S32(&data[start+2]);
1775                 v3s32 ss = readV3S32(&data[start+2+12]);
1776                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1777                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1778                 u32 keyPressed = 0;
1779                 if(datasize >= 2+12+12+4+4+4)
1780                         keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1781                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1782                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1783                 pitch = wrapDegrees(pitch);
1784                 yaw = wrapDegrees(yaw);
1785
1786                 player->setPosition(position);
1787                 player->setSpeed(speed);
1788                 player->setPitch(pitch);
1789                 player->setYaw(yaw);
1790                 player->keyPressed=keyPressed;
1791                 player->control.up = (bool)(keyPressed&1);
1792                 player->control.down = (bool)(keyPressed&2);
1793                 player->control.left = (bool)(keyPressed&4);
1794                 player->control.right = (bool)(keyPressed&8);
1795                 player->control.jump = (bool)(keyPressed&16);
1796                 player->control.aux1 = (bool)(keyPressed&32);
1797                 player->control.sneak = (bool)(keyPressed&64);
1798                 player->control.LMB = (bool)(keyPressed&128);
1799                 player->control.RMB = (bool)(keyPressed&256);
1800
1801                 bool cheated = playersao->checkMovementCheat();
1802                 if(cheated){
1803                         // Call callbacks
1804                         m_script->on_cheat(playersao, "moved_too_fast");
1805                 }
1806
1807                 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1808                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1809                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1810         }
1811         else if(command == TOSERVER_DELETEDBLOCKS)
1812         {
1813                 if(datasize < 2+1)
1814                         return;
1815
1816                 /*
1817                         [0] u16 command
1818                         [2] u8 count
1819                         [3] v3s16 pos_0
1820                         [3+6] v3s16 pos_1
1821                         ...
1822                 */
1823
1824                 u16 count = data[2];
1825                 for(u16 i=0; i<count; i++)
1826                 {
1827                         if((s16)datasize < 2+1+(i+1)*6)
1828                                 throw con::InvalidIncomingDataException
1829                                         ("DELETEDBLOCKS length is too short");
1830                         v3s16 p = readV3S16(&data[2+1+i*6]);
1831                         /*infostream<<"Server: DELETEDBLOCKS ("
1832                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1833                         RemoteClient *client = getClient(peer_id);
1834                         client->SetBlockNotSent(p);
1835                 }
1836         }
1837         else if(command == TOSERVER_CLICK_OBJECT)
1838         {
1839                 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1840                 return;
1841         }
1842         else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1843         {
1844                 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1845                 return;
1846         }
1847         else if(command == TOSERVER_GROUND_ACTION)
1848         {
1849                 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1850                 return;
1851
1852         }
1853         else if(command == TOSERVER_RELEASE)
1854         {
1855                 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1856                 return;
1857         }
1858         else if(command == TOSERVER_SIGNTEXT)
1859         {
1860                 infostream<<"Server: SIGNTEXT not supported anymore"
1861                                 <<std::endl;
1862                 return;
1863         }
1864         else if(command == TOSERVER_SIGNNODETEXT)
1865         {
1866                 infostream<<"Server: SIGNNODETEXT not supported anymore"
1867                                 <<std::endl;
1868                 return;
1869         }
1870         else if(command == TOSERVER_INVENTORY_ACTION)
1871         {
1872                 // Strip command and create a stream
1873                 std::string datastring((char*)&data[2], datasize-2);
1874                 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1875                 std::istringstream is(datastring, std::ios_base::binary);
1876                 // Create an action
1877                 InventoryAction *a = InventoryAction::deSerialize(is);
1878                 if(a == NULL)
1879                 {
1880                         infostream<<"TOSERVER_INVENTORY_ACTION: "
1881                                         <<"InventoryAction::deSerialize() returned NULL"
1882                                         <<std::endl;
1883                         return;
1884                 }
1885
1886                 // If something goes wrong, this player is to blame
1887                 RollbackScopeActor rollback_scope(m_rollback,
1888                                 std::string("player:")+player->getName());
1889
1890                 /*
1891                         Note: Always set inventory not sent, to repair cases
1892                         where the client made a bad prediction.
1893                 */
1894
1895                 /*
1896                         Handle restrictions and special cases of the move action
1897                 */
1898                 if(a->getType() == IACTION_MOVE)
1899                 {
1900                         IMoveAction *ma = (IMoveAction*)a;
1901
1902                         ma->from_inv.applyCurrentPlayer(player->getName());
1903                         ma->to_inv.applyCurrentPlayer(player->getName());
1904
1905                         setInventoryModified(ma->from_inv);
1906                         setInventoryModified(ma->to_inv);
1907
1908                         bool from_inv_is_current_player =
1909                                 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1910                                 (ma->from_inv.name == player->getName());
1911
1912                         bool to_inv_is_current_player =
1913                                 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1914                                 (ma->to_inv.name == player->getName());
1915
1916                         /*
1917                                 Disable moving items out of craftpreview
1918                         */
1919                         if(ma->from_list == "craftpreview")
1920                         {
1921                                 infostream<<"Ignoring IMoveAction from "
1922                                                 <<(ma->from_inv.dump())<<":"<<ma->from_list
1923                                                 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1924                                                 <<" because src is "<<ma->from_list<<std::endl;
1925                                 delete a;
1926                                 return;
1927                         }
1928
1929                         /*
1930                                 Disable moving items into craftresult and craftpreview
1931                         */
1932                         if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1933                         {
1934                                 infostream<<"Ignoring IMoveAction from "
1935                                                 <<(ma->from_inv.dump())<<":"<<ma->from_list
1936                                                 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1937                                                 <<" because dst is "<<ma->to_list<<std::endl;
1938                                 delete a;
1939                                 return;
1940                         }
1941
1942                         // Disallow moving items in elsewhere than player's inventory
1943                         // if not allowed to interact
1944                         if(!checkPriv(player->getName(), "interact") &&
1945                                         (!from_inv_is_current_player ||
1946                                         !to_inv_is_current_player))
1947                         {
1948                                 infostream<<"Cannot move outside of player's inventory: "
1949                                                 <<"No interact privilege"<<std::endl;
1950                                 delete a;
1951                                 return;
1952                         }
1953                 }
1954                 /*
1955                         Handle restrictions and special cases of the drop action
1956                 */
1957                 else if(a->getType() == IACTION_DROP)
1958                 {
1959                         IDropAction *da = (IDropAction*)a;
1960
1961                         da->from_inv.applyCurrentPlayer(player->getName());
1962
1963                         setInventoryModified(da->from_inv);
1964
1965                         /*
1966                                 Disable dropping items out of craftpreview
1967                         */
1968                         if(da->from_list == "craftpreview")
1969                         {
1970                                 infostream<<"Ignoring IDropAction from "
1971                                                 <<(da->from_inv.dump())<<":"<<da->from_list
1972                                                 <<" because src is "<<da->from_list<<std::endl;
1973                                 delete a;
1974                                 return;
1975                         }
1976
1977                         // Disallow dropping items if not allowed to interact
1978                         if(!checkPriv(player->getName(), "interact"))
1979                         {
1980                                 delete a;
1981                                 return;
1982                         }
1983                 }
1984                 /*
1985                         Handle restrictions and special cases of the craft action
1986                 */
1987                 else if(a->getType() == IACTION_CRAFT)
1988                 {
1989                         ICraftAction *ca = (ICraftAction*)a;
1990
1991                         ca->craft_inv.applyCurrentPlayer(player->getName());
1992
1993                         setInventoryModified(ca->craft_inv);
1994
1995                         //bool craft_inv_is_current_player =
1996                         //      (ca->craft_inv.type == InventoryLocation::PLAYER) &&
1997                         //      (ca->craft_inv.name == player->getName());
1998
1999                         // Disallow crafting if not allowed to interact
2000                         if(!checkPriv(player->getName(), "interact"))
2001                         {
2002                                 infostream<<"Cannot craft: "
2003                                                 <<"No interact privilege"<<std::endl;
2004                                 delete a;
2005                                 return;
2006                         }
2007                 }
2008
2009                 // Do the action
2010                 a->apply(this, playersao, this);
2011                 // Eat the action
2012                 delete a;
2013         }
2014         else if(command == TOSERVER_CHAT_MESSAGE)
2015         {
2016                 /*
2017                         u16 command
2018                         u16 length
2019                         wstring message
2020                 */
2021                 u8 buf[6];
2022                 std::string datastring((char*)&data[2], datasize-2);
2023                 std::istringstream is(datastring, std::ios_base::binary);
2024
2025                 // Read stuff
2026                 is.read((char*)buf, 2);
2027                 u16 len = readU16(buf);
2028
2029                 std::wstring message;
2030                 for(u16 i=0; i<len; i++)
2031                 {
2032                         is.read((char*)buf, 2);
2033                         message += (wchar_t)readU16(buf);
2034                 }
2035
2036                 // If something goes wrong, this player is to blame
2037                 RollbackScopeActor rollback_scope(m_rollback,
2038                                 std::string("player:")+player->getName());
2039
2040                 // Get player name of this client
2041                 std::wstring name = narrow_to_wide(player->getName());
2042
2043                 // Run script hook
2044                 bool ate = m_script->on_chat_message(player->getName(),
2045                                 wide_to_narrow(message));
2046                 // If script ate the message, don't proceed
2047                 if(ate)
2048                         return;
2049
2050                 // Line to send to players
2051                 std::wstring line;
2052                 // Whether to send to the player that sent the line
2053                 bool send_to_sender_only = false;
2054
2055                 // Commands are implemented in Lua, so only catch invalid
2056                 // commands that were not "eaten" and send an error back
2057                 if(message[0] == L'/')
2058                 {
2059                         message = message.substr(1);
2060                         send_to_sender_only = true;
2061                         if(message.length() == 0)
2062                                 line += L"-!- Empty command";
2063                         else
2064                                 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2065                 }
2066                 else
2067                 {
2068                         if(checkPriv(player->getName(), "shout")){
2069                                 line += L"<";
2070                                 line += name;
2071                                 line += L"> ";
2072                                 line += message;
2073                         } else {
2074                                 line += L"-!- You don't have permission to shout.";
2075                                 send_to_sender_only = true;
2076                         }
2077                 }
2078
2079                 if(line != L"")
2080                 {
2081                         /*
2082                                 Send the message to sender
2083                         */
2084                         if (send_to_sender_only)
2085                         {
2086                                 SendChatMessage(peer_id, line);
2087                         }
2088                         /*
2089                                 Send the message to others
2090                         */
2091                         else
2092                         {
2093                                 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2094
2095                                 std::list<u16> clients = m_clients.getClientIDs();
2096
2097                                 for(std::list<u16>::iterator
2098                                         i = clients.begin();
2099                                         i != clients.end(); ++i)
2100                                 {
2101                                         if (*i != peer_id)
2102                                                 SendChatMessage(*i, line);
2103                                 }
2104                         }
2105                 }
2106         }
2107         else if(command == TOSERVER_DAMAGE)
2108         {
2109                 std::string datastring((char*)&data[2], datasize-2);
2110                 std::istringstream is(datastring, std::ios_base::binary);
2111                 u8 damage = readU8(is);
2112
2113                 if(g_settings->getBool("enable_damage"))
2114                 {
2115                         actionstream<<player->getName()<<" damaged by "
2116                                         <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2117                                         <<std::endl;
2118
2119                         playersao->setHP(playersao->getHP() - damage);
2120
2121                         if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2122                                 DiePlayer(peer_id);
2123
2124                         if(playersao->m_hp_not_sent)
2125                                 SendPlayerHP(peer_id);
2126                 }
2127         }
2128         else if(command == TOSERVER_BREATH)
2129         {
2130                 std::string datastring((char*)&data[2], datasize-2);
2131                 std::istringstream is(datastring, std::ios_base::binary);
2132                 u16 breath = readU16(is);
2133                 playersao->setBreath(breath);
2134         }
2135         else if(command == TOSERVER_PASSWORD)
2136         {
2137                 /*
2138                         [0] u16 TOSERVER_PASSWORD
2139                         [2] u8[28] old password
2140                         [30] u8[28] new password
2141                 */
2142
2143                 if(datasize != 2+PASSWORD_SIZE*2)
2144                         return;
2145                 /*char password[PASSWORD_SIZE];
2146                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2147                         password[i] = data[2+i];
2148                 password[PASSWORD_SIZE-1] = 0;*/
2149                 std::string oldpwd;
2150                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2151                 {
2152                         char c = data[2+i];
2153                         if(c == 0)
2154                                 break;
2155                         oldpwd += c;
2156                 }
2157                 std::string newpwd;
2158                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2159                 {
2160                         char c = data[2+PASSWORD_SIZE+i];
2161                         if(c == 0)
2162                                 break;
2163                         newpwd += c;
2164                 }
2165
2166                 if(!base64_is_valid(newpwd)){
2167                         infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2168                         // Wrong old password supplied!!
2169                         SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2170                         return;
2171                 }
2172
2173                 infostream<<"Server: Client requests a password change from "
2174                                 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2175
2176                 std::string playername = player->getName();
2177
2178                 std::string checkpwd;
2179                 m_script->getAuth(playername, &checkpwd, NULL);
2180
2181                 if(oldpwd != checkpwd)
2182                 {
2183                         infostream<<"Server: invalid old password"<<std::endl;
2184                         // Wrong old password supplied!!
2185                         SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2186                         return;
2187                 }
2188
2189                 bool success = m_script->setPassword(playername, newpwd);
2190                 if(success){
2191                         actionstream<<player->getName()<<" changes password"<<std::endl;
2192                         SendChatMessage(peer_id, L"Password change successful.");
2193                 } else {
2194                         actionstream<<player->getName()<<" tries to change password but "
2195                                         <<"it fails"<<std::endl;
2196                         SendChatMessage(peer_id, L"Password change failed or inavailable.");
2197                 }
2198         }
2199         else if(command == TOSERVER_PLAYERITEM)
2200         {
2201                 if (datasize < 2+2)
2202                         return;
2203
2204                 u16 item = readU16(&data[2]);
2205                 playersao->setWieldIndex(item);
2206         }
2207         else if(command == TOSERVER_RESPAWN)
2208         {
2209                 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2210                         return;
2211
2212                 RespawnPlayer(peer_id);
2213
2214                 actionstream<<player->getName()<<" respawns at "
2215                                 <<PP(player->getPosition()/BS)<<std::endl;
2216
2217                 // ActiveObject is added to environment in AsyncRunStep after
2218                 // the previous addition has been succesfully removed
2219         }
2220         else if(command == TOSERVER_INTERACT)
2221         {
2222                 std::string datastring((char*)&data[2], datasize-2);
2223                 std::istringstream is(datastring, std::ios_base::binary);
2224
2225                 /*
2226                         [0] u16 command
2227                         [2] u8 action
2228                         [3] u16 item
2229                         [5] u32 length of the next item
2230                         [9] serialized PointedThing
2231                         actions:
2232                         0: start digging (from undersurface) or use
2233                         1: stop digging (all parameters ignored)
2234                         2: digging completed
2235                         3: place block or item (to abovesurface)
2236                         4: use item
2237                 */
2238                 u8 action = readU8(is);
2239                 u16 item_i = readU16(is);
2240                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2241                 PointedThing pointed;
2242                 pointed.deSerialize(tmp_is);
2243
2244                 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2245                                 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2246
2247                 if(player->hp == 0)
2248                 {
2249                         verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2250                                 <<" tried to interact, but is dead!"<<std::endl;
2251                         return;
2252                 }
2253
2254                 v3f player_pos = playersao->getLastGoodPosition();
2255
2256                 // Update wielded item
2257                 playersao->setWieldIndex(item_i);
2258
2259                 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2260                 v3s16 p_under = pointed.node_undersurface;
2261                 v3s16 p_above = pointed.node_abovesurface;
2262
2263                 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2264                 ServerActiveObject *pointed_object = NULL;
2265                 if(pointed.type == POINTEDTHING_OBJECT)
2266                 {
2267                         pointed_object = m_env->getActiveObject(pointed.object_id);
2268                         if(pointed_object == NULL)
2269                         {
2270                                 verbosestream<<"TOSERVER_INTERACT: "
2271                                         "pointed object is NULL"<<std::endl;
2272                                 return;
2273                         }
2274
2275                 }
2276
2277                 v3f pointed_pos_under = player_pos;
2278                 v3f pointed_pos_above = player_pos;
2279                 if(pointed.type == POINTEDTHING_NODE)
2280                 {
2281                         pointed_pos_under = intToFloat(p_under, BS);
2282                         pointed_pos_above = intToFloat(p_above, BS);
2283                 }
2284                 else if(pointed.type == POINTEDTHING_OBJECT)
2285                 {
2286                         pointed_pos_under = pointed_object->getBasePosition();
2287                         pointed_pos_above = pointed_pos_under;
2288                 }
2289
2290                 /*
2291                         Check that target is reasonably close
2292                         (only when digging or placing things)
2293                 */
2294                 if(action == 0 || action == 2 || action == 3)
2295                 {
2296                         float d = player_pos.getDistanceFrom(pointed_pos_under);
2297                         float max_d = BS * 14; // Just some large enough value
2298                         if(d > max_d){
2299                                 actionstream<<"Player "<<player->getName()
2300                                                 <<" tried to access "<<pointed.dump()
2301                                                 <<" from too far: "
2302                                                 <<"d="<<d<<", max_d="<<max_d
2303                                                 <<". ignoring."<<std::endl;
2304                                 // Re-send block to revert change on client-side
2305                                 RemoteClient *client = getClient(peer_id);
2306                                 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2307                                 client->SetBlockNotSent(blockpos);
2308                                 // Call callbacks
2309                                 m_script->on_cheat(playersao, "interacted_too_far");
2310                                 // Do nothing else
2311                                 return;
2312                         }
2313                 }
2314
2315                 /*
2316                         Make sure the player is allowed to do it
2317                 */
2318                 if(!checkPriv(player->getName(), "interact"))
2319                 {
2320                         actionstream<<player->getName()<<" attempted to interact with "
2321                                         <<pointed.dump()<<" without 'interact' privilege"
2322                                         <<std::endl;
2323                         // Re-send block to revert change on client-side
2324                         RemoteClient *client = getClient(peer_id);
2325                         // Digging completed -> under
2326                         if(action == 2){
2327                                 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2328                                 client->SetBlockNotSent(blockpos);
2329                         }
2330                         // Placement -> above
2331                         if(action == 3){
2332                                 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2333                                 client->SetBlockNotSent(blockpos);
2334                         }
2335                         return;
2336                 }
2337
2338                 /*
2339                         If something goes wrong, this player is to blame
2340                 */
2341                 RollbackScopeActor rollback_scope(m_rollback,
2342                                 std::string("player:")+player->getName());
2343
2344                 /*
2345                         0: start digging or punch object
2346                 */
2347                 if(action == 0)
2348                 {
2349                         if(pointed.type == POINTEDTHING_NODE)
2350                         {
2351                                 /*
2352                                         NOTE: This can be used in the future to check if
2353                                         somebody is cheating, by checking the timing.
2354                                 */
2355                                 MapNode n(CONTENT_IGNORE);
2356                                 try
2357                                 {
2358                                         n = m_env->getMap().getNode(p_under);
2359                                 }
2360                                 catch(InvalidPositionException &e)
2361                                 {
2362                                         infostream<<"Server: Not punching: Node not found."
2363                                                         <<" Adding block to emerge queue."
2364                                                         <<std::endl;
2365                                         m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2366                                 }
2367                                 if(n.getContent() != CONTENT_IGNORE)
2368                                         m_script->node_on_punch(p_under, n, playersao, pointed);
2369                                 // Cheat prevention
2370                                 playersao->noCheatDigStart(p_under);
2371                         }
2372                         else if(pointed.type == POINTEDTHING_OBJECT)
2373                         {
2374                                 // Skip if object has been removed
2375                                 if(pointed_object->m_removed)
2376                                         return;
2377
2378                                 actionstream<<player->getName()<<" punches object "
2379                                                 <<pointed.object_id<<": "
2380                                                 <<pointed_object->getDescription()<<std::endl;
2381
2382                                 ItemStack punchitem = playersao->getWieldedItem();
2383                                 ToolCapabilities toolcap =
2384                                                 punchitem.getToolCapabilities(m_itemdef);
2385                                 v3f dir = (pointed_object->getBasePosition() -
2386                                                 (player->getPosition() + player->getEyeOffset())
2387                                                         ).normalize();
2388                                 float time_from_last_punch =
2389                                         playersao->resetTimeFromLastPunch();
2390                                 pointed_object->punch(dir, &toolcap, playersao,
2391                                                 time_from_last_punch);
2392                         }
2393
2394                 } // action == 0
2395
2396                 /*
2397                         1: stop digging
2398                 */
2399                 else if(action == 1)
2400                 {
2401                 } // action == 1
2402
2403                 /*
2404                         2: Digging completed
2405                 */
2406                 else if(action == 2)
2407                 {
2408                         // Only digging of nodes
2409                         if(pointed.type == POINTEDTHING_NODE)
2410                         {
2411                                 MapNode n(CONTENT_IGNORE);
2412                                 try
2413                                 {
2414                                         n = m_env->getMap().getNode(p_under);
2415                                 }
2416                                 catch(InvalidPositionException &e)
2417                                 {
2418                                         infostream<<"Server: Not finishing digging: Node not found."
2419                                                         <<" Adding block to emerge queue."
2420                                                         <<std::endl;
2421                                         m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2422                                 }
2423
2424                                 /* Cheat prevention */
2425                                 bool is_valid_dig = true;
2426                                 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2427                                 {
2428                                         v3s16 nocheat_p = playersao->getNoCheatDigPos();
2429                                         float nocheat_t = playersao->getNoCheatDigTime();
2430                                         playersao->noCheatDigEnd();
2431                                         // If player didn't start digging this, ignore dig
2432                                         if(nocheat_p != p_under){
2433                                                 infostream<<"Server: NoCheat: "<<player->getName()
2434                                                                 <<" started digging "
2435                                                                 <<PP(nocheat_p)<<" and completed digging "
2436                                                                 <<PP(p_under)<<"; not digging."<<std::endl;
2437                                                 is_valid_dig = false;
2438                                                 // Call callbacks
2439                                                 m_script->on_cheat(playersao, "finished_unknown_dig");
2440                                         }
2441                                         // Get player's wielded item
2442                                         ItemStack playeritem;
2443                                         InventoryList *mlist = playersao->getInventory()->getList("main");
2444                                         if(mlist != NULL)
2445                                                 playeritem = mlist->getItem(playersao->getWieldIndex());
2446                                         ToolCapabilities playeritem_toolcap =
2447                                                         playeritem.getToolCapabilities(m_itemdef);
2448                                         // Get diggability and expected digging time
2449                                         DigParams params = getDigParams(m_nodedef->get(n).groups,
2450                                                         &playeritem_toolcap);
2451                                         // If can't dig, try hand
2452                                         if(!params.diggable){
2453                                                 const ItemDefinition &hand = m_itemdef->get("");
2454                                                 const ToolCapabilities *tp = hand.tool_capabilities;
2455                                                 if(tp)
2456                                                         params = getDigParams(m_nodedef->get(n).groups, tp);
2457                                         }
2458                                         // If can't dig, ignore dig
2459                                         if(!params.diggable){
2460                                                 infostream<<"Server: NoCheat: "<<player->getName()
2461                                                                 <<" completed digging "<<PP(p_under)
2462                                                                 <<", which is not diggable with tool. not digging."
2463                                                                 <<std::endl;
2464                                                 is_valid_dig = false;
2465                                                 // Call callbacks
2466                                                 m_script->on_cheat(playersao, "dug_unbreakable");
2467                                         }
2468                                         // Check digging time
2469                                         // If already invalidated, we don't have to
2470                                         if(!is_valid_dig){
2471                                                 // Well not our problem then
2472                                         }
2473                                         // Clean and long dig
2474                                         else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2475                                                 // All is good, but grab time from pool; don't care if
2476                                                 // it's actually available
2477                                                 playersao->getDigPool().grab(params.time);
2478                                         }
2479                                         // Short or laggy dig
2480                                         // Try getting the time from pool
2481                                         else if(playersao->getDigPool().grab(params.time)){
2482                                                 // All is good
2483                                         }
2484                                         // Dig not possible
2485                                         else{
2486                                                 infostream<<"Server: NoCheat: "<<player->getName()
2487                                                                 <<" completed digging "<<PP(p_under)
2488                                                                 <<"too fast; not digging."<<std::endl;
2489                                                 is_valid_dig = false;
2490                                                 // Call callbacks
2491                                                 m_script->on_cheat(playersao, "dug_too_fast");
2492                                         }
2493                                 }
2494
2495                                 /* Actually dig node */
2496
2497                                 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2498                                         m_script->node_on_dig(p_under, n, playersao);
2499
2500                                 // Send unusual result (that is, node not being removed)
2501                                 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2502                                 {
2503                                         // Re-send block to revert change on client-side
2504                                         RemoteClient *client = getClient(peer_id);
2505                                         v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2506                                         client->SetBlockNotSent(blockpos);
2507                                 }
2508                         }
2509                 } // action == 2
2510
2511                 /*
2512                         3: place block or right-click object
2513                 */
2514                 else if(action == 3)
2515                 {
2516                         ItemStack item = playersao->getWieldedItem();
2517
2518                         // Reset build time counter
2519                         if(pointed.type == POINTEDTHING_NODE &&
2520                                         item.getDefinition(m_itemdef).type == ITEM_NODE)
2521                                 getClient(peer_id)->m_time_from_building = 0.0;
2522
2523                         if(pointed.type == POINTEDTHING_OBJECT)
2524                         {
2525                                 // Right click object
2526
2527                                 // Skip if object has been removed
2528                                 if(pointed_object->m_removed)
2529                                         return;
2530
2531                                 actionstream<<player->getName()<<" right-clicks object "
2532                                                 <<pointed.object_id<<": "
2533                                                 <<pointed_object->getDescription()<<std::endl;
2534
2535                                 // Do stuff
2536                                 pointed_object->rightClick(playersao);
2537                         }
2538                         else if(m_script->item_OnPlace(
2539                                         item, playersao, pointed))
2540                         {
2541                                 // Placement was handled in lua
2542
2543                                 // Apply returned ItemStack
2544                                 playersao->setWieldedItem(item);
2545                         }
2546
2547                         // If item has node placement prediction, always send the
2548                         // blocks to make sure the client knows what exactly happened
2549                         if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2550                                 RemoteClient *client = getClient(peer_id);
2551                                 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2552                                 client->SetBlockNotSent(blockpos);
2553                                 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2554                                 if(blockpos2 != blockpos){
2555                                         client->SetBlockNotSent(blockpos2);
2556                                 }
2557                         }
2558                 } // action == 3
2559
2560                 /*
2561                         4: use
2562                 */
2563                 else if(action == 4)
2564                 {
2565                         ItemStack item = playersao->getWieldedItem();
2566
2567                         actionstream<<player->getName()<<" uses "<<item.name
2568                                         <<", pointing at "<<pointed.dump()<<std::endl;
2569
2570                         if(m_script->item_OnUse(
2571                                         item, playersao, pointed))
2572                         {
2573                                 // Apply returned ItemStack
2574                                 playersao->setWieldedItem(item);
2575                         }
2576
2577                 } // action == 4
2578                 
2579
2580                 /*
2581                         Catch invalid actions
2582                 */
2583                 else
2584                 {
2585                         infostream<<"WARNING: Server: Invalid action "
2586                                         <<action<<std::endl;
2587                 }
2588         }
2589         else if(command == TOSERVER_REMOVED_SOUNDS)
2590         {
2591                 std::string datastring((char*)&data[2], datasize-2);
2592                 std::istringstream is(datastring, std::ios_base::binary);
2593
2594                 int num = readU16(is);
2595                 for(int k=0; k<num; k++){
2596                         s32 id = readS32(is);
2597                         std::map<s32, ServerPlayingSound>::iterator i =
2598                                         m_playing_sounds.find(id);
2599                         if(i == m_playing_sounds.end())
2600                                 continue;
2601                         ServerPlayingSound &psound = i->second;
2602                         psound.clients.erase(peer_id);
2603                         if(psound.clients.size() == 0)
2604                                 m_playing_sounds.erase(i++);
2605                 }
2606         }
2607         else if(command == TOSERVER_NODEMETA_FIELDS)
2608         {
2609                 std::string datastring((char*)&data[2], datasize-2);
2610                 std::istringstream is(datastring, std::ios_base::binary);
2611
2612                 v3s16 p = readV3S16(is);
2613                 std::string formname = deSerializeString(is);
2614                 int num = readU16(is);
2615                 std::map<std::string, std::string> fields;
2616                 for(int k=0; k<num; k++){
2617                         std::string fieldname = deSerializeString(is);
2618                         std::string fieldvalue = deSerializeLongString(is);
2619                         fields[fieldname] = fieldvalue;
2620                 }
2621
2622                 // If something goes wrong, this player is to blame
2623                 RollbackScopeActor rollback_scope(m_rollback,
2624                                 std::string("player:")+player->getName());
2625
2626                 // Check the target node for rollback data; leave others unnoticed
2627                 RollbackNode rn_old(&m_env->getMap(), p, this);
2628
2629                 m_script->node_on_receive_fields(p, formname, fields,playersao);
2630
2631                 // Report rollback data
2632                 RollbackNode rn_new(&m_env->getMap(), p, this);
2633                 if(rollback() && rn_new != rn_old){
2634                         RollbackAction action;
2635                         action.setSetNode(p, rn_old, rn_new);
2636                         rollback()->reportAction(action);
2637                 }
2638         }
2639         else if(command == TOSERVER_INVENTORY_FIELDS)
2640         {
2641                 std::string datastring((char*)&data[2], datasize-2);
2642                 std::istringstream is(datastring, std::ios_base::binary);
2643
2644                 std::string formname = deSerializeString(is);
2645                 int num = readU16(is);
2646                 std::map<std::string, std::string> fields;
2647                 for(int k=0; k<num; k++){
2648                         std::string fieldname = deSerializeString(is);
2649                         std::string fieldvalue = deSerializeLongString(is);
2650                         fields[fieldname] = fieldvalue;
2651                 }
2652
2653                 m_script->on_playerReceiveFields(playersao, formname, fields);
2654         }
2655         else
2656         {
2657                 infostream<<"Server::ProcessData(): Ignoring "
2658                                 "unknown command "<<command<<std::endl;
2659         }
2660
2661         } //try
2662         catch(SendFailedException &e)
2663         {
2664                 errorstream<<"Server::ProcessData(): SendFailedException: "
2665                                 <<"what="<<e.what()
2666                                 <<std::endl;
2667         }
2668 }
2669
2670 void Server::setTimeOfDay(u32 time)
2671 {
2672         m_env->setTimeOfDay(time);
2673         m_time_of_day_send_timer = 0;
2674 }
2675
2676 void Server::onMapEditEvent(MapEditEvent *event)
2677 {
2678         //infostream<<"Server::onMapEditEvent()"<<std::endl;
2679         if(m_ignore_map_edit_events)
2680                 return;
2681         if(m_ignore_map_edit_events_area.contains(event->getArea()))
2682                 return;
2683         MapEditEvent *e = event->clone();
2684         m_unsent_map_edit_queue.push_back(e);
2685 }
2686
2687 Inventory* Server::getInventory(const InventoryLocation &loc)
2688 {
2689         switch(loc.type){
2690         case InventoryLocation::UNDEFINED:
2691         {}
2692         break;
2693         case InventoryLocation::CURRENT_PLAYER:
2694         {}
2695         break;
2696         case InventoryLocation::PLAYER:
2697         {
2698                 Player *player = m_env->getPlayer(loc.name.c_str());
2699                 if(!player)
2700                         return NULL;
2701                 PlayerSAO *playersao = player->getPlayerSAO();
2702                 if(!playersao)
2703                         return NULL;
2704                 return playersao->getInventory();
2705         }
2706         break;
2707         case InventoryLocation::NODEMETA:
2708         {
2709                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2710                 if(!meta)
2711                         return NULL;
2712                 return meta->getInventory();
2713         }
2714         break;
2715         case InventoryLocation::DETACHED:
2716         {
2717                 if(m_detached_inventories.count(loc.name) == 0)
2718                         return NULL;
2719                 return m_detached_inventories[loc.name];
2720         }
2721         break;
2722         default:
2723                 assert(0);
2724         }
2725         return NULL;
2726 }
2727 void Server::setInventoryModified(const InventoryLocation &loc)
2728 {
2729         switch(loc.type){
2730         case InventoryLocation::UNDEFINED:
2731         {}
2732         break;
2733         case InventoryLocation::PLAYER:
2734         {
2735                 Player *player = m_env->getPlayer(loc.name.c_str());
2736                 if(!player)
2737                         return;
2738                 PlayerSAO *playersao = player->getPlayerSAO();
2739                 if(!playersao)
2740                         return;
2741                 playersao->m_inventory_not_sent = true;
2742                 playersao->m_wielded_item_not_sent = true;
2743         }
2744         break;
2745         case InventoryLocation::NODEMETA:
2746         {
2747                 v3s16 blockpos = getNodeBlockPos(loc.p);
2748
2749                 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2750                 if(block)
2751                         block->raiseModified(MOD_STATE_WRITE_NEEDED);
2752
2753                 setBlockNotSent(blockpos);
2754         }
2755         break;
2756         case InventoryLocation::DETACHED:
2757         {
2758                 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2759         }
2760         break;
2761         default:
2762                 assert(0);
2763         }
2764 }
2765
2766 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2767 {
2768         std::list<u16> clients = m_clients.getClientIDs();
2769         m_clients.Lock();
2770         // Set the modified blocks unsent for all the clients
2771         for (std::list<u16>::iterator
2772                  i = clients.begin();
2773                  i != clients.end(); ++i) {
2774                         RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2775                         if (client != NULL)
2776                                 client->SetBlocksNotSent(block);
2777                 }
2778         m_clients.Unlock();
2779 }
2780
2781 void Server::peerAdded(con::Peer *peer)
2782 {
2783         DSTACK(__FUNCTION_NAME);
2784         verbosestream<<"Server::peerAdded(): peer->id="
2785                         <<peer->id<<std::endl;
2786
2787         con::PeerChange c;
2788         c.type = con::PEER_ADDED;
2789         c.peer_id = peer->id;
2790         c.timeout = false;
2791         m_peer_change_queue.push_back(c);
2792 }
2793
2794 void Server::deletingPeer(con::Peer *peer, bool timeout)
2795 {
2796         DSTACK(__FUNCTION_NAME);
2797         verbosestream<<"Server::deletingPeer(): peer->id="
2798                         <<peer->id<<", timeout="<<timeout<<std::endl;
2799
2800         m_clients.event(peer->id,Disconnect);
2801         con::PeerChange c;
2802         c.type = con::PEER_REMOVED;
2803         c.peer_id = peer->id;
2804         c.timeout = timeout;
2805         m_peer_change_queue.push_back(c);
2806 }
2807
2808 void Server::handlePeerChanges()
2809 {
2810         while(m_peer_change_queue.size() > 0)
2811         {
2812                 con::PeerChange c = m_peer_change_queue.pop_front();
2813
2814                 verbosestream<<"Server: Handling peer change: "
2815                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2816                                 <<std::endl;
2817
2818                 switch(c.type)
2819                 {
2820                 case con::PEER_ADDED:
2821                         m_clients.CreateClient(c.peer_id);
2822                         break;
2823
2824                 case con::PEER_REMOVED:
2825                         DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2826                         break;
2827
2828                 default:
2829                         assert("Invalid peer change event received!" == 0);
2830                         break;
2831                 }
2832         }
2833 }
2834
2835 void Server::SendMovement(u16 peer_id)
2836 {
2837         DSTACK(__FUNCTION_NAME);
2838         std::ostringstream os(std::ios_base::binary);
2839
2840         writeU16(os, TOCLIENT_MOVEMENT);
2841         writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2842         writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2843         writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2844         writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2845         writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2846         writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2847         writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2848         writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2849         writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2850         writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2851         writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2852         writeF1000(os, g_settings->getFloat("movement_gravity"));
2853
2854         // Make data buffer
2855         std::string s = os.str();
2856         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2857         // Send as reliable
2858         m_clients.send(peer_id, 0, data, true);
2859 }
2860
2861 void Server::SendHP(u16 peer_id, u8 hp)
2862 {
2863         DSTACK(__FUNCTION_NAME);
2864         std::ostringstream os(std::ios_base::binary);
2865
2866         writeU16(os, TOCLIENT_HP);
2867         writeU8(os, hp);
2868
2869         // Make data buffer
2870         std::string s = os.str();
2871         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2872         // Send as reliable
2873         m_clients.send(peer_id, 0, data, true);
2874 }
2875
2876 void Server::SendBreath(u16 peer_id, u16 breath)
2877 {
2878         DSTACK(__FUNCTION_NAME);
2879         std::ostringstream os(std::ios_base::binary);
2880
2881         writeU16(os, TOCLIENT_BREATH);
2882         writeU16(os, breath);
2883
2884         // Make data buffer
2885         std::string s = os.str();
2886         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2887         // Send as reliable
2888         m_clients.send(peer_id, 0, data, true);
2889 }
2890
2891 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
2892 {
2893         DSTACK(__FUNCTION_NAME);
2894         std::ostringstream os(std::ios_base::binary);
2895
2896         writeU16(os, TOCLIENT_ACCESS_DENIED);
2897         os<<serializeWideString(reason);
2898
2899         // Make data buffer
2900         std::string s = os.str();
2901         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2902         // Send as reliable
2903         m_clients.send(peer_id, 0, data, true);
2904 }
2905
2906 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
2907                 v3f camera_point_target)
2908 {
2909         DSTACK(__FUNCTION_NAME);
2910         std::ostringstream os(std::ios_base::binary);
2911
2912         writeU16(os, TOCLIENT_DEATHSCREEN);
2913         writeU8(os, set_camera_point_target);
2914         writeV3F1000(os, camera_point_target);
2915
2916         // Make data buffer
2917         std::string s = os.str();
2918         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2919         // Send as reliable
2920         m_clients.send(peer_id, 0, data, true);
2921 }
2922
2923 void Server::SendItemDef(u16 peer_id,
2924                 IItemDefManager *itemdef, u16 protocol_version)
2925 {
2926         DSTACK(__FUNCTION_NAME);
2927         std::ostringstream os(std::ios_base::binary);
2928
2929         /*
2930                 u16 command
2931                 u32 length of the next item
2932                 zlib-compressed serialized ItemDefManager
2933         */
2934         writeU16(os, TOCLIENT_ITEMDEF);
2935         std::ostringstream tmp_os(std::ios::binary);
2936         itemdef->serialize(tmp_os, protocol_version);
2937         std::ostringstream tmp_os2(std::ios::binary);
2938         compressZlib(tmp_os.str(), tmp_os2);
2939         os<<serializeLongString(tmp_os2.str());
2940
2941         // Make data buffer
2942         std::string s = os.str();
2943         verbosestream<<"Server: Sending item definitions to id("<<peer_id
2944                         <<"): size="<<s.size()<<std::endl;
2945         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2946         // Send as reliable
2947         m_clients.send(peer_id, 0, data, true);
2948 }
2949
2950 void Server::SendNodeDef(u16 peer_id,
2951                 INodeDefManager *nodedef, u16 protocol_version)
2952 {
2953         DSTACK(__FUNCTION_NAME);
2954         std::ostringstream os(std::ios_base::binary);
2955
2956         /*
2957                 u16 command
2958                 u32 length of the next item
2959                 zlib-compressed serialized NodeDefManager
2960         */
2961         writeU16(os, TOCLIENT_NODEDEF);
2962         std::ostringstream tmp_os(std::ios::binary);
2963         nodedef->serialize(tmp_os, protocol_version);
2964         std::ostringstream tmp_os2(std::ios::binary);
2965         compressZlib(tmp_os.str(), tmp_os2);
2966         os<<serializeLongString(tmp_os2.str());
2967
2968         // Make data buffer
2969         std::string s = os.str();
2970         verbosestream<<"Server: Sending node definitions to id("<<peer_id
2971                         <<"): size="<<s.size()<<std::endl;
2972         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2973         // Send as reliable
2974         m_clients.send(peer_id, 0, data, true);
2975 }
2976
2977 /*
2978         Non-static send methods
2979 */
2980
2981 void Server::SendInventory(u16 peer_id)
2982 {
2983         DSTACK(__FUNCTION_NAME);
2984
2985         PlayerSAO *playersao = getPlayerSAO(peer_id);
2986         assert(playersao);
2987
2988         playersao->m_inventory_not_sent = false;
2989
2990         /*
2991                 Serialize it
2992         */
2993
2994         std::ostringstream os;
2995         playersao->getInventory()->serialize(os);
2996
2997         std::string s = os.str();
2998
2999         SharedBuffer<u8> data(s.size()+2);
3000         writeU16(&data[0], TOCLIENT_INVENTORY);
3001         memcpy(&data[2], s.c_str(), s.size());
3002
3003         // Send as reliable
3004         m_clients.send(peer_id, 0, data, true);
3005 }
3006
3007 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3008 {
3009         DSTACK(__FUNCTION_NAME);
3010
3011         std::ostringstream os(std::ios_base::binary);
3012         u8 buf[12];
3013
3014         // Write command
3015         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3016         os.write((char*)buf, 2);
3017
3018         // Write length
3019         writeU16(buf, message.size());
3020         os.write((char*)buf, 2);
3021
3022         // Write string
3023         for(u32 i=0; i<message.size(); i++)
3024         {
3025                 u16 w = message[i];
3026                 writeU16(buf, w);
3027                 os.write((char*)buf, 2);
3028         }
3029
3030         // Make data buffer
3031         std::string s = os.str();
3032         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3033
3034         if (peer_id != PEER_ID_INEXISTENT)
3035         {
3036                 // Send as reliable
3037                 m_clients.send(peer_id, 0, data, true);
3038         }
3039         else
3040         {
3041                 m_clients.sendToAll(0,data,true);
3042         }
3043 }
3044
3045 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3046                                         const std::string formname)
3047 {
3048         DSTACK(__FUNCTION_NAME);
3049
3050         std::ostringstream os(std::ios_base::binary);
3051         u8 buf[12];
3052
3053         // Write command
3054         writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3055         os.write((char*)buf, 2);
3056         os<<serializeLongString(formspec);
3057         os<<serializeString(formname);
3058
3059         // Make data buffer
3060         std::string s = os.str();
3061         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3062         // Send as reliable
3063         m_clients.send(peer_id, 0, data, true);
3064 }
3065
3066 // Spawns a particle on peer with peer_id
3067 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3068                                 float expirationtime, float size, bool collisiondetection,
3069                                 bool vertical, std::string texture)
3070 {
3071         DSTACK(__FUNCTION_NAME);
3072
3073         std::ostringstream os(std::ios_base::binary);
3074         writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3075         writeV3F1000(os, pos);
3076         writeV3F1000(os, velocity);
3077         writeV3F1000(os, acceleration);
3078         writeF1000(os, expirationtime);
3079         writeF1000(os, size);
3080         writeU8(os,  collisiondetection);
3081         os<<serializeLongString(texture);
3082         writeU8(os, vertical);
3083
3084         // Make data buffer
3085         std::string s = os.str();
3086         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3087
3088         if (peer_id != PEER_ID_INEXISTENT)
3089         {
3090         // Send as reliable
3091                 m_clients.send(peer_id, 0, data, true);
3092         }
3093         else
3094         {
3095                 m_clients.sendToAll(0,data,true);
3096         }
3097 }
3098
3099 // Adds a ParticleSpawner on peer with peer_id
3100 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3101         v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3102         float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3103 {
3104         DSTACK(__FUNCTION_NAME);
3105
3106         std::ostringstream os(std::ios_base::binary);
3107         writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3108
3109         writeU16(os, amount);
3110         writeF1000(os, spawntime);
3111         writeV3F1000(os, minpos);
3112         writeV3F1000(os, maxpos);
3113         writeV3F1000(os, minvel);
3114         writeV3F1000(os, maxvel);
3115         writeV3F1000(os, minacc);
3116         writeV3F1000(os, maxacc);
3117         writeF1000(os, minexptime);
3118         writeF1000(os, maxexptime);
3119         writeF1000(os, minsize);
3120         writeF1000(os, maxsize);
3121         writeU8(os,  collisiondetection);
3122         os<<serializeLongString(texture);
3123         writeU32(os, id);
3124         writeU8(os, vertical);
3125
3126         // Make data buffer
3127         std::string s = os.str();
3128         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3129
3130         if (peer_id != PEER_ID_INEXISTENT)
3131         {
3132                 // Send as reliable
3133                 m_clients.send(peer_id, 0, data, true);
3134         }
3135         else {
3136                 m_clients.sendToAll(0,data,true);
3137         }
3138 }
3139
3140 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3141 {
3142         DSTACK(__FUNCTION_NAME);
3143
3144         std::ostringstream os(std::ios_base::binary);
3145         writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3146
3147         writeU16(os, id);
3148
3149         // Make data buffer
3150         std::string s = os.str();
3151         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3152
3153         if (peer_id != PEER_ID_INEXISTENT) {
3154                 // Send as reliable
3155                 m_clients.send(peer_id, 0, data, true);
3156         }
3157         else {
3158                 m_clients.sendToAll(0,data,true);
3159         }
3160
3161 }
3162
3163 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3164 {
3165         std::ostringstream os(std::ios_base::binary);
3166
3167         // Write command
3168         writeU16(os, TOCLIENT_HUDADD);
3169         writeU32(os, id);
3170         writeU8(os, (u8)form->type);
3171         writeV2F1000(os, form->pos);
3172         os << serializeString(form->name);
3173         writeV2F1000(os, form->scale);
3174         os << serializeString(form->text);
3175         writeU32(os, form->number);
3176         writeU32(os, form->item);
3177         writeU32(os, form->dir);
3178         writeV2F1000(os, form->align);
3179         writeV2F1000(os, form->offset);
3180         writeV3F1000(os, form->world_pos);
3181
3182         // Make data buffer
3183         std::string s = os.str();
3184         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3185         // Send as reliable
3186         m_clients.send(peer_id, 1, data, true);
3187 }
3188
3189 void Server::SendHUDRemove(u16 peer_id, u32 id)
3190 {
3191         std::ostringstream os(std::ios_base::binary);
3192
3193         // Write command
3194         writeU16(os, TOCLIENT_HUDRM);
3195         writeU32(os, id);
3196
3197         // Make data buffer
3198         std::string s = os.str();
3199         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3200         // Send as reliable
3201
3202         m_clients.send(peer_id, 1, data, true);
3203 }
3204
3205 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3206 {
3207         std::ostringstream os(std::ios_base::binary);
3208
3209         // Write command
3210         writeU16(os, TOCLIENT_HUDCHANGE);
3211         writeU32(os, id);
3212         writeU8(os, (u8)stat);
3213         switch (stat) {
3214                 case HUD_STAT_POS:
3215                 case HUD_STAT_SCALE:
3216                 case HUD_STAT_ALIGN:
3217                 case HUD_STAT_OFFSET:
3218                         writeV2F1000(os, *(v2f *)value);
3219                         break;
3220                 case HUD_STAT_NAME:
3221                 case HUD_STAT_TEXT:
3222                         os << serializeString(*(std::string *)value);
3223                         break;
3224                 case HUD_STAT_WORLD_POS:
3225                         writeV3F1000(os, *(v3f *)value);
3226                         break;
3227                 case HUD_STAT_NUMBER:
3228                 case HUD_STAT_ITEM:
3229                 case HUD_STAT_DIR:
3230                 default:
3231                         writeU32(os, *(u32 *)value);
3232                         break;
3233         }
3234
3235         // Make data buffer
3236         std::string s = os.str();
3237         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3238         // Send as reliable
3239         m_clients.send(peer_id, 0, data, true);
3240 }
3241
3242 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3243 {
3244         std::ostringstream os(std::ios_base::binary);
3245
3246         // Write command
3247         writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3248         writeU32(os, flags);
3249         writeU32(os, mask);
3250
3251         // Make data buffer
3252         std::string s = os.str();
3253         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3254         // Send as reliable
3255         m_clients.send(peer_id, 0, data, true);
3256 }
3257
3258 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3259 {
3260         std::ostringstream os(std::ios_base::binary);
3261
3262         // Write command
3263         writeU16(os, TOCLIENT_HUD_SET_PARAM);
3264         writeU16(os, param);
3265         os<<serializeString(value);
3266
3267         // Make data buffer
3268         std::string s = os.str();
3269         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3270         // Send as reliable
3271         m_clients.send(peer_id, 0, data, true);
3272 }
3273
3274 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3275 {
3276         DSTACK(__FUNCTION_NAME);
3277
3278         // Make packet
3279         SharedBuffer<u8> data(2+2+4);
3280         writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3281         writeU16(&data[2], time);
3282         writeF1000(&data[4], time_speed);
3283
3284         if (peer_id == PEER_ID_INEXISTENT) {
3285                 m_clients.sendToAll(0,data,true);
3286         }
3287         else {
3288                 // Send as reliable
3289                 m_clients.send(peer_id, 0, data, true);
3290         }
3291 }
3292
3293 void Server::SendPlayerHP(u16 peer_id)
3294 {
3295         DSTACK(__FUNCTION_NAME);
3296         PlayerSAO *playersao = getPlayerSAO(peer_id);
3297         assert(playersao);
3298         playersao->m_hp_not_sent = false;
3299         SendHP(peer_id, playersao->getHP());
3300
3301         // Send to other clients
3302         std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3303         ActiveObjectMessage aom(playersao->getId(), true, str);
3304         playersao->m_messages_out.push_back(aom);
3305 }
3306
3307 void Server::SendPlayerBreath(u16 peer_id)
3308 {
3309         DSTACK(__FUNCTION_NAME);
3310         PlayerSAO *playersao = getPlayerSAO(peer_id);
3311         assert(playersao);
3312         playersao->m_breath_not_sent = false;
3313         SendBreath(peer_id, playersao->getBreath());
3314 }
3315
3316 void Server::SendMovePlayer(u16 peer_id)
3317 {
3318         DSTACK(__FUNCTION_NAME);
3319         Player *player = m_env->getPlayer(peer_id);
3320         assert(player);
3321
3322         std::ostringstream os(std::ios_base::binary);
3323         writeU16(os, TOCLIENT_MOVE_PLAYER);
3324         writeV3F1000(os, player->getPosition());
3325         writeF1000(os, player->getPitch());
3326         writeF1000(os, player->getYaw());
3327
3328         {
3329                 v3f pos = player->getPosition();
3330                 f32 pitch = player->getPitch();
3331                 f32 yaw = player->getYaw();
3332                 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3333                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3334                                 <<" pitch="<<pitch
3335                                 <<" yaw="<<yaw
3336                                 <<std::endl;
3337         }
3338
3339         // Make data buffer
3340         std::string s = os.str();
3341         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3342         // Send as reliable
3343         m_clients.send(peer_id, 0, data, true);
3344 }
3345
3346 void Server::SendPlayerPrivileges(u16 peer_id)
3347 {
3348         Player *player = m_env->getPlayer(peer_id);
3349         assert(player);
3350         if(player->peer_id == PEER_ID_INEXISTENT)
3351                 return;
3352
3353         std::set<std::string> privs;
3354         m_script->getAuth(player->getName(), NULL, &privs);
3355
3356         std::ostringstream os(std::ios_base::binary);
3357         writeU16(os, TOCLIENT_PRIVILEGES);
3358         writeU16(os, privs.size());
3359         for(std::set<std::string>::const_iterator i = privs.begin();
3360                         i != privs.end(); i++){
3361                 os<<serializeString(*i);
3362         }
3363
3364         // Make data buffer
3365         std::string s = os.str();
3366         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3367         // Send as reliable
3368         m_clients.send(peer_id, 0, data, true);
3369 }
3370
3371 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3372 {
3373         Player *player = m_env->getPlayer(peer_id);
3374         assert(player);
3375         if(player->peer_id == PEER_ID_INEXISTENT)
3376                 return;
3377
3378         std::ostringstream os(std::ios_base::binary);
3379         writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3380         os<<serializeLongString(player->inventory_formspec);
3381
3382         // Make data buffer
3383         std::string s = os.str();
3384         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3385         // Send as reliable
3386         m_clients.send(peer_id, 0, data, true);
3387 }
3388
3389 s32 Server::playSound(const SimpleSoundSpec &spec,
3390                 const ServerSoundParams &params)
3391 {
3392         // Find out initial position of sound
3393         bool pos_exists = false;
3394         v3f pos = params.getPos(m_env, &pos_exists);
3395         // If position is not found while it should be, cancel sound
3396         if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3397                 return -1;
3398
3399         // Filter destination clients
3400         std::list<u16> dst_clients;
3401         if(params.to_player != "")
3402         {
3403                 Player *player = m_env->getPlayer(params.to_player.c_str());
3404                 if(!player){
3405                         infostream<<"Server::playSound: Player \""<<params.to_player
3406                                         <<"\" not found"<<std::endl;
3407                         return -1;
3408                 }
3409                 if(player->peer_id == PEER_ID_INEXISTENT){
3410                         infostream<<"Server::playSound: Player \""<<params.to_player
3411                                         <<"\" not connected"<<std::endl;
3412                         return -1;
3413                 }
3414                 dst_clients.push_back(player->peer_id);
3415         }
3416         else
3417         {
3418                 std::list<u16> clients = m_clients.getClientIDs();
3419
3420                 for(std::list<u16>::iterator
3421                                 i = clients.begin(); i != clients.end(); ++i)
3422                 {
3423                         Player *player = m_env->getPlayer(*i);
3424                         if(!player)
3425                                 continue;
3426                         if(pos_exists){
3427                                 if(player->getPosition().getDistanceFrom(pos) >
3428                                                 params.max_hear_distance)
3429                                         continue;
3430                         }
3431                         dst_clients.push_back(*i);
3432                 }
3433         }
3434         if(dst_clients.size() == 0)
3435                 return -1;
3436
3437         // Create the sound
3438         s32 id = m_next_sound_id++;
3439         // The sound will exist as a reference in m_playing_sounds
3440         m_playing_sounds[id] = ServerPlayingSound();
3441         ServerPlayingSound &psound = m_playing_sounds[id];
3442         psound.params = params;
3443         for(std::list<u16>::iterator i = dst_clients.begin();
3444                         i != dst_clients.end(); i++)
3445                 psound.clients.insert(*i);
3446         // Create packet
3447         std::ostringstream os(std::ios_base::binary);
3448         writeU16(os, TOCLIENT_PLAY_SOUND);
3449         writeS32(os, id);
3450         os<<serializeString(spec.name);
3451         writeF1000(os, spec.gain * params.gain);
3452         writeU8(os, params.type);
3453         writeV3F1000(os, pos);
3454         writeU16(os, params.object);
3455         writeU8(os, params.loop);
3456         // Make data buffer
3457         std::string s = os.str();
3458         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3459         // Send
3460         for(std::list<u16>::iterator i = dst_clients.begin();
3461                         i != dst_clients.end(); i++){
3462                 // Send as reliable
3463                 m_clients.send(*i, 0, data, true);
3464         }
3465         return id;
3466 }
3467 void Server::stopSound(s32 handle)
3468 {
3469         // Get sound reference
3470         std::map<s32, ServerPlayingSound>::iterator i =
3471                         m_playing_sounds.find(handle);
3472         if(i == m_playing_sounds.end())
3473                 return;
3474         ServerPlayingSound &psound = i->second;
3475         // Create packet
3476         std::ostringstream os(std::ios_base::binary);
3477         writeU16(os, TOCLIENT_STOP_SOUND);
3478         writeS32(os, handle);
3479         // Make data buffer
3480         std::string s = os.str();
3481         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3482         // Send
3483         for(std::set<u16>::iterator i = psound.clients.begin();
3484                         i != psound.clients.end(); i++){
3485                 // Send as reliable
3486                 m_clients.send(*i, 0, data, true);
3487         }
3488         // Remove sound reference
3489         m_playing_sounds.erase(i);
3490 }
3491
3492 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3493         std::list<u16> *far_players, float far_d_nodes)
3494 {
3495         float maxd = far_d_nodes*BS;
3496         v3f p_f = intToFloat(p, BS);
3497
3498         // Create packet
3499         u32 replysize = 8;
3500         SharedBuffer<u8> reply(replysize);
3501         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3502         writeS16(&reply[2], p.X);
3503         writeS16(&reply[4], p.Y);
3504         writeS16(&reply[6], p.Z);
3505
3506         std::list<u16> clients = m_clients.getClientIDs();
3507         for(std::list<u16>::iterator
3508                 i = clients.begin();
3509                 i != clients.end(); ++i)
3510         {
3511                 if(far_players)
3512                 {
3513                         // Get player
3514                         Player *player = m_env->getPlayer(*i);
3515                         if(player)
3516                         {
3517                                 // If player is far away, only set modified blocks not sent
3518                                 v3f player_pos = player->getPosition();
3519                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3520                                 {
3521                                         far_players->push_back(*i);
3522                                         continue;
3523                                 }
3524                         }
3525                 }
3526
3527                 // Send as reliable
3528                 m_clients.send(*i, 0, reply, true);
3529         }
3530 }
3531
3532 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3533                 std::list<u16> *far_players, float far_d_nodes,
3534                 bool remove_metadata)
3535 {
3536         float maxd = far_d_nodes*BS;
3537         v3f p_f = intToFloat(p, BS);
3538
3539         std::list<u16> clients = m_clients.getClientIDs();
3540                 for(std::list<u16>::iterator
3541                         i = clients.begin();
3542                         i != clients.end(); ++i)
3543                 {
3544
3545                 if(far_players)
3546                 {
3547                         // Get player
3548                         Player *player = m_env->getPlayer(*i);
3549                         if(player)
3550                         {
3551                                 // If player is far away, only set modified blocks not sent
3552                                 v3f player_pos = player->getPosition();
3553                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3554                                 {
3555                                         far_players->push_back(*i);
3556                                         continue;
3557                                 }
3558                         }
3559                 }
3560                 SharedBuffer<u8> reply(0);
3561                 m_clients.Lock();
3562                 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3563                 if (client != 0)
3564                 {
3565                         // Create packet
3566                         u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3567                         reply = SharedBuffer<u8>(replysize);
3568                         writeU16(&reply[0], TOCLIENT_ADDNODE);
3569                         writeS16(&reply[2], p.X);
3570                         writeS16(&reply[4], p.Y);
3571                         writeS16(&reply[6], p.Z);
3572                         n.serialize(&reply[8], client->serialization_version);
3573                         u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3574                         writeU8(&reply[index], remove_metadata ? 0 : 1);
3575
3576                         if (!remove_metadata) {
3577                                 if (client->net_proto_version <= 21) {
3578                                         // Old clients always clear metadata; fix it
3579                                         // by sending the full block again.
3580                                         client->SetBlockNotSent(p);
3581                                 }
3582                         }
3583                 }
3584                 m_clients.Unlock();
3585
3586                 // Send as reliable
3587                 if (reply.getSize() > 0)
3588                         m_clients.send(*i, 0, reply, true);
3589         }
3590 }
3591
3592 void Server::setBlockNotSent(v3s16 p)
3593 {
3594         std::list<u16> clients = m_clients.getClientIDs();
3595         m_clients.Lock();
3596         for(std::list<u16>::iterator
3597                 i = clients.begin();
3598                 i != clients.end(); ++i)
3599         {
3600                 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3601                 client->SetBlockNotSent(p);
3602         }
3603         m_clients.Unlock();
3604 }
3605
3606 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3607 {
3608         DSTACK(__FUNCTION_NAME);
3609
3610         v3s16 p = block->getPos();
3611
3612 #if 0
3613         // Analyze it a bit
3614         bool completely_air = true;
3615         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3616         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3617         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3618         {
3619                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3620                 {
3621                         completely_air = false;
3622                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3623                 }
3624         }
3625
3626         // Print result
3627         infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3628         if(completely_air)
3629                 infostream<<"[completely air] ";
3630         infostream<<std::endl;
3631 #endif
3632
3633         /*
3634                 Create a packet with the block in the right format
3635         */
3636
3637         std::ostringstream os(std::ios_base::binary);
3638         block->serialize(os, ver, false);
3639         block->serializeNetworkSpecific(os, net_proto_version);
3640         std::string s = os.str();
3641         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3642
3643         u32 replysize = 8 + blockdata.getSize();
3644         SharedBuffer<u8> reply(replysize);
3645         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3646         writeS16(&reply[2], p.X);
3647         writeS16(&reply[4], p.Y);
3648         writeS16(&reply[6], p.Z);
3649         memcpy(&reply[8], *blockdata, blockdata.getSize());
3650
3651         /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3652                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3653
3654         /*
3655                 Send packet
3656         */
3657         m_clients.send(peer_id, 2, reply, true);
3658 }
3659
3660 void Server::SendBlocks(float dtime)
3661 {
3662         DSTACK(__FUNCTION_NAME);
3663
3664         JMutexAutoLock envlock(m_env_mutex);
3665         //TODO check if one big lock could be faster then multiple small ones
3666
3667         ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3668
3669         std::vector<PrioritySortedBlockTransfer> queue;
3670
3671         s32 total_sending = 0;
3672
3673         {
3674                 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3675
3676                 std::list<u16> clients = m_clients.getClientIDs();
3677
3678                 m_clients.Lock();
3679                 for(std::list<u16>::iterator
3680                         i = clients.begin();
3681                         i != clients.end(); ++i)
3682                 {
3683                         RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3684
3685                         if (client == NULL)
3686                                 return;
3687
3688                         total_sending += client->SendingCount();
3689                         client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3690                 }
3691                 m_clients.Unlock();
3692         }
3693
3694         // Sort.
3695         // Lowest priority number comes first.
3696         // Lowest is most important.
3697         std::sort(queue.begin(), queue.end());
3698
3699         m_clients.Lock();
3700         for(u32 i=0; i<queue.size(); i++)
3701         {
3702                 //TODO: Calculate limit dynamically
3703                 if(total_sending >= g_settings->getS32
3704                                 ("max_simultaneous_block_sends_server_total"))
3705                         break;
3706
3707                 PrioritySortedBlockTransfer q = queue[i];
3708
3709                 MapBlock *block = NULL;
3710                 try
3711                 {
3712                         block = m_env->getMap().getBlockNoCreate(q.pos);
3713                 }
3714                 catch(InvalidPositionException &e)
3715                 {
3716                         continue;
3717                 }
3718
3719                 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3720
3721                 if(!client)
3722                         continue;
3723
3724                 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3725
3726                 client->SentBlock(q.pos);
3727                 total_sending++;
3728         }
3729         m_clients.Unlock();
3730 }
3731
3732 void Server::fillMediaCache()
3733 {
3734         DSTACK(__FUNCTION_NAME);
3735
3736         infostream<<"Server: Calculating media file checksums"<<std::endl;
3737
3738         // Collect all media file paths
3739         std::list<std::string> paths;
3740         for(std::vector<ModSpec>::iterator i = m_mods.begin();
3741                         i != m_mods.end(); i++){
3742                 const ModSpec &mod = *i;
3743                 paths.push_back(mod.path + DIR_DELIM + "textures");
3744                 paths.push_back(mod.path + DIR_DELIM + "sounds");
3745                 paths.push_back(mod.path + DIR_DELIM + "media");
3746                 paths.push_back(mod.path + DIR_DELIM + "models");
3747         }
3748         paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3749
3750         // Collect media file information from paths into cache
3751         for(std::list<std::string>::iterator i = paths.begin();
3752                         i != paths.end(); i++)
3753         {
3754                 std::string mediapath = *i;
3755                 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3756                 for(u32 j=0; j<dirlist.size(); j++){
3757                         if(dirlist[j].dir) // Ignode dirs
3758                                 continue;
3759                         std::string filename = dirlist[j].name;
3760                         // If name contains illegal characters, ignore the file
3761                         if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3762                                 infostream<<"Server: ignoring illegal file name: \""
3763                                                 <<filename<<"\""<<std::endl;
3764                                 continue;
3765                         }
3766                         // If name is not in a supported format, ignore it
3767                         const char *supported_ext[] = {
3768                                 ".png", ".jpg", ".bmp", ".tga",
3769                                 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3770                                 ".ogg",
3771                                 ".x", ".b3d", ".md2", ".obj",
3772                                 NULL
3773                         };
3774                         if(removeStringEnd(filename, supported_ext) == ""){
3775                                 infostream<<"Server: ignoring unsupported file extension: \""
3776                                                 <<filename<<"\""<<std::endl;
3777                                 continue;
3778                         }
3779                         // Ok, attempt to load the file and add to cache
3780                         std::string filepath = mediapath + DIR_DELIM + filename;
3781                         // Read data
3782                         std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3783                         if(fis.good() == false){
3784                                 errorstream<<"Server::fillMediaCache(): Could not open \""
3785                                                 <<filename<<"\" for reading"<<std::endl;
3786                                 continue;
3787                         }
3788                         std::ostringstream tmp_os(std::ios_base::binary);
3789                         bool bad = false;
3790                         for(;;){
3791                                 char buf[1024];
3792                                 fis.read(buf, 1024);
3793                                 std::streamsize len = fis.gcount();
3794                                 tmp_os.write(buf, len);
3795                                 if(fis.eof())
3796                                         break;
3797                                 if(!fis.good()){
3798                                         bad = true;
3799                                         break;
3800                                 }
3801                         }
3802                         if(bad){
3803                                 errorstream<<"Server::fillMediaCache(): Failed to read \""
3804                                                 <<filename<<"\""<<std::endl;
3805                                 continue;
3806                         }
3807                         if(tmp_os.str().length() == 0){
3808                                 errorstream<<"Server::fillMediaCache(): Empty file \""
3809                                                 <<filepath<<"\""<<std::endl;
3810                                 continue;
3811                         }
3812
3813                         SHA1 sha1;
3814                         sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3815
3816                         unsigned char *digest = sha1.getDigest();
3817                         std::string sha1_base64 = base64_encode(digest, 20);
3818                         std::string sha1_hex = hex_encode((char*)digest, 20);
3819                         free(digest);
3820
3821                         // Put in list
3822                         this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3823                         verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3824                 }
3825         }
3826 }
3827
3828 struct SendableMediaAnnouncement
3829 {
3830         std::string name;
3831         std::string sha1_digest;
3832
3833         SendableMediaAnnouncement(const std::string name_="",
3834                         const std::string sha1_digest_=""):
3835                 name(name_),
3836                 sha1_digest(sha1_digest_)
3837         {}
3838 };
3839
3840 void Server::sendMediaAnnouncement(u16 peer_id)
3841 {
3842         DSTACK(__FUNCTION_NAME);
3843
3844         verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
3845                         <<std::endl;
3846
3847         std::list<SendableMediaAnnouncement> file_announcements;
3848
3849         for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
3850                         i != m_media.end(); i++){
3851                 // Put in list
3852                 file_announcements.push_back(
3853                                 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
3854         }
3855
3856         // Make packet
3857         std::ostringstream os(std::ios_base::binary);
3858
3859         /*
3860                 u16 command
3861                 u32 number of files
3862                 for each texture {
3863                         u16 length of name
3864                         string name
3865                         u16 length of sha1_digest
3866                         string sha1_digest
3867                 }
3868         */
3869
3870         writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
3871         writeU16(os, file_announcements.size());
3872
3873         for(std::list<SendableMediaAnnouncement>::iterator
3874                         j = file_announcements.begin();
3875                         j != file_announcements.end(); ++j){
3876                 os<<serializeString(j->name);
3877                 os<<serializeString(j->sha1_digest);
3878         }
3879         os<<serializeString(g_settings->get("remote_media"));
3880
3881         // Make data buffer
3882         std::string s = os.str();
3883         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3884
3885         // Send as reliable
3886         m_clients.send(peer_id, 0, data, true);
3887 }
3888
3889 struct SendableMedia
3890 {
3891         std::string name;
3892         std::string path;
3893         std::string data;
3894
3895         SendableMedia(const std::string &name_="", const std::string path_="",
3896                         const std::string &data_=""):
3897                 name(name_),
3898                 path(path_),
3899                 data(data_)
3900         {}
3901 };
3902
3903 void Server::sendRequestedMedia(u16 peer_id,
3904                 const std::list<std::string> &tosend)
3905 {
3906         DSTACK(__FUNCTION_NAME);
3907
3908         verbosestream<<"Server::sendRequestedMedia(): "
3909                         <<"Sending files to client"<<std::endl;
3910
3911         /* Read files */
3912
3913         // Put 5kB in one bunch (this is not accurate)
3914         u32 bytes_per_bunch = 5000;
3915
3916         std::vector< std::list<SendableMedia> > file_bunches;
3917         file_bunches.push_back(std::list<SendableMedia>());
3918
3919         u32 file_size_bunch_total = 0;
3920
3921         for(std::list<std::string>::const_iterator i = tosend.begin();
3922                         i != tosend.end(); ++i)
3923         {
3924                 const std::string &name = *i;
3925
3926                 if(m_media.find(name) == m_media.end()){
3927                         errorstream<<"Server::sendRequestedMedia(): Client asked for "
3928                                         <<"unknown file \""<<(name)<<"\""<<std::endl;
3929                         continue;
3930                 }
3931
3932                 //TODO get path + name
3933                 std::string tpath = m_media[name].path;
3934
3935                 // Read data
3936                 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3937                 if(fis.good() == false){
3938                         errorstream<<"Server::sendRequestedMedia(): Could not open \""
3939                                         <<tpath<<"\" for reading"<<std::endl;
3940                         continue;
3941                 }
3942                 std::ostringstream tmp_os(std::ios_base::binary);
3943                 bool bad = false;
3944                 for(;;){
3945                         char buf[1024];
3946                         fis.read(buf, 1024);
3947                         std::streamsize len = fis.gcount();
3948                         tmp_os.write(buf, len);
3949                         file_size_bunch_total += len;
3950                         if(fis.eof())
3951                                 break;
3952                         if(!fis.good()){
3953                                 bad = true;
3954                                 break;
3955                         }
3956                 }
3957                 if(bad){
3958                         errorstream<<"Server::sendRequestedMedia(): Failed to read \""
3959                                         <<name<<"\""<<std::endl;
3960                         continue;
3961                 }
3962                 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
3963                                 <<tname<<"\""<<std::endl;*/
3964                 // Put in list
3965                 file_bunches[file_bunches.size()-1].push_back(
3966                                 SendableMedia(name, tpath, tmp_os.str()));
3967
3968                 // Start next bunch if got enough data
3969                 if(file_size_bunch_total >= bytes_per_bunch){
3970                         file_bunches.push_back(std::list<SendableMedia>());
3971                         file_size_bunch_total = 0;
3972                 }
3973
3974         }
3975
3976         /* Create and send packets */
3977
3978         u32 num_bunches = file_bunches.size();
3979         for(u32 i=0; i<num_bunches; i++)
3980         {
3981                 std::ostringstream os(std::ios_base::binary);
3982
3983                 /*
3984                         u16 command
3985                         u16 total number of texture bunches
3986                         u16 index of this bunch
3987                         u32 number of files in this bunch
3988                         for each file {
3989                                 u16 length of name
3990                                 string name
3991                                 u32 length of data
3992                                 data
3993                         }
3994                 */
3995
3996                 writeU16(os, TOCLIENT_MEDIA);
3997                 writeU16(os, num_bunches);
3998                 writeU16(os, i);
3999                 writeU32(os, file_bunches[i].size());
4000
4001                 for(std::list<SendableMedia>::iterator
4002                                 j = file_bunches[i].begin();
4003                                 j != file_bunches[i].end(); ++j){
4004                         os<<serializeString(j->name);
4005                         os<<serializeLongString(j->data);
4006                 }
4007
4008                 // Make data buffer
4009                 std::string s = os.str();
4010                 verbosestream<<"Server::sendRequestedMedia(): bunch "
4011                                 <<i<<"/"<<num_bunches
4012                                 <<" files="<<file_bunches[i].size()
4013                                 <<" size=" <<s.size()<<std::endl;
4014                 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4015                 // Send as reliable
4016                 m_clients.send(peer_id, 2, data, true);
4017         }
4018 }
4019
4020 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4021 {
4022         if(m_detached_inventories.count(name) == 0){
4023                 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4024                 return;
4025         }
4026         Inventory *inv = m_detached_inventories[name];
4027
4028         std::ostringstream os(std::ios_base::binary);
4029         writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4030         os<<serializeString(name);
4031         inv->serialize(os);
4032
4033         // Make data buffer
4034         std::string s = os.str();
4035         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4036
4037         if (peer_id != PEER_ID_INEXISTENT)
4038         {
4039                 // Send as reliable
4040                 m_clients.send(peer_id, 0, data, true);
4041         }
4042         else
4043         {
4044                 m_clients.sendToAll(0,data,true);
4045         }
4046 }
4047
4048 void Server::sendDetachedInventories(u16 peer_id)
4049 {
4050         DSTACK(__FUNCTION_NAME);
4051
4052         for(std::map<std::string, Inventory*>::iterator
4053                         i = m_detached_inventories.begin();
4054                         i != m_detached_inventories.end(); i++){
4055                 const std::string &name = i->first;
4056                 //Inventory *inv = i->second;
4057                 sendDetachedInventory(name, peer_id);
4058         }
4059 }
4060
4061 /*
4062         Something random
4063 */
4064
4065 void Server::DiePlayer(u16 peer_id)
4066 {
4067         DSTACK(__FUNCTION_NAME);
4068
4069         PlayerSAO *playersao = getPlayerSAO(peer_id);
4070         assert(playersao);
4071
4072         infostream<<"Server::DiePlayer(): Player "
4073                         <<playersao->getPlayer()->getName()
4074                         <<" dies"<<std::endl;
4075
4076         playersao->setHP(0);
4077
4078         // Trigger scripted stuff
4079         m_script->on_dieplayer(playersao);
4080
4081         SendPlayerHP(peer_id);
4082         SendDeathscreen(peer_id, false, v3f(0,0,0));
4083 }
4084
4085 void Server::RespawnPlayer(u16 peer_id)
4086 {
4087         DSTACK(__FUNCTION_NAME);
4088
4089         PlayerSAO *playersao = getPlayerSAO(peer_id);
4090         assert(playersao);
4091
4092         infostream<<"Server::RespawnPlayer(): Player "
4093                         <<playersao->getPlayer()->getName()
4094                         <<" respawns"<<std::endl;
4095
4096         playersao->setHP(PLAYER_MAX_HP);
4097
4098         bool repositioned = m_script->on_respawnplayer(playersao);
4099         if(!repositioned){
4100                 v3f pos = findSpawnPos(m_env->getServerMap());
4101                 playersao->setPos(pos);
4102         }
4103 }
4104
4105 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4106 {
4107         DSTACK(__FUNCTION_NAME);
4108
4109         SendAccessDenied(peer_id, reason);
4110         m_clients.event(peer_id,SetDenied);
4111         m_con.DisconnectPeer(peer_id);
4112 }
4113
4114 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4115 {
4116         DSTACK(__FUNCTION_NAME);
4117         std::wstring message;
4118         {
4119                 /*
4120                         Clear references to playing sounds
4121                 */
4122                 for(std::map<s32, ServerPlayingSound>::iterator
4123                                 i = m_playing_sounds.begin();
4124                                 i != m_playing_sounds.end();)
4125                 {
4126                         ServerPlayingSound &psound = i->second;
4127                         psound.clients.erase(peer_id);
4128                         if(psound.clients.size() == 0)
4129                                 m_playing_sounds.erase(i++);
4130                         else
4131                                 i++;
4132                 }
4133
4134                 Player *player = m_env->getPlayer(peer_id);
4135
4136                 // Collect information about leaving in chat
4137                 {
4138                         if(player != NULL && reason != CDR_DENY)
4139                         {
4140                                 std::wstring name = narrow_to_wide(player->getName());
4141                                 message += L"*** ";
4142                                 message += name;
4143                                 message += L" left the game.";
4144                                 if(reason == CDR_TIMEOUT)
4145                                         message += L" (timed out)";
4146                         }
4147                 }
4148
4149                 /* Run scripts and remove from environment */
4150                 {
4151                         if(player != NULL)
4152                         {
4153                                 PlayerSAO *playersao = player->getPlayerSAO();
4154                                 assert(playersao);
4155
4156                                 m_script->on_leaveplayer(playersao);
4157
4158                                 playersao->disconnected();
4159                         }
4160                 }
4161
4162                 /*
4163                         Print out action
4164                 */
4165                 {
4166                         if(player != NULL && reason != CDR_DENY)
4167                         {
4168                                 std::ostringstream os(std::ios_base::binary);
4169                                 std::list<u16> clients = m_clients.getClientIDs();
4170
4171                                 for(std::list<u16>::iterator
4172                                         i = clients.begin();
4173                                         i != clients.end(); ++i)
4174                                 {
4175                                         // Get player
4176                                         Player *player = m_env->getPlayer(*i);
4177                                         if(!player)
4178                                                 continue;
4179                                         // Get name of player
4180                                         os<<player->getName()<<" ";
4181                                 }
4182
4183                                 actionstream<<player->getName()<<" "
4184                                                 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4185                                                 <<" List of players: "<<os.str()<<std::endl;
4186                         }
4187                 }
4188                 m_env_mutex.Lock();
4189                 m_clients.DeleteClient(peer_id);
4190                 m_env_mutex.Unlock();
4191         }
4192
4193         // Send leave chat message to all remaining clients
4194         if(message.length() != 0)
4195                 SendChatMessage(PEER_ID_INEXISTENT,message);
4196 }
4197
4198 void Server::UpdateCrafting(u16 peer_id)
4199 {
4200         DSTACK(__FUNCTION_NAME);
4201
4202         Player* player = m_env->getPlayer(peer_id);
4203         assert(player);
4204
4205         // Get a preview for crafting
4206         ItemStack preview;
4207         InventoryLocation loc;
4208         loc.setPlayer(player->getName());
4209         getCraftingResult(&player->inventory, preview, false, this);
4210         m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4211
4212         // Put the new preview in
4213         InventoryList *plist = player->inventory.getList("craftpreview");
4214         assert(plist);
4215         assert(plist->getSize() >= 1);
4216         plist->changeItem(0, preview);
4217 }
4218
4219 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4220 {
4221         RemoteClient *client = getClientNoEx(peer_id,state_min);
4222         if(!client)
4223                 throw ClientNotFoundException("Client not found");
4224
4225         return client;
4226 }
4227 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4228 {
4229         return m_clients.getClientNoEx(peer_id, state_min);
4230 }
4231
4232 std::string Server::getPlayerName(u16 peer_id)
4233 {
4234         Player *player = m_env->getPlayer(peer_id);
4235         if(player == NULL)
4236                 return "[id="+itos(peer_id)+"]";
4237         return player->getName();
4238 }
4239
4240 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4241 {
4242         Player *player = m_env->getPlayer(peer_id);
4243         if(player == NULL)
4244                 return NULL;
4245         return player->getPlayerSAO();
4246 }
4247
4248 std::wstring Server::getStatusString()
4249 {
4250         std::wostringstream os(std::ios_base::binary);
4251         os<<L"# Server: ";
4252         // Version
4253         os<<L"version="<<narrow_to_wide(minetest_version_simple);
4254         // Uptime
4255         os<<L", uptime="<<m_uptime.get();
4256         // Max lag estimate
4257         os<<L", max_lag="<<m_env->getMaxLagEstimate();
4258         // Information about clients
4259         bool first = true;
4260         os<<L", clients={";
4261         std::list<u16> clients = m_clients.getClientIDs();
4262         for(std::list<u16>::iterator i = clients.begin();
4263                 i != clients.end(); ++i)
4264         {
4265                 // Get player
4266                 Player *player = m_env->getPlayer(*i);
4267                 // Get name of player
4268                 std::wstring name = L"unknown";
4269                 if(player != NULL)
4270                         name = narrow_to_wide(player->getName());
4271                 // Add name to information string
4272                 if(!first)
4273                         os<<L",";
4274                 else
4275                         first = false;
4276                 os<<name;
4277         }
4278         os<<L"}";
4279         if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4280                 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4281         if(g_settings->get("motd") != "")
4282                 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4283         return os.str();
4284 }
4285
4286 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4287 {
4288         std::set<std::string> privs;
4289         m_script->getAuth(name, NULL, &privs);
4290         return privs;
4291 }
4292
4293 bool Server::checkPriv(const std::string &name, const std::string &priv)
4294 {
4295         std::set<std::string> privs = getPlayerEffectivePrivs(name);
4296         return (privs.count(priv) != 0);
4297 }
4298
4299 void Server::reportPrivsModified(const std::string &name)
4300 {
4301         if(name == ""){
4302                 std::list<u16> clients = m_clients.getClientIDs();
4303                 for(std::list<u16>::iterator
4304                                 i = clients.begin();
4305                                 i != clients.end(); ++i){
4306                         Player *player = m_env->getPlayer(*i);
4307                         reportPrivsModified(player->getName());
4308                 }
4309         } else {
4310                 Player *player = m_env->getPlayer(name.c_str());
4311                 if(!player)
4312                         return;
4313                 SendPlayerPrivileges(player->peer_id);
4314                 PlayerSAO *sao = player->getPlayerSAO();
4315                 if(!sao)
4316                         return;
4317                 sao->updatePrivileges(
4318                                 getPlayerEffectivePrivs(name),
4319                                 isSingleplayer());
4320         }
4321 }
4322
4323 void Server::reportInventoryFormspecModified(const std::string &name)
4324 {
4325         Player *player = m_env->getPlayer(name.c_str());
4326         if(!player)
4327                 return;
4328         SendPlayerInventoryFormspec(player->peer_id);
4329 }
4330
4331 void Server::setIpBanned(const std::string &ip, const std::string &name)
4332 {
4333         m_banmanager->add(ip, name);
4334 }
4335
4336 void Server::unsetIpBanned(const std::string &ip_or_name)
4337 {
4338         m_banmanager->remove(ip_or_name);
4339 }
4340
4341 std::string Server::getBanDescription(const std::string &ip_or_name)
4342 {
4343         return m_banmanager->getBanDescription(ip_or_name);
4344 }
4345
4346 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4347 {
4348         Player *player = m_env->getPlayer(name);
4349         if(!player)
4350                 return;
4351         if (prepend)
4352                 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4353         else
4354                 SendChatMessage(player->peer_id, msg);
4355 }
4356
4357 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4358 {
4359         Player *player = m_env->getPlayer(playername);
4360
4361         if(!player)
4362         {
4363                 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4364                 return false;
4365         }
4366
4367         SendShowFormspecMessage(player->peer_id, formspec, formname);
4368         return true;
4369 }
4370
4371 u32 Server::hudAdd(Player *player, HudElement *form) {
4372         if (!player)
4373                 return -1;
4374
4375         u32 id = player->getFreeHudID();
4376         if (id < player->hud.size())
4377                 player->hud[id] = form;
4378         else
4379                 player->hud.push_back(form);
4380         
4381         SendHUDAdd(player->peer_id, id, form);
4382         return id;
4383 }
4384
4385 bool Server::hudRemove(Player *player, u32 id) {
4386         if (!player || id >= player->hud.size() || !player->hud[id])
4387                 return false;
4388
4389         delete player->hud[id];
4390         player->hud[id] = NULL;
4391         
4392         SendHUDRemove(player->peer_id, id);
4393         return true;
4394 }
4395
4396 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4397         if (!player)
4398                 return false;
4399
4400         SendHUDChange(player->peer_id, id, stat, data);
4401         return true;
4402 }
4403
4404 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4405         if (!player)
4406                 return false;
4407
4408         SendHUDSetFlags(player->peer_id, flags, mask);
4409         return true;
4410 }
4411
4412 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4413         if (!player)
4414                 return false;
4415         if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4416                 return false;
4417
4418         std::ostringstream os(std::ios::binary);
4419         writeS32(os, hotbar_itemcount);
4420         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4421         return true;
4422 }
4423
4424 void Server::hudSetHotbarImage(Player *player, std::string name) {
4425         if (!player)
4426                 return;
4427
4428         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4429 }
4430
4431 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4432         if (!player)
4433                 return;
4434
4435         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4436 }
4437
4438 void Server::notifyPlayers(const std::wstring msg)
4439 {
4440         SendChatMessage(PEER_ID_INEXISTENT,msg);
4441 }
4442
4443 void Server::spawnParticle(const char *playername, v3f pos,
4444                 v3f velocity, v3f acceleration,
4445                 float expirationtime, float size, bool
4446                 collisiondetection, bool vertical, std::string texture)
4447 {
4448         Player *player = m_env->getPlayer(playername);
4449         if(!player)
4450                 return;
4451         SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4452                         expirationtime, size, collisiondetection, vertical, texture);
4453 }
4454
4455 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4456                 float expirationtime, float size,
4457                 bool collisiondetection, bool vertical, std::string texture)
4458 {
4459         SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4460                         expirationtime, size, collisiondetection, vertical, texture);
4461 }
4462
4463 u32 Server::addParticleSpawner(const char *playername,
4464                 u16 amount, float spawntime,
4465                 v3f minpos, v3f maxpos,
4466                 v3f minvel, v3f maxvel,
4467                 v3f minacc, v3f maxacc,
4468                 float minexptime, float maxexptime,
4469                 float minsize, float maxsize,
4470                 bool collisiondetection, bool vertical, std::string texture)
4471 {
4472         Player *player = m_env->getPlayer(playername);
4473         if(!player)
4474                 return -1;
4475
4476         u32 id = 0;
4477         for(;;) // look for unused particlespawner id
4478         {
4479                 id++;
4480                 if (std::find(m_particlespawner_ids.begin(),
4481                                 m_particlespawner_ids.end(), id)
4482                                 == m_particlespawner_ids.end())
4483                 {
4484                         m_particlespawner_ids.push_back(id);
4485                         break;
4486                 }
4487         }
4488
4489         SendAddParticleSpawner(player->peer_id, amount, spawntime,
4490                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4491                 minexptime, maxexptime, minsize, maxsize,
4492                 collisiondetection, vertical, texture, id);
4493
4494         return id;
4495 }
4496
4497 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4498                 v3f minpos, v3f maxpos,
4499                 v3f minvel, v3f maxvel,
4500                 v3f minacc, v3f maxacc,
4501                 float minexptime, float maxexptime,
4502                 float minsize, float maxsize,
4503                 bool collisiondetection, bool vertical, std::string texture)
4504 {
4505         u32 id = 0;
4506         for(;;) // look for unused particlespawner id
4507         {
4508                 id++;
4509                 if (std::find(m_particlespawner_ids.begin(),
4510                                 m_particlespawner_ids.end(), id)
4511                                 == m_particlespawner_ids.end())
4512                 {
4513                         m_particlespawner_ids.push_back(id);
4514                         break;
4515                 }
4516         }
4517
4518         SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4519                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4520                 minexptime, maxexptime, minsize, maxsize,
4521                 collisiondetection, vertical, texture, id);
4522
4523         return id;
4524 }
4525
4526 void Server::deleteParticleSpawner(const char *playername, u32 id)
4527 {
4528         Player *player = m_env->getPlayer(playername);
4529         if(!player)
4530                 return;
4531
4532         m_particlespawner_ids.erase(
4533                         std::remove(m_particlespawner_ids.begin(),
4534                         m_particlespawner_ids.end(), id),
4535                         m_particlespawner_ids.end());
4536         SendDeleteParticleSpawner(player->peer_id, id);
4537 }
4538
4539 void Server::deleteParticleSpawnerAll(u32 id)
4540 {
4541         m_particlespawner_ids.erase(
4542                         std::remove(m_particlespawner_ids.begin(),
4543                         m_particlespawner_ids.end(), id),
4544                         m_particlespawner_ids.end());
4545         SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4546 }
4547
4548 Inventory* Server::createDetachedInventory(const std::string &name)
4549 {
4550         if(m_detached_inventories.count(name) > 0){
4551                 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4552                 delete m_detached_inventories[name];
4553         } else {
4554                 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4555         }
4556         Inventory *inv = new Inventory(m_itemdef);
4557         assert(inv);
4558         m_detached_inventories[name] = inv;
4559         //TODO find a better way to do this
4560         sendDetachedInventory(name,PEER_ID_INEXISTENT);
4561         return inv;
4562 }
4563
4564 class BoolScopeSet
4565 {
4566 public:
4567         BoolScopeSet(bool *dst, bool val):
4568                 m_dst(dst)
4569         {
4570                 m_orig_state = *m_dst;
4571                 *m_dst = val;
4572         }
4573         ~BoolScopeSet()
4574         {
4575                 *m_dst = m_orig_state;
4576         }
4577 private:
4578         bool *m_dst;
4579         bool m_orig_state;
4580 };
4581
4582 // actions: time-reversed list
4583 // Return value: success/failure
4584 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4585                 std::list<std::string> *log)
4586 {
4587         infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4588         ServerMap *map = (ServerMap*)(&m_env->getMap());
4589         // Disable rollback report sink while reverting
4590         BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4591
4592         // Fail if no actions to handle
4593         if(actions.empty()){
4594                 log->push_back("Nothing to do.");
4595                 return false;
4596         }
4597
4598         int num_tried = 0;
4599         int num_failed = 0;
4600
4601         for(std::list<RollbackAction>::const_iterator
4602                         i = actions.begin();
4603                         i != actions.end(); i++)
4604         {
4605                 const RollbackAction &action = *i;
4606                 num_tried++;
4607                 bool success = action.applyRevert(map, this, this);
4608                 if(!success){
4609                         num_failed++;
4610                         std::ostringstream os;
4611                         os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4612                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4613                         if(log)
4614                                 log->push_back(os.str());
4615                 }else{
4616                         std::ostringstream os;
4617                         os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4618                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4619                         if(log)
4620                                 log->push_back(os.str());
4621                 }
4622         }
4623
4624         infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4625                         <<" failed"<<std::endl;
4626
4627         // Call it done if less than half failed
4628         return num_failed <= num_tried/2;
4629 }
4630
4631 // IGameDef interface
4632 // Under envlock
4633 IItemDefManager* Server::getItemDefManager()
4634 {
4635         return m_itemdef;
4636 }
4637 INodeDefManager* Server::getNodeDefManager()
4638 {
4639         return m_nodedef;
4640 }
4641 ICraftDefManager* Server::getCraftDefManager()
4642 {
4643         return m_craftdef;
4644 }
4645 ITextureSource* Server::getTextureSource()
4646 {
4647         return NULL;
4648 }
4649 IShaderSource* Server::getShaderSource()
4650 {
4651         return NULL;
4652 }
4653 u16 Server::allocateUnknownNodeId(const std::string &name)
4654 {
4655         return m_nodedef->allocateDummy(name);
4656 }
4657 ISoundManager* Server::getSoundManager()
4658 {
4659         return &dummySoundManager;
4660 }
4661 MtEventManager* Server::getEventManager()
4662 {
4663         return m_event;
4664 }
4665 IRollbackReportSink* Server::getRollbackReportSink()
4666 {
4667         if(!m_enable_rollback_recording)
4668                 return NULL;
4669         if(!m_rollback_sink_enabled)
4670                 return NULL;
4671         return m_rollback;
4672 }
4673
4674 IWritableItemDefManager* Server::getWritableItemDefManager()
4675 {
4676         return m_itemdef;
4677 }
4678 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4679 {
4680         return m_nodedef;
4681 }
4682 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4683 {
4684         return m_craftdef;
4685 }
4686
4687 const ModSpec* Server::getModSpec(const std::string &modname)
4688 {
4689         for(std::vector<ModSpec>::iterator i = m_mods.begin();
4690                         i != m_mods.end(); i++){
4691                 const ModSpec &mod = *i;
4692                 if(mod.name == modname)
4693                         return &mod;
4694         }
4695         return NULL;
4696 }
4697 void Server::getModNames(std::list<std::string> &modlist)
4698 {
4699         for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4700         {
4701                 modlist.push_back(i->name);
4702         }
4703 }
4704 std::string Server::getBuiltinLuaPath()
4705 {
4706         return porting::path_share + DIR_DELIM + "builtin";
4707 }
4708
4709 v3f findSpawnPos(ServerMap &map)
4710 {
4711         //return v3f(50,50,50)*BS;
4712
4713         v3s16 nodepos;
4714
4715 #if 0
4716         nodepos = v2s16(0,0);
4717         groundheight = 20;
4718 #endif
4719
4720 #if 1
4721         s16 water_level = map.m_mgparams->water_level;
4722
4723         // Try to find a good place a few times
4724         for(s32 i=0; i<1000; i++)
4725         {
4726                 s32 range = 1 + i;
4727                 // We're going to try to throw the player to this position
4728                 v2s16 nodepos2d = v2s16(
4729                                 -range + (myrand() % (range * 2)),
4730                                 -range + (myrand() % (range * 2)));
4731
4732                 // Get ground height at point
4733                 s16 groundheight = map.findGroundLevel(nodepos2d);
4734                 if (groundheight <= water_level) // Don't go underwater
4735                         continue;
4736                 if (groundheight > water_level + 6) // Don't go to high places
4737                         continue;
4738
4739                 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4740                 bool is_good = false;
4741                 s32 air_count = 0;
4742                 for (s32 i = 0; i < 10; i++) {
4743                         v3s16 blockpos = getNodeBlockPos(nodepos);
4744                         map.emergeBlock(blockpos, true);
4745                         content_t c = map.getNodeNoEx(nodepos).getContent();
4746                         if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4747                                 air_count++;
4748                                 if (air_count >= 2){
4749                                         is_good = true;
4750                                         break;
4751                                 }
4752                         }
4753                         nodepos.Y++;
4754                 }
4755                 if(is_good){
4756                         // Found a good place
4757                         //infostream<<"Searched through "<<i<<" places."<<std::endl;
4758                         break;
4759                 }
4760         }
4761 #endif
4762
4763         return intToFloat(nodepos, BS);
4764 }
4765
4766 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4767 {
4768         RemotePlayer *player = NULL;
4769         bool newplayer = false;
4770
4771         /*
4772                 Try to get an existing player
4773         */
4774         player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4775
4776         // If player is already connected, cancel
4777         if(player != NULL && player->peer_id != 0)
4778         {
4779                 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4780                 return NULL;
4781         }
4782
4783         /*
4784                 If player with the wanted peer_id already exists, cancel.
4785         */
4786         if(m_env->getPlayer(peer_id) != NULL)
4787         {
4788                 infostream<<"emergePlayer(): Player with wrong name but same"
4789                                 " peer_id already exists"<<std::endl;
4790                 return NULL;
4791         }
4792
4793         /*
4794                 Create a new player if it doesn't exist yet
4795         */
4796         if(player == NULL)
4797         {
4798                 newplayer = true;
4799                 player = new RemotePlayer(this);
4800                 player->updateName(name);
4801
4802                 /* Set player position */
4803                 infostream<<"Server: Finding spawn place for player \""
4804                                 <<name<<"\""<<std::endl;
4805                 v3f pos = findSpawnPos(m_env->getServerMap());
4806                 player->setPosition(pos);
4807
4808                 /* Add player to environment */
4809                 m_env->addPlayer(player);
4810         }
4811
4812         /*
4813                 Create a new player active object
4814         */
4815         PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4816                         getPlayerEffectivePrivs(player->getName()),
4817                         isSingleplayer());
4818
4819         /* Clean up old HUD elements from previous sessions */
4820         player->hud.clear();
4821
4822         /* Add object to environment */
4823         m_env->addActiveObject(playersao);
4824
4825         /* Run scripts */
4826         if(newplayer)
4827                 m_script->on_newplayer(playersao);
4828
4829         return playersao;
4830 }
4831
4832 void dedicated_server_loop(Server &server, bool &kill)
4833 {
4834         DSTACK(__FUNCTION_NAME);
4835
4836         verbosestream<<"dedicated_server_loop()"<<std::endl;
4837
4838         IntervalLimiter m_profiler_interval;
4839
4840         for(;;)
4841         {
4842                 float steplen = g_settings->getFloat("dedicated_server_step");
4843                 // This is kind of a hack but can be done like this
4844                 // because server.step() is very light
4845                 {
4846                         ScopeProfiler sp(g_profiler, "dedicated server sleep");
4847                         sleep_ms((int)(steplen*1000.0));
4848                 }
4849                 server.step(steplen);
4850
4851                 if(server.getShutdownRequested() || kill)
4852                 {
4853                         infostream<<"Dedicated server quitting"<<std::endl;
4854 #if USE_CURL
4855                         if(g_settings->getBool("server_announce") == true)
4856                                 ServerList::sendAnnounce("delete");
4857 #endif
4858                         break;
4859                 }
4860
4861                 /*
4862                         Profiler
4863                 */
4864                 float profiler_print_interval =
4865                                 g_settings->getFloat("profiler_print_interval");
4866                 if(profiler_print_interval != 0)
4867                 {
4868                         if(m_profiler_interval.step(steplen, profiler_print_interval))
4869                         {
4870                                 infostream<<"Profiler:"<<std::endl;
4871                                 g_profiler->print(infostream);
4872                                 g_profiler->clear();
4873                         }
4874                 }
4875         }
4876 }
4877
4878