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