]> git.lizzy.rs Git - dragonfireclient.git/blob - src/server.cpp
Add player:set_sky() with simple skybox support
[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::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3275                 const std::string &type, const std::vector<std::string> &params)
3276 {
3277         std::ostringstream os(std::ios_base::binary);
3278
3279         // Write command
3280         writeU16(os, TOCLIENT_SET_SKY);
3281         writeARGB8(os, bgcolor);
3282         os<<serializeString(type);
3283         writeU16(os, params.size());
3284         for(size_t i=0; i<params.size(); i++)
3285                 os<<serializeString(params[i]);
3286
3287         // Make data buffer
3288         std::string s = os.str();
3289         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3290         // Send as reliable
3291         m_clients.send(peer_id, 0, data, true);
3292 }
3293
3294 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3295 {
3296         DSTACK(__FUNCTION_NAME);
3297
3298         // Make packet
3299         SharedBuffer<u8> data(2+2+4);
3300         writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3301         writeU16(&data[2], time);
3302         writeF1000(&data[4], time_speed);
3303
3304         if (peer_id == PEER_ID_INEXISTENT) {
3305                 m_clients.sendToAll(0,data,true);
3306         }
3307         else {
3308                 // Send as reliable
3309                 m_clients.send(peer_id, 0, data, true);
3310         }
3311 }
3312
3313 void Server::SendPlayerHP(u16 peer_id)
3314 {
3315         DSTACK(__FUNCTION_NAME);
3316         PlayerSAO *playersao = getPlayerSAO(peer_id);
3317         assert(playersao);
3318         playersao->m_hp_not_sent = false;
3319         SendHP(peer_id, playersao->getHP());
3320
3321         // Send to other clients
3322         std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3323         ActiveObjectMessage aom(playersao->getId(), true, str);
3324         playersao->m_messages_out.push_back(aom);
3325 }
3326
3327 void Server::SendPlayerBreath(u16 peer_id)
3328 {
3329         DSTACK(__FUNCTION_NAME);
3330         PlayerSAO *playersao = getPlayerSAO(peer_id);
3331         assert(playersao);
3332         playersao->m_breath_not_sent = false;
3333         SendBreath(peer_id, playersao->getBreath());
3334 }
3335
3336 void Server::SendMovePlayer(u16 peer_id)
3337 {
3338         DSTACK(__FUNCTION_NAME);
3339         Player *player = m_env->getPlayer(peer_id);
3340         assert(player);
3341
3342         std::ostringstream os(std::ios_base::binary);
3343         writeU16(os, TOCLIENT_MOVE_PLAYER);
3344         writeV3F1000(os, player->getPosition());
3345         writeF1000(os, player->getPitch());
3346         writeF1000(os, player->getYaw());
3347
3348         {
3349                 v3f pos = player->getPosition();
3350                 f32 pitch = player->getPitch();
3351                 f32 yaw = player->getYaw();
3352                 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3353                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3354                                 <<" pitch="<<pitch
3355                                 <<" yaw="<<yaw
3356                                 <<std::endl;
3357         }
3358
3359         // Make data buffer
3360         std::string s = os.str();
3361         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3362         // Send as reliable
3363         m_clients.send(peer_id, 0, data, true);
3364 }
3365
3366 void Server::SendPlayerPrivileges(u16 peer_id)
3367 {
3368         Player *player = m_env->getPlayer(peer_id);
3369         assert(player);
3370         if(player->peer_id == PEER_ID_INEXISTENT)
3371                 return;
3372
3373         std::set<std::string> privs;
3374         m_script->getAuth(player->getName(), NULL, &privs);
3375
3376         std::ostringstream os(std::ios_base::binary);
3377         writeU16(os, TOCLIENT_PRIVILEGES);
3378         writeU16(os, privs.size());
3379         for(std::set<std::string>::const_iterator i = privs.begin();
3380                         i != privs.end(); i++){
3381                 os<<serializeString(*i);
3382         }
3383
3384         // Make data buffer
3385         std::string s = os.str();
3386         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3387         // Send as reliable
3388         m_clients.send(peer_id, 0, data, true);
3389 }
3390
3391 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3392 {
3393         Player *player = m_env->getPlayer(peer_id);
3394         assert(player);
3395         if(player->peer_id == PEER_ID_INEXISTENT)
3396                 return;
3397
3398         std::ostringstream os(std::ios_base::binary);
3399         writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3400         os<<serializeLongString(player->inventory_formspec);
3401
3402         // Make data buffer
3403         std::string s = os.str();
3404         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3405         // Send as reliable
3406         m_clients.send(peer_id, 0, data, true);
3407 }
3408
3409 s32 Server::playSound(const SimpleSoundSpec &spec,
3410                 const ServerSoundParams &params)
3411 {
3412         // Find out initial position of sound
3413         bool pos_exists = false;
3414         v3f pos = params.getPos(m_env, &pos_exists);
3415         // If position is not found while it should be, cancel sound
3416         if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3417                 return -1;
3418
3419         // Filter destination clients
3420         std::list<u16> dst_clients;
3421         if(params.to_player != "")
3422         {
3423                 Player *player = m_env->getPlayer(params.to_player.c_str());
3424                 if(!player){
3425                         infostream<<"Server::playSound: Player \""<<params.to_player
3426                                         <<"\" not found"<<std::endl;
3427                         return -1;
3428                 }
3429                 if(player->peer_id == PEER_ID_INEXISTENT){
3430                         infostream<<"Server::playSound: Player \""<<params.to_player
3431                                         <<"\" not connected"<<std::endl;
3432                         return -1;
3433                 }
3434                 dst_clients.push_back(player->peer_id);
3435         }
3436         else
3437         {
3438                 std::list<u16> clients = m_clients.getClientIDs();
3439
3440                 for(std::list<u16>::iterator
3441                                 i = clients.begin(); i != clients.end(); ++i)
3442                 {
3443                         Player *player = m_env->getPlayer(*i);
3444                         if(!player)
3445                                 continue;
3446                         if(pos_exists){
3447                                 if(player->getPosition().getDistanceFrom(pos) >
3448                                                 params.max_hear_distance)
3449                                         continue;
3450                         }
3451                         dst_clients.push_back(*i);
3452                 }
3453         }
3454         if(dst_clients.size() == 0)
3455                 return -1;
3456
3457         // Create the sound
3458         s32 id = m_next_sound_id++;
3459         // The sound will exist as a reference in m_playing_sounds
3460         m_playing_sounds[id] = ServerPlayingSound();
3461         ServerPlayingSound &psound = m_playing_sounds[id];
3462         psound.params = params;
3463         for(std::list<u16>::iterator i = dst_clients.begin();
3464                         i != dst_clients.end(); i++)
3465                 psound.clients.insert(*i);
3466         // Create packet
3467         std::ostringstream os(std::ios_base::binary);
3468         writeU16(os, TOCLIENT_PLAY_SOUND);
3469         writeS32(os, id);
3470         os<<serializeString(spec.name);
3471         writeF1000(os, spec.gain * params.gain);
3472         writeU8(os, params.type);
3473         writeV3F1000(os, pos);
3474         writeU16(os, params.object);
3475         writeU8(os, params.loop);
3476         // Make data buffer
3477         std::string s = os.str();
3478         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3479         // Send
3480         for(std::list<u16>::iterator i = dst_clients.begin();
3481                         i != dst_clients.end(); i++){
3482                 // Send as reliable
3483                 m_clients.send(*i, 0, data, true);
3484         }
3485         return id;
3486 }
3487 void Server::stopSound(s32 handle)
3488 {
3489         // Get sound reference
3490         std::map<s32, ServerPlayingSound>::iterator i =
3491                         m_playing_sounds.find(handle);
3492         if(i == m_playing_sounds.end())
3493                 return;
3494         ServerPlayingSound &psound = i->second;
3495         // Create packet
3496         std::ostringstream os(std::ios_base::binary);
3497         writeU16(os, TOCLIENT_STOP_SOUND);
3498         writeS32(os, handle);
3499         // Make data buffer
3500         std::string s = os.str();
3501         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3502         // Send
3503         for(std::set<u16>::iterator i = psound.clients.begin();
3504                         i != psound.clients.end(); i++){
3505                 // Send as reliable
3506                 m_clients.send(*i, 0, data, true);
3507         }
3508         // Remove sound reference
3509         m_playing_sounds.erase(i);
3510 }
3511
3512 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3513         std::list<u16> *far_players, float far_d_nodes)
3514 {
3515         float maxd = far_d_nodes*BS;
3516         v3f p_f = intToFloat(p, BS);
3517
3518         // Create packet
3519         u32 replysize = 8;
3520         SharedBuffer<u8> reply(replysize);
3521         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3522         writeS16(&reply[2], p.X);
3523         writeS16(&reply[4], p.Y);
3524         writeS16(&reply[6], p.Z);
3525
3526         std::list<u16> clients = m_clients.getClientIDs();
3527         for(std::list<u16>::iterator
3528                 i = clients.begin();
3529                 i != clients.end(); ++i)
3530         {
3531                 if(far_players)
3532                 {
3533                         // Get player
3534                         Player *player = m_env->getPlayer(*i);
3535                         if(player)
3536                         {
3537                                 // If player is far away, only set modified blocks not sent
3538                                 v3f player_pos = player->getPosition();
3539                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3540                                 {
3541                                         far_players->push_back(*i);
3542                                         continue;
3543                                 }
3544                         }
3545                 }
3546
3547                 // Send as reliable
3548                 m_clients.send(*i, 0, reply, true);
3549         }
3550 }
3551
3552 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3553                 std::list<u16> *far_players, float far_d_nodes,
3554                 bool remove_metadata)
3555 {
3556         float maxd = far_d_nodes*BS;
3557         v3f p_f = intToFloat(p, BS);
3558
3559         std::list<u16> clients = m_clients.getClientIDs();
3560                 for(std::list<u16>::iterator
3561                         i = clients.begin();
3562                         i != clients.end(); ++i)
3563                 {
3564
3565                 if(far_players)
3566                 {
3567                         // Get player
3568                         Player *player = m_env->getPlayer(*i);
3569                         if(player)
3570                         {
3571                                 // If player is far away, only set modified blocks not sent
3572                                 v3f player_pos = player->getPosition();
3573                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3574                                 {
3575                                         far_players->push_back(*i);
3576                                         continue;
3577                                 }
3578                         }
3579                 }
3580                 SharedBuffer<u8> reply(0);
3581                 m_clients.Lock();
3582                 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3583                 if (client != 0)
3584                 {
3585                         // Create packet
3586                         u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3587                         reply = SharedBuffer<u8>(replysize);
3588                         writeU16(&reply[0], TOCLIENT_ADDNODE);
3589                         writeS16(&reply[2], p.X);
3590                         writeS16(&reply[4], p.Y);
3591                         writeS16(&reply[6], p.Z);
3592                         n.serialize(&reply[8], client->serialization_version);
3593                         u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3594                         writeU8(&reply[index], remove_metadata ? 0 : 1);
3595
3596                         if (!remove_metadata) {
3597                                 if (client->net_proto_version <= 21) {
3598                                         // Old clients always clear metadata; fix it
3599                                         // by sending the full block again.
3600                                         client->SetBlockNotSent(p);
3601                                 }
3602                         }
3603                 }
3604                 m_clients.Unlock();
3605
3606                 // Send as reliable
3607                 if (reply.getSize() > 0)
3608                         m_clients.send(*i, 0, reply, true);
3609         }
3610 }
3611
3612 void Server::setBlockNotSent(v3s16 p)
3613 {
3614         std::list<u16> clients = m_clients.getClientIDs();
3615         m_clients.Lock();
3616         for(std::list<u16>::iterator
3617                 i = clients.begin();
3618                 i != clients.end(); ++i)
3619         {
3620                 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3621                 client->SetBlockNotSent(p);
3622         }
3623         m_clients.Unlock();
3624 }
3625
3626 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3627 {
3628         DSTACK(__FUNCTION_NAME);
3629
3630         v3s16 p = block->getPos();
3631
3632 #if 0
3633         // Analyze it a bit
3634         bool completely_air = true;
3635         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3636         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3637         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3638         {
3639                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3640                 {
3641                         completely_air = false;
3642                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3643                 }
3644         }
3645
3646         // Print result
3647         infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3648         if(completely_air)
3649                 infostream<<"[completely air] ";
3650         infostream<<std::endl;
3651 #endif
3652
3653         /*
3654                 Create a packet with the block in the right format
3655         */
3656
3657         std::ostringstream os(std::ios_base::binary);
3658         block->serialize(os, ver, false);
3659         block->serializeNetworkSpecific(os, net_proto_version);
3660         std::string s = os.str();
3661         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3662
3663         u32 replysize = 8 + blockdata.getSize();
3664         SharedBuffer<u8> reply(replysize);
3665         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3666         writeS16(&reply[2], p.X);
3667         writeS16(&reply[4], p.Y);
3668         writeS16(&reply[6], p.Z);
3669         memcpy(&reply[8], *blockdata, blockdata.getSize());
3670
3671         /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3672                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3673
3674         /*
3675                 Send packet
3676         */
3677         m_clients.send(peer_id, 2, reply, true);
3678 }
3679
3680 void Server::SendBlocks(float dtime)
3681 {
3682         DSTACK(__FUNCTION_NAME);
3683
3684         JMutexAutoLock envlock(m_env_mutex);
3685         //TODO check if one big lock could be faster then multiple small ones
3686
3687         ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3688
3689         std::vector<PrioritySortedBlockTransfer> queue;
3690
3691         s32 total_sending = 0;
3692
3693         {
3694                 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3695
3696                 std::list<u16> clients = m_clients.getClientIDs();
3697
3698                 m_clients.Lock();
3699                 for(std::list<u16>::iterator
3700                         i = clients.begin();
3701                         i != clients.end(); ++i)
3702                 {
3703                         RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3704
3705                         if (client == NULL)
3706                                 return;
3707
3708                         total_sending += client->SendingCount();
3709                         client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3710                 }
3711                 m_clients.Unlock();
3712         }
3713
3714         // Sort.
3715         // Lowest priority number comes first.
3716         // Lowest is most important.
3717         std::sort(queue.begin(), queue.end());
3718
3719         m_clients.Lock();
3720         for(u32 i=0; i<queue.size(); i++)
3721         {
3722                 //TODO: Calculate limit dynamically
3723                 if(total_sending >= g_settings->getS32
3724                                 ("max_simultaneous_block_sends_server_total"))
3725                         break;
3726
3727                 PrioritySortedBlockTransfer q = queue[i];
3728
3729                 MapBlock *block = NULL;
3730                 try
3731                 {
3732                         block = m_env->getMap().getBlockNoCreate(q.pos);
3733                 }
3734                 catch(InvalidPositionException &e)
3735                 {
3736                         continue;
3737                 }
3738
3739                 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3740
3741                 if(!client)
3742                         continue;
3743
3744                 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3745
3746                 client->SentBlock(q.pos);
3747                 total_sending++;
3748         }
3749         m_clients.Unlock();
3750 }
3751
3752 void Server::fillMediaCache()
3753 {
3754         DSTACK(__FUNCTION_NAME);
3755
3756         infostream<<"Server: Calculating media file checksums"<<std::endl;
3757
3758         // Collect all media file paths
3759         std::list<std::string> paths;
3760         for(std::vector<ModSpec>::iterator i = m_mods.begin();
3761                         i != m_mods.end(); i++){
3762                 const ModSpec &mod = *i;
3763                 paths.push_back(mod.path + DIR_DELIM + "textures");
3764                 paths.push_back(mod.path + DIR_DELIM + "sounds");
3765                 paths.push_back(mod.path + DIR_DELIM + "media");
3766                 paths.push_back(mod.path + DIR_DELIM + "models");
3767         }
3768         paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3769
3770         // Collect media file information from paths into cache
3771         for(std::list<std::string>::iterator i = paths.begin();
3772                         i != paths.end(); i++)
3773         {
3774                 std::string mediapath = *i;
3775                 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3776                 for(u32 j=0; j<dirlist.size(); j++){
3777                         if(dirlist[j].dir) // Ignode dirs
3778                                 continue;
3779                         std::string filename = dirlist[j].name;
3780                         // If name contains illegal characters, ignore the file
3781                         if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3782                                 infostream<<"Server: ignoring illegal file name: \""
3783                                                 <<filename<<"\""<<std::endl;
3784                                 continue;
3785                         }
3786                         // If name is not in a supported format, ignore it
3787                         const char *supported_ext[] = {
3788                                 ".png", ".jpg", ".bmp", ".tga",
3789                                 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3790                                 ".ogg",
3791                                 ".x", ".b3d", ".md2", ".obj",
3792                                 NULL
3793                         };
3794                         if(removeStringEnd(filename, supported_ext) == ""){
3795                                 infostream<<"Server: ignoring unsupported file extension: \""
3796                                                 <<filename<<"\""<<std::endl;
3797                                 continue;
3798                         }
3799                         // Ok, attempt to load the file and add to cache
3800                         std::string filepath = mediapath + DIR_DELIM + filename;
3801                         // Read data
3802                         std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3803                         if(fis.good() == false){
3804                                 errorstream<<"Server::fillMediaCache(): Could not open \""
3805                                                 <<filename<<"\" for reading"<<std::endl;
3806                                 continue;
3807                         }
3808                         std::ostringstream tmp_os(std::ios_base::binary);
3809                         bool bad = false;
3810                         for(;;){
3811                                 char buf[1024];
3812                                 fis.read(buf, 1024);
3813                                 std::streamsize len = fis.gcount();
3814                                 tmp_os.write(buf, len);
3815                                 if(fis.eof())
3816                                         break;
3817                                 if(!fis.good()){
3818                                         bad = true;
3819                                         break;
3820                                 }
3821                         }
3822                         if(bad){
3823                                 errorstream<<"Server::fillMediaCache(): Failed to read \""
3824                                                 <<filename<<"\""<<std::endl;
3825                                 continue;
3826                         }
3827                         if(tmp_os.str().length() == 0){
3828                                 errorstream<<"Server::fillMediaCache(): Empty file \""
3829                                                 <<filepath<<"\""<<std::endl;
3830                                 continue;
3831                         }
3832
3833                         SHA1 sha1;
3834                         sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3835
3836                         unsigned char *digest = sha1.getDigest();
3837                         std::string sha1_base64 = base64_encode(digest, 20);
3838                         std::string sha1_hex = hex_encode((char*)digest, 20);
3839                         free(digest);
3840
3841                         // Put in list
3842                         this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3843                         verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3844                 }
3845         }
3846 }
3847
3848 struct SendableMediaAnnouncement
3849 {
3850         std::string name;
3851         std::string sha1_digest;
3852
3853         SendableMediaAnnouncement(const std::string name_="",
3854                         const std::string sha1_digest_=""):
3855                 name(name_),
3856                 sha1_digest(sha1_digest_)
3857         {}
3858 };
3859
3860 void Server::sendMediaAnnouncement(u16 peer_id)
3861 {
3862         DSTACK(__FUNCTION_NAME);
3863
3864         verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
3865                         <<std::endl;
3866
3867         std::list<SendableMediaAnnouncement> file_announcements;
3868
3869         for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
3870                         i != m_media.end(); i++){
3871                 // Put in list
3872                 file_announcements.push_back(
3873                                 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
3874         }
3875
3876         // Make packet
3877         std::ostringstream os(std::ios_base::binary);
3878
3879         /*
3880                 u16 command
3881                 u32 number of files
3882                 for each texture {
3883                         u16 length of name
3884                         string name
3885                         u16 length of sha1_digest
3886                         string sha1_digest
3887                 }
3888         */
3889
3890         writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
3891         writeU16(os, file_announcements.size());
3892
3893         for(std::list<SendableMediaAnnouncement>::iterator
3894                         j = file_announcements.begin();
3895                         j != file_announcements.end(); ++j){
3896                 os<<serializeString(j->name);
3897                 os<<serializeString(j->sha1_digest);
3898         }
3899         os<<serializeString(g_settings->get("remote_media"));
3900
3901         // Make data buffer
3902         std::string s = os.str();
3903         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3904
3905         // Send as reliable
3906         m_clients.send(peer_id, 0, data, true);
3907 }
3908
3909 struct SendableMedia
3910 {
3911         std::string name;
3912         std::string path;
3913         std::string data;
3914
3915         SendableMedia(const std::string &name_="", const std::string path_="",
3916                         const std::string &data_=""):
3917                 name(name_),
3918                 path(path_),
3919                 data(data_)
3920         {}
3921 };
3922
3923 void Server::sendRequestedMedia(u16 peer_id,
3924                 const std::list<std::string> &tosend)
3925 {
3926         DSTACK(__FUNCTION_NAME);
3927
3928         verbosestream<<"Server::sendRequestedMedia(): "
3929                         <<"Sending files to client"<<std::endl;
3930
3931         /* Read files */
3932
3933         // Put 5kB in one bunch (this is not accurate)
3934         u32 bytes_per_bunch = 5000;
3935
3936         std::vector< std::list<SendableMedia> > file_bunches;
3937         file_bunches.push_back(std::list<SendableMedia>());
3938
3939         u32 file_size_bunch_total = 0;
3940
3941         for(std::list<std::string>::const_iterator i = tosend.begin();
3942                         i != tosend.end(); ++i)
3943         {
3944                 const std::string &name = *i;
3945
3946                 if(m_media.find(name) == m_media.end()){
3947                         errorstream<<"Server::sendRequestedMedia(): Client asked for "
3948                                         <<"unknown file \""<<(name)<<"\""<<std::endl;
3949                         continue;
3950                 }
3951
3952                 //TODO get path + name
3953                 std::string tpath = m_media[name].path;
3954
3955                 // Read data
3956                 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3957                 if(fis.good() == false){
3958                         errorstream<<"Server::sendRequestedMedia(): Could not open \""
3959                                         <<tpath<<"\" for reading"<<std::endl;
3960                         continue;
3961                 }
3962                 std::ostringstream tmp_os(std::ios_base::binary);
3963                 bool bad = false;
3964                 for(;;){
3965                         char buf[1024];
3966                         fis.read(buf, 1024);
3967                         std::streamsize len = fis.gcount();
3968                         tmp_os.write(buf, len);
3969                         file_size_bunch_total += len;
3970                         if(fis.eof())
3971                                 break;
3972                         if(!fis.good()){
3973                                 bad = true;
3974                                 break;
3975                         }
3976                 }
3977                 if(bad){
3978                         errorstream<<"Server::sendRequestedMedia(): Failed to read \""
3979                                         <<name<<"\""<<std::endl;
3980                         continue;
3981                 }
3982                 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
3983                                 <<tname<<"\""<<std::endl;*/
3984                 // Put in list
3985                 file_bunches[file_bunches.size()-1].push_back(
3986                                 SendableMedia(name, tpath, tmp_os.str()));
3987
3988                 // Start next bunch if got enough data
3989                 if(file_size_bunch_total >= bytes_per_bunch){
3990                         file_bunches.push_back(std::list<SendableMedia>());
3991                         file_size_bunch_total = 0;
3992                 }
3993
3994         }
3995
3996         /* Create and send packets */
3997
3998         u32 num_bunches = file_bunches.size();
3999         for(u32 i=0; i<num_bunches; i++)
4000         {
4001                 std::ostringstream os(std::ios_base::binary);
4002
4003                 /*
4004                         u16 command
4005                         u16 total number of texture bunches
4006                         u16 index of this bunch
4007                         u32 number of files in this bunch
4008                         for each file {
4009                                 u16 length of name
4010                                 string name
4011                                 u32 length of data
4012                                 data
4013                         }
4014                 */
4015
4016                 writeU16(os, TOCLIENT_MEDIA);
4017                 writeU16(os, num_bunches);
4018                 writeU16(os, i);
4019                 writeU32(os, file_bunches[i].size());
4020
4021                 for(std::list<SendableMedia>::iterator
4022                                 j = file_bunches[i].begin();
4023                                 j != file_bunches[i].end(); ++j){
4024                         os<<serializeString(j->name);
4025                         os<<serializeLongString(j->data);
4026                 }
4027
4028                 // Make data buffer
4029                 std::string s = os.str();
4030                 verbosestream<<"Server::sendRequestedMedia(): bunch "
4031                                 <<i<<"/"<<num_bunches
4032                                 <<" files="<<file_bunches[i].size()
4033                                 <<" size=" <<s.size()<<std::endl;
4034                 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4035                 // Send as reliable
4036                 m_clients.send(peer_id, 2, data, true);
4037         }
4038 }
4039
4040 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4041 {
4042         if(m_detached_inventories.count(name) == 0){
4043                 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4044                 return;
4045         }
4046         Inventory *inv = m_detached_inventories[name];
4047
4048         std::ostringstream os(std::ios_base::binary);
4049         writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4050         os<<serializeString(name);
4051         inv->serialize(os);
4052
4053         // Make data buffer
4054         std::string s = os.str();
4055         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4056
4057         if (peer_id != PEER_ID_INEXISTENT)
4058         {
4059                 // Send as reliable
4060                 m_clients.send(peer_id, 0, data, true);
4061         }
4062         else
4063         {
4064                 m_clients.sendToAll(0,data,true);
4065         }
4066 }
4067
4068 void Server::sendDetachedInventories(u16 peer_id)
4069 {
4070         DSTACK(__FUNCTION_NAME);
4071
4072         for(std::map<std::string, Inventory*>::iterator
4073                         i = m_detached_inventories.begin();
4074                         i != m_detached_inventories.end(); i++){
4075                 const std::string &name = i->first;
4076                 //Inventory *inv = i->second;
4077                 sendDetachedInventory(name, peer_id);
4078         }
4079 }
4080
4081 /*
4082         Something random
4083 */
4084
4085 void Server::DiePlayer(u16 peer_id)
4086 {
4087         DSTACK(__FUNCTION_NAME);
4088
4089         PlayerSAO *playersao = getPlayerSAO(peer_id);
4090         assert(playersao);
4091
4092         infostream<<"Server::DiePlayer(): Player "
4093                         <<playersao->getPlayer()->getName()
4094                         <<" dies"<<std::endl;
4095
4096         playersao->setHP(0);
4097
4098         // Trigger scripted stuff
4099         m_script->on_dieplayer(playersao);
4100
4101         SendPlayerHP(peer_id);
4102         SendDeathscreen(peer_id, false, v3f(0,0,0));
4103 }
4104
4105 void Server::RespawnPlayer(u16 peer_id)
4106 {
4107         DSTACK(__FUNCTION_NAME);
4108
4109         PlayerSAO *playersao = getPlayerSAO(peer_id);
4110         assert(playersao);
4111
4112         infostream<<"Server::RespawnPlayer(): Player "
4113                         <<playersao->getPlayer()->getName()
4114                         <<" respawns"<<std::endl;
4115
4116         playersao->setHP(PLAYER_MAX_HP);
4117
4118         bool repositioned = m_script->on_respawnplayer(playersao);
4119         if(!repositioned){
4120                 v3f pos = findSpawnPos(m_env->getServerMap());
4121                 playersao->setPos(pos);
4122         }
4123 }
4124
4125 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4126 {
4127         DSTACK(__FUNCTION_NAME);
4128
4129         SendAccessDenied(peer_id, reason);
4130         m_clients.event(peer_id,SetDenied);
4131         m_con.DisconnectPeer(peer_id);
4132 }
4133
4134 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4135 {
4136         DSTACK(__FUNCTION_NAME);
4137         std::wstring message;
4138         {
4139                 /*
4140                         Clear references to playing sounds
4141                 */
4142                 for(std::map<s32, ServerPlayingSound>::iterator
4143                                 i = m_playing_sounds.begin();
4144                                 i != m_playing_sounds.end();)
4145                 {
4146                         ServerPlayingSound &psound = i->second;
4147                         psound.clients.erase(peer_id);
4148                         if(psound.clients.size() == 0)
4149                                 m_playing_sounds.erase(i++);
4150                         else
4151                                 i++;
4152                 }
4153
4154                 Player *player = m_env->getPlayer(peer_id);
4155
4156                 // Collect information about leaving in chat
4157                 {
4158                         if(player != NULL && reason != CDR_DENY)
4159                         {
4160                                 std::wstring name = narrow_to_wide(player->getName());
4161                                 message += L"*** ";
4162                                 message += name;
4163                                 message += L" left the game.";
4164                                 if(reason == CDR_TIMEOUT)
4165                                         message += L" (timed out)";
4166                         }
4167                 }
4168
4169                 /* Run scripts and remove from environment */
4170                 {
4171                         if(player != NULL)
4172                         {
4173                                 PlayerSAO *playersao = player->getPlayerSAO();
4174                                 assert(playersao);
4175
4176                                 m_script->on_leaveplayer(playersao);
4177
4178                                 playersao->disconnected();
4179                         }
4180                 }
4181
4182                 /*
4183                         Print out action
4184                 */
4185                 {
4186                         if(player != NULL && reason != CDR_DENY)
4187                         {
4188                                 std::ostringstream os(std::ios_base::binary);
4189                                 std::list<u16> clients = m_clients.getClientIDs();
4190
4191                                 for(std::list<u16>::iterator
4192                                         i = clients.begin();
4193                                         i != clients.end(); ++i)
4194                                 {
4195                                         // Get player
4196                                         Player *player = m_env->getPlayer(*i);
4197                                         if(!player)
4198                                                 continue;
4199                                         // Get name of player
4200                                         os<<player->getName()<<" ";
4201                                 }
4202
4203                                 actionstream<<player->getName()<<" "
4204                                                 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4205                                                 <<" List of players: "<<os.str()<<std::endl;
4206                         }
4207                 }
4208                 m_env_mutex.Lock();
4209                 m_clients.DeleteClient(peer_id);
4210                 m_env_mutex.Unlock();
4211         }
4212
4213         // Send leave chat message to all remaining clients
4214         if(message.length() != 0)
4215                 SendChatMessage(PEER_ID_INEXISTENT,message);
4216 }
4217
4218 void Server::UpdateCrafting(u16 peer_id)
4219 {
4220         DSTACK(__FUNCTION_NAME);
4221
4222         Player* player = m_env->getPlayer(peer_id);
4223         assert(player);
4224
4225         // Get a preview for crafting
4226         ItemStack preview;
4227         InventoryLocation loc;
4228         loc.setPlayer(player->getName());
4229         getCraftingResult(&player->inventory, preview, false, this);
4230         m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4231
4232         // Put the new preview in
4233         InventoryList *plist = player->inventory.getList("craftpreview");
4234         assert(plist);
4235         assert(plist->getSize() >= 1);
4236         plist->changeItem(0, preview);
4237 }
4238
4239 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4240 {
4241         RemoteClient *client = getClientNoEx(peer_id,state_min);
4242         if(!client)
4243                 throw ClientNotFoundException("Client not found");
4244
4245         return client;
4246 }
4247 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4248 {
4249         return m_clients.getClientNoEx(peer_id, state_min);
4250 }
4251
4252 std::string Server::getPlayerName(u16 peer_id)
4253 {
4254         Player *player = m_env->getPlayer(peer_id);
4255         if(player == NULL)
4256                 return "[id="+itos(peer_id)+"]";
4257         return player->getName();
4258 }
4259
4260 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4261 {
4262         Player *player = m_env->getPlayer(peer_id);
4263         if(player == NULL)
4264                 return NULL;
4265         return player->getPlayerSAO();
4266 }
4267
4268 std::wstring Server::getStatusString()
4269 {
4270         std::wostringstream os(std::ios_base::binary);
4271         os<<L"# Server: ";
4272         // Version
4273         os<<L"version="<<narrow_to_wide(minetest_version_simple);
4274         // Uptime
4275         os<<L", uptime="<<m_uptime.get();
4276         // Max lag estimate
4277         os<<L", max_lag="<<m_env->getMaxLagEstimate();
4278         // Information about clients
4279         bool first = true;
4280         os<<L", clients={";
4281         std::list<u16> clients = m_clients.getClientIDs();
4282         for(std::list<u16>::iterator i = clients.begin();
4283                 i != clients.end(); ++i)
4284         {
4285                 // Get player
4286                 Player *player = m_env->getPlayer(*i);
4287                 // Get name of player
4288                 std::wstring name = L"unknown";
4289                 if(player != NULL)
4290                         name = narrow_to_wide(player->getName());
4291                 // Add name to information string
4292                 if(!first)
4293                         os<<L",";
4294                 else
4295                         first = false;
4296                 os<<name;
4297         }
4298         os<<L"}";
4299         if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4300                 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4301         if(g_settings->get("motd") != "")
4302                 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4303         return os.str();
4304 }
4305
4306 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4307 {
4308         std::set<std::string> privs;
4309         m_script->getAuth(name, NULL, &privs);
4310         return privs;
4311 }
4312
4313 bool Server::checkPriv(const std::string &name, const std::string &priv)
4314 {
4315         std::set<std::string> privs = getPlayerEffectivePrivs(name);
4316         return (privs.count(priv) != 0);
4317 }
4318
4319 void Server::reportPrivsModified(const std::string &name)
4320 {
4321         if(name == ""){
4322                 std::list<u16> clients = m_clients.getClientIDs();
4323                 for(std::list<u16>::iterator
4324                                 i = clients.begin();
4325                                 i != clients.end(); ++i){
4326                         Player *player = m_env->getPlayer(*i);
4327                         reportPrivsModified(player->getName());
4328                 }
4329         } else {
4330                 Player *player = m_env->getPlayer(name.c_str());
4331                 if(!player)
4332                         return;
4333                 SendPlayerPrivileges(player->peer_id);
4334                 PlayerSAO *sao = player->getPlayerSAO();
4335                 if(!sao)
4336                         return;
4337                 sao->updatePrivileges(
4338                                 getPlayerEffectivePrivs(name),
4339                                 isSingleplayer());
4340         }
4341 }
4342
4343 void Server::reportInventoryFormspecModified(const std::string &name)
4344 {
4345         Player *player = m_env->getPlayer(name.c_str());
4346         if(!player)
4347                 return;
4348         SendPlayerInventoryFormspec(player->peer_id);
4349 }
4350
4351 void Server::setIpBanned(const std::string &ip, const std::string &name)
4352 {
4353         m_banmanager->add(ip, name);
4354 }
4355
4356 void Server::unsetIpBanned(const std::string &ip_or_name)
4357 {
4358         m_banmanager->remove(ip_or_name);
4359 }
4360
4361 std::string Server::getBanDescription(const std::string &ip_or_name)
4362 {
4363         return m_banmanager->getBanDescription(ip_or_name);
4364 }
4365
4366 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4367 {
4368         Player *player = m_env->getPlayer(name);
4369         if(!player)
4370                 return;
4371         if (prepend)
4372                 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4373         else
4374                 SendChatMessage(player->peer_id, msg);
4375 }
4376
4377 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4378 {
4379         Player *player = m_env->getPlayer(playername);
4380
4381         if(!player)
4382         {
4383                 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4384                 return false;
4385         }
4386
4387         SendShowFormspecMessage(player->peer_id, formspec, formname);
4388         return true;
4389 }
4390
4391 u32 Server::hudAdd(Player *player, HudElement *form) {
4392         if (!player)
4393                 return -1;
4394
4395         u32 id = player->getFreeHudID();
4396         if (id < player->hud.size())
4397                 player->hud[id] = form;
4398         else
4399                 player->hud.push_back(form);
4400         
4401         SendHUDAdd(player->peer_id, id, form);
4402         return id;
4403 }
4404
4405 bool Server::hudRemove(Player *player, u32 id) {
4406         if (!player || id >= player->hud.size() || !player->hud[id])
4407                 return false;
4408
4409         delete player->hud[id];
4410         player->hud[id] = NULL;
4411         
4412         SendHUDRemove(player->peer_id, id);
4413         return true;
4414 }
4415
4416 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4417         if (!player)
4418                 return false;
4419
4420         SendHUDChange(player->peer_id, id, stat, data);
4421         return true;
4422 }
4423
4424 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4425         if (!player)
4426                 return false;
4427
4428         SendHUDSetFlags(player->peer_id, flags, mask);
4429         return true;
4430 }
4431
4432 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4433         if (!player)
4434                 return false;
4435         if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4436                 return false;
4437
4438         std::ostringstream os(std::ios::binary);
4439         writeS32(os, hotbar_itemcount);
4440         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4441         return true;
4442 }
4443
4444 void Server::hudSetHotbarImage(Player *player, std::string name) {
4445         if (!player)
4446                 return;
4447
4448         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4449 }
4450
4451 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4452         if (!player)
4453                 return;
4454
4455         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4456 }
4457
4458 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4459                 const std::string &type, const std::vector<std::string> &params)
4460 {
4461         if (!player)
4462                 return false;
4463
4464         SendSetSky(player->peer_id, bgcolor, type, params);
4465         return true;
4466 }
4467
4468 void Server::notifyPlayers(const std::wstring msg)
4469 {
4470         SendChatMessage(PEER_ID_INEXISTENT,msg);
4471 }
4472
4473 void Server::spawnParticle(const char *playername, v3f pos,
4474                 v3f velocity, v3f acceleration,
4475                 float expirationtime, float size, bool
4476                 collisiondetection, bool vertical, std::string texture)
4477 {
4478         Player *player = m_env->getPlayer(playername);
4479         if(!player)
4480                 return;
4481         SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4482                         expirationtime, size, collisiondetection, vertical, texture);
4483 }
4484
4485 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4486                 float expirationtime, float size,
4487                 bool collisiondetection, bool vertical, std::string texture)
4488 {
4489         SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4490                         expirationtime, size, collisiondetection, vertical, texture);
4491 }
4492
4493 u32 Server::addParticleSpawner(const char *playername,
4494                 u16 amount, float spawntime,
4495                 v3f minpos, v3f maxpos,
4496                 v3f minvel, v3f maxvel,
4497                 v3f minacc, v3f maxacc,
4498                 float minexptime, float maxexptime,
4499                 float minsize, float maxsize,
4500                 bool collisiondetection, bool vertical, std::string texture)
4501 {
4502         Player *player = m_env->getPlayer(playername);
4503         if(!player)
4504                 return -1;
4505
4506         u32 id = 0;
4507         for(;;) // look for unused particlespawner id
4508         {
4509                 id++;
4510                 if (std::find(m_particlespawner_ids.begin(),
4511                                 m_particlespawner_ids.end(), id)
4512                                 == m_particlespawner_ids.end())
4513                 {
4514                         m_particlespawner_ids.push_back(id);
4515                         break;
4516                 }
4517         }
4518
4519         SendAddParticleSpawner(player->peer_id, amount, spawntime,
4520                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4521                 minexptime, maxexptime, minsize, maxsize,
4522                 collisiondetection, vertical, texture, id);
4523
4524         return id;
4525 }
4526
4527 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4528                 v3f minpos, v3f maxpos,
4529                 v3f minvel, v3f maxvel,
4530                 v3f minacc, v3f maxacc,
4531                 float minexptime, float maxexptime,
4532                 float minsize, float maxsize,
4533                 bool collisiondetection, bool vertical, std::string texture)
4534 {
4535         u32 id = 0;
4536         for(;;) // look for unused particlespawner id
4537         {
4538                 id++;
4539                 if (std::find(m_particlespawner_ids.begin(),
4540                                 m_particlespawner_ids.end(), id)
4541                                 == m_particlespawner_ids.end())
4542                 {
4543                         m_particlespawner_ids.push_back(id);
4544                         break;
4545                 }
4546         }
4547
4548         SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4549                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4550                 minexptime, maxexptime, minsize, maxsize,
4551                 collisiondetection, vertical, texture, id);
4552
4553         return id;
4554 }
4555
4556 void Server::deleteParticleSpawner(const char *playername, u32 id)
4557 {
4558         Player *player = m_env->getPlayer(playername);
4559         if(!player)
4560                 return;
4561
4562         m_particlespawner_ids.erase(
4563                         std::remove(m_particlespawner_ids.begin(),
4564                         m_particlespawner_ids.end(), id),
4565                         m_particlespawner_ids.end());
4566         SendDeleteParticleSpawner(player->peer_id, id);
4567 }
4568
4569 void Server::deleteParticleSpawnerAll(u32 id)
4570 {
4571         m_particlespawner_ids.erase(
4572                         std::remove(m_particlespawner_ids.begin(),
4573                         m_particlespawner_ids.end(), id),
4574                         m_particlespawner_ids.end());
4575         SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4576 }
4577
4578 Inventory* Server::createDetachedInventory(const std::string &name)
4579 {
4580         if(m_detached_inventories.count(name) > 0){
4581                 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4582                 delete m_detached_inventories[name];
4583         } else {
4584                 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4585         }
4586         Inventory *inv = new Inventory(m_itemdef);
4587         assert(inv);
4588         m_detached_inventories[name] = inv;
4589         //TODO find a better way to do this
4590         sendDetachedInventory(name,PEER_ID_INEXISTENT);
4591         return inv;
4592 }
4593
4594 class BoolScopeSet
4595 {
4596 public:
4597         BoolScopeSet(bool *dst, bool val):
4598                 m_dst(dst)
4599         {
4600                 m_orig_state = *m_dst;
4601                 *m_dst = val;
4602         }
4603         ~BoolScopeSet()
4604         {
4605                 *m_dst = m_orig_state;
4606         }
4607 private:
4608         bool *m_dst;
4609         bool m_orig_state;
4610 };
4611
4612 // actions: time-reversed list
4613 // Return value: success/failure
4614 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4615                 std::list<std::string> *log)
4616 {
4617         infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4618         ServerMap *map = (ServerMap*)(&m_env->getMap());
4619         // Disable rollback report sink while reverting
4620         BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4621
4622         // Fail if no actions to handle
4623         if(actions.empty()){
4624                 log->push_back("Nothing to do.");
4625                 return false;
4626         }
4627
4628         int num_tried = 0;
4629         int num_failed = 0;
4630
4631         for(std::list<RollbackAction>::const_iterator
4632                         i = actions.begin();
4633                         i != actions.end(); i++)
4634         {
4635                 const RollbackAction &action = *i;
4636                 num_tried++;
4637                 bool success = action.applyRevert(map, this, this);
4638                 if(!success){
4639                         num_failed++;
4640                         std::ostringstream os;
4641                         os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4642                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4643                         if(log)
4644                                 log->push_back(os.str());
4645                 }else{
4646                         std::ostringstream os;
4647                         os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4648                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4649                         if(log)
4650                                 log->push_back(os.str());
4651                 }
4652         }
4653
4654         infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4655                         <<" failed"<<std::endl;
4656
4657         // Call it done if less than half failed
4658         return num_failed <= num_tried/2;
4659 }
4660
4661 // IGameDef interface
4662 // Under envlock
4663 IItemDefManager* Server::getItemDefManager()
4664 {
4665         return m_itemdef;
4666 }
4667 INodeDefManager* Server::getNodeDefManager()
4668 {
4669         return m_nodedef;
4670 }
4671 ICraftDefManager* Server::getCraftDefManager()
4672 {
4673         return m_craftdef;
4674 }
4675 ITextureSource* Server::getTextureSource()
4676 {
4677         return NULL;
4678 }
4679 IShaderSource* Server::getShaderSource()
4680 {
4681         return NULL;
4682 }
4683 u16 Server::allocateUnknownNodeId(const std::string &name)
4684 {
4685         return m_nodedef->allocateDummy(name);
4686 }
4687 ISoundManager* Server::getSoundManager()
4688 {
4689         return &dummySoundManager;
4690 }
4691 MtEventManager* Server::getEventManager()
4692 {
4693         return m_event;
4694 }
4695 IRollbackReportSink* Server::getRollbackReportSink()
4696 {
4697         if(!m_enable_rollback_recording)
4698                 return NULL;
4699         if(!m_rollback_sink_enabled)
4700                 return NULL;
4701         return m_rollback;
4702 }
4703
4704 IWritableItemDefManager* Server::getWritableItemDefManager()
4705 {
4706         return m_itemdef;
4707 }
4708 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4709 {
4710         return m_nodedef;
4711 }
4712 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4713 {
4714         return m_craftdef;
4715 }
4716
4717 const ModSpec* Server::getModSpec(const std::string &modname)
4718 {
4719         for(std::vector<ModSpec>::iterator i = m_mods.begin();
4720                         i != m_mods.end(); i++){
4721                 const ModSpec &mod = *i;
4722                 if(mod.name == modname)
4723                         return &mod;
4724         }
4725         return NULL;
4726 }
4727 void Server::getModNames(std::list<std::string> &modlist)
4728 {
4729         for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4730         {
4731                 modlist.push_back(i->name);
4732         }
4733 }
4734 std::string Server::getBuiltinLuaPath()
4735 {
4736         return porting::path_share + DIR_DELIM + "builtin";
4737 }
4738
4739 v3f findSpawnPos(ServerMap &map)
4740 {
4741         //return v3f(50,50,50)*BS;
4742
4743         v3s16 nodepos;
4744
4745 #if 0
4746         nodepos = v2s16(0,0);
4747         groundheight = 20;
4748 #endif
4749
4750 #if 1
4751         s16 water_level = map.m_mgparams->water_level;
4752
4753         // Try to find a good place a few times
4754         for(s32 i=0; i<1000; i++)
4755         {
4756                 s32 range = 1 + i;
4757                 // We're going to try to throw the player to this position
4758                 v2s16 nodepos2d = v2s16(
4759                                 -range + (myrand() % (range * 2)),
4760                                 -range + (myrand() % (range * 2)));
4761
4762                 // Get ground height at point
4763                 s16 groundheight = map.findGroundLevel(nodepos2d);
4764                 if (groundheight <= water_level) // Don't go underwater
4765                         continue;
4766                 if (groundheight > water_level + 6) // Don't go to high places
4767                         continue;
4768
4769                 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4770                 bool is_good = false;
4771                 s32 air_count = 0;
4772                 for (s32 i = 0; i < 10; i++) {
4773                         v3s16 blockpos = getNodeBlockPos(nodepos);
4774                         map.emergeBlock(blockpos, true);
4775                         content_t c = map.getNodeNoEx(nodepos).getContent();
4776                         if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4777                                 air_count++;
4778                                 if (air_count >= 2){
4779                                         is_good = true;
4780                                         break;
4781                                 }
4782                         }
4783                         nodepos.Y++;
4784                 }
4785                 if(is_good){
4786                         // Found a good place
4787                         //infostream<<"Searched through "<<i<<" places."<<std::endl;
4788                         break;
4789                 }
4790         }
4791 #endif
4792
4793         return intToFloat(nodepos, BS);
4794 }
4795
4796 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4797 {
4798         RemotePlayer *player = NULL;
4799         bool newplayer = false;
4800
4801         /*
4802                 Try to get an existing player
4803         */
4804         player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4805
4806         // If player is already connected, cancel
4807         if(player != NULL && player->peer_id != 0)
4808         {
4809                 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4810                 return NULL;
4811         }
4812
4813         /*
4814                 If player with the wanted peer_id already exists, cancel.
4815         */
4816         if(m_env->getPlayer(peer_id) != NULL)
4817         {
4818                 infostream<<"emergePlayer(): Player with wrong name but same"
4819                                 " peer_id already exists"<<std::endl;
4820                 return NULL;
4821         }
4822
4823         /*
4824                 Create a new player if it doesn't exist yet
4825         */
4826         if(player == NULL)
4827         {
4828                 newplayer = true;
4829                 player = new RemotePlayer(this);
4830                 player->updateName(name);
4831
4832                 /* Set player position */
4833                 infostream<<"Server: Finding spawn place for player \""
4834                                 <<name<<"\""<<std::endl;
4835                 v3f pos = findSpawnPos(m_env->getServerMap());
4836                 player->setPosition(pos);
4837
4838                 /* Add player to environment */
4839                 m_env->addPlayer(player);
4840         }
4841
4842         /*
4843                 Create a new player active object
4844         */
4845         PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4846                         getPlayerEffectivePrivs(player->getName()),
4847                         isSingleplayer());
4848
4849         /* Clean up old HUD elements from previous sessions */
4850         player->hud.clear();
4851
4852         /* Add object to environment */
4853         m_env->addActiveObject(playersao);
4854
4855         /* Run scripts */
4856         if(newplayer)
4857                 m_script->on_newplayer(playersao);
4858
4859         return playersao;
4860 }
4861
4862 void dedicated_server_loop(Server &server, bool &kill)
4863 {
4864         DSTACK(__FUNCTION_NAME);
4865
4866         verbosestream<<"dedicated_server_loop()"<<std::endl;
4867
4868         IntervalLimiter m_profiler_interval;
4869
4870         for(;;)
4871         {
4872                 float steplen = g_settings->getFloat("dedicated_server_step");
4873                 // This is kind of a hack but can be done like this
4874                 // because server.step() is very light
4875                 {
4876                         ScopeProfiler sp(g_profiler, "dedicated server sleep");
4877                         sleep_ms((int)(steplen*1000.0));
4878                 }
4879                 server.step(steplen);
4880
4881                 if(server.getShutdownRequested() || kill)
4882                 {
4883                         infostream<<"Dedicated server quitting"<<std::endl;
4884 #if USE_CURL
4885                         if(g_settings->getBool("server_announce") == true)
4886                                 ServerList::sendAnnounce("delete");
4887 #endif
4888                         break;
4889                 }
4890
4891                 /*
4892                         Profiler
4893                 */
4894                 float profiler_print_interval =
4895                                 g_settings->getFloat("profiler_print_interval");
4896                 if(profiler_print_interval != 0)
4897                 {
4898                         if(m_profiler_interval.step(steplen, profiler_print_interval))
4899                         {
4900                                 infostream<<"Profiler:"<<std::endl;
4901                                 g_profiler->print(infostream);
4902                                 g_profiler->clear();
4903                         }
4904                 }
4905         }
4906 }
4907
4908