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