]> git.lizzy.rs Git - dragonfireclient.git/blob - src/server.cpp
Remove most exceptions from getNode() (and variants)
[dragonfireclient.git] / src / server.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "server.h"
21 #include <iostream>
22 #include <queue>
23 #include <algorithm>
24 #include "clientserver.h"
25 #include "ban.h"
26 #include "environment.h"
27 #include "map.h"
28 #include "jthread/jmutexautolock.h"
29 #include "main.h"
30 #include "constants.h"
31 #include "voxel.h"
32 #include "config.h"
33 #include "version.h"
34 #include "filesys.h"
35 #include "mapblock.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
38 #include "settings.h"
39 #include "profiler.h"
40 #include "log.h"
41 #include "scripting_game.h"
42 #include "nodedef.h"
43 #include "itemdef.h"
44 #include "craftdef.h"
45 #include "emerge.h"
46 #include "mapgen.h"
47 #include "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                                 bool pos_ok;
2428                                 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2429                                 if (pos_ok)
2430                                         n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2431
2432                                 if (!pos_ok) {
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
2439                                 if(n.getContent() != CONTENT_IGNORE)
2440                                         m_script->node_on_punch(p_under, n, playersao, pointed);
2441                                 // Cheat prevention
2442                                 playersao->noCheatDigStart(p_under);
2443                         }
2444                         else if(pointed.type == POINTEDTHING_OBJECT)
2445                         {
2446                                 // Skip if object has been removed
2447                                 if(pointed_object->m_removed)
2448                                         return;
2449
2450                                 actionstream<<player->getName()<<" punches object "
2451                                                 <<pointed.object_id<<": "
2452                                                 <<pointed_object->getDescription()<<std::endl;
2453
2454                                 ItemStack punchitem = playersao->getWieldedItem();
2455                                 ToolCapabilities toolcap =
2456                                                 punchitem.getToolCapabilities(m_itemdef);
2457                                 v3f dir = (pointed_object->getBasePosition() -
2458                                                 (player->getPosition() + player->getEyeOffset())
2459                                                         ).normalize();
2460                                 float time_from_last_punch =
2461                                         playersao->resetTimeFromLastPunch();
2462                                 pointed_object->punch(dir, &toolcap, playersao,
2463                                                 time_from_last_punch);
2464                         }
2465
2466                 } // action == 0
2467
2468                 /*
2469                         1: stop digging
2470                 */
2471                 else if(action == 1)
2472                 {
2473                 } // action == 1
2474
2475                 /*
2476                         2: Digging completed
2477                 */
2478                 else if(action == 2)
2479                 {
2480                         // Only digging of nodes
2481                         if(pointed.type == POINTEDTHING_NODE)
2482                         {
2483                                 bool pos_ok;
2484                                 MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2485                                 if (!pos_ok) {
2486                                         infostream << "Server: Not finishing digging: Node not found."
2487                                                    << " Adding block to emerge queue."
2488                                                    << std::endl;
2489                                         m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2490                                 }
2491
2492                                 /* Cheat prevention */
2493                                 bool is_valid_dig = true;
2494                                 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2495                                 {
2496                                         v3s16 nocheat_p = playersao->getNoCheatDigPos();
2497                                         float nocheat_t = playersao->getNoCheatDigTime();
2498                                         playersao->noCheatDigEnd();
2499                                         // If player didn't start digging this, ignore dig
2500                                         if(nocheat_p != p_under){
2501                                                 infostream<<"Server: NoCheat: "<<player->getName()
2502                                                                 <<" started digging "
2503                                                                 <<PP(nocheat_p)<<" and completed digging "
2504                                                                 <<PP(p_under)<<"; not digging."<<std::endl;
2505                                                 is_valid_dig = false;
2506                                                 // Call callbacks
2507                                                 m_script->on_cheat(playersao, "finished_unknown_dig");
2508                                         }
2509                                         // Get player's wielded item
2510                                         ItemStack playeritem;
2511                                         InventoryList *mlist = playersao->getInventory()->getList("main");
2512                                         if(mlist != NULL)
2513                                                 playeritem = mlist->getItem(playersao->getWieldIndex());
2514                                         ToolCapabilities playeritem_toolcap =
2515                                                         playeritem.getToolCapabilities(m_itemdef);
2516                                         // Get diggability and expected digging time
2517                                         DigParams params = getDigParams(m_nodedef->get(n).groups,
2518                                                         &playeritem_toolcap);
2519                                         // If can't dig, try hand
2520                                         if(!params.diggable){
2521                                                 const ItemDefinition &hand = m_itemdef->get("");
2522                                                 const ToolCapabilities *tp = hand.tool_capabilities;
2523                                                 if(tp)
2524                                                         params = getDigParams(m_nodedef->get(n).groups, tp);
2525                                         }
2526                                         // If can't dig, ignore dig
2527                                         if(!params.diggable){
2528                                                 infostream<<"Server: NoCheat: "<<player->getName()
2529                                                                 <<" completed digging "<<PP(p_under)
2530                                                                 <<", which is not diggable with tool. not digging."
2531                                                                 <<std::endl;
2532                                                 is_valid_dig = false;
2533                                                 // Call callbacks
2534                                                 m_script->on_cheat(playersao, "dug_unbreakable");
2535                                         }
2536                                         // Check digging time
2537                                         // If already invalidated, we don't have to
2538                                         if(!is_valid_dig){
2539                                                 // Well not our problem then
2540                                         }
2541                                         // Clean and long dig
2542                                         else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2543                                                 // All is good, but grab time from pool; don't care if
2544                                                 // it's actually available
2545                                                 playersao->getDigPool().grab(params.time);
2546                                         }
2547                                         // Short or laggy dig
2548                                         // Try getting the time from pool
2549                                         else if(playersao->getDigPool().grab(params.time)){
2550                                                 // All is good
2551                                         }
2552                                         // Dig not possible
2553                                         else{
2554                                                 infostream<<"Server: NoCheat: "<<player->getName()
2555                                                                 <<" completed digging "<<PP(p_under)
2556                                                                 <<"too fast; not digging."<<std::endl;
2557                                                 is_valid_dig = false;
2558                                                 // Call callbacks
2559                                                 m_script->on_cheat(playersao, "dug_too_fast");
2560                                         }
2561                                 }
2562
2563                                 /* Actually dig node */
2564
2565                                 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2566                                         m_script->node_on_dig(p_under, n, playersao);
2567
2568                                 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2569                                 RemoteClient *client = getClient(peer_id);
2570                                 // Send unusual result (that is, node not being removed)
2571                                 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2572                                 {
2573                                         // Re-send block to revert change on client-side
2574                                         client->SetBlockNotSent(blockpos);
2575                                 }
2576                                 else {
2577                                         client->ResendBlockIfOnWire(blockpos);
2578                                 }
2579                         }
2580                 } // action == 2
2581
2582                 /*
2583                         3: place block or right-click object
2584                 */
2585                 else if(action == 3)
2586                 {
2587                         ItemStack item = playersao->getWieldedItem();
2588
2589                         // Reset build time counter
2590                         if(pointed.type == POINTEDTHING_NODE &&
2591                                         item.getDefinition(m_itemdef).type == ITEM_NODE)
2592                                 getClient(peer_id)->m_time_from_building = 0.0;
2593
2594                         if(pointed.type == POINTEDTHING_OBJECT)
2595                         {
2596                                 // Right click object
2597
2598                                 // Skip if object has been removed
2599                                 if(pointed_object->m_removed)
2600                                         return;
2601
2602                                 actionstream<<player->getName()<<" right-clicks object "
2603                                                 <<pointed.object_id<<": "
2604                                                 <<pointed_object->getDescription()<<std::endl;
2605
2606                                 // Do stuff
2607                                 pointed_object->rightClick(playersao);
2608                         }
2609                         else if(m_script->item_OnPlace(
2610                                         item, playersao, pointed))
2611                         {
2612                                 // Placement was handled in lua
2613
2614                                 // Apply returned ItemStack
2615                                 playersao->setWieldedItem(item);
2616                         }
2617
2618                         // If item has node placement prediction, always send the
2619                         // blocks to make sure the client knows what exactly happened
2620                         RemoteClient *client = getClient(peer_id);
2621                         v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2622                         v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2623                         if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
2624                                 client->SetBlockNotSent(blockpos);
2625                                 if(blockpos2 != blockpos) {
2626                                         client->SetBlockNotSent(blockpos2);
2627                                 }
2628                         }
2629                         else {
2630                                 client->ResendBlockIfOnWire(blockpos);
2631                                 if(blockpos2 != blockpos) {
2632                                         client->ResendBlockIfOnWire(blockpos2);
2633                                 }
2634                         }
2635                 } // action == 3
2636
2637                 /*
2638                         4: use
2639                 */
2640                 else if(action == 4)
2641                 {
2642                         ItemStack item = playersao->getWieldedItem();
2643
2644                         actionstream<<player->getName()<<" uses "<<item.name
2645                                         <<", pointing at "<<pointed.dump()<<std::endl;
2646
2647                         if(m_script->item_OnUse(
2648                                         item, playersao, pointed))
2649                         {
2650                                 // Apply returned ItemStack
2651                                 playersao->setWieldedItem(item);
2652                         }
2653
2654                 } // action == 4
2655                 
2656
2657                 /*
2658                         Catch invalid actions
2659                 */
2660                 else
2661                 {
2662                         infostream<<"WARNING: Server: Invalid action "
2663                                         <<action<<std::endl;
2664                 }
2665         }
2666         else if(command == TOSERVER_REMOVED_SOUNDS)
2667         {
2668                 std::string datastring((char*)&data[2], datasize-2);
2669                 std::istringstream is(datastring, std::ios_base::binary);
2670
2671                 int num = readU16(is);
2672                 for(int k=0; k<num; k++){
2673                         s32 id = readS32(is);
2674                         std::map<s32, ServerPlayingSound>::iterator i =
2675                                         m_playing_sounds.find(id);
2676                         if(i == m_playing_sounds.end())
2677                                 continue;
2678                         ServerPlayingSound &psound = i->second;
2679                         psound.clients.erase(peer_id);
2680                         if(psound.clients.size() == 0)
2681                                 m_playing_sounds.erase(i++);
2682                 }
2683         }
2684         else if(command == TOSERVER_NODEMETA_FIELDS)
2685         {
2686                 std::string datastring((char*)&data[2], datasize-2);
2687                 std::istringstream is(datastring, std::ios_base::binary);
2688
2689                 v3s16 p = readV3S16(is);
2690                 std::string formname = deSerializeString(is);
2691                 int num = readU16(is);
2692                 std::map<std::string, std::string> fields;
2693                 for(int k=0; k<num; k++){
2694                         std::string fieldname = deSerializeString(is);
2695                         std::string fieldvalue = deSerializeLongString(is);
2696                         fields[fieldname] = fieldvalue;
2697                 }
2698
2699                 // If something goes wrong, this player is to blame
2700                 RollbackScopeActor rollback_scope(m_rollback,
2701                                 std::string("player:")+player->getName());
2702
2703                 // Check the target node for rollback data; leave others unnoticed
2704                 RollbackNode rn_old(&m_env->getMap(), p, this);
2705
2706                 m_script->node_on_receive_fields(p, formname, fields,playersao);
2707
2708                 // Report rollback data
2709                 RollbackNode rn_new(&m_env->getMap(), p, this);
2710                 if(rollback() && rn_new != rn_old){
2711                         RollbackAction action;
2712                         action.setSetNode(p, rn_old, rn_new);
2713                         rollback()->reportAction(action);
2714                 }
2715         }
2716         else if(command == TOSERVER_INVENTORY_FIELDS)
2717         {
2718                 std::string datastring((char*)&data[2], datasize-2);
2719                 std::istringstream is(datastring, std::ios_base::binary);
2720
2721                 std::string formname = deSerializeString(is);
2722                 int num = readU16(is);
2723                 std::map<std::string, std::string> fields;
2724                 for(int k=0; k<num; k++){
2725                         std::string fieldname = deSerializeString(is);
2726                         std::string fieldvalue = deSerializeLongString(is);
2727                         fields[fieldname] = fieldvalue;
2728                 }
2729
2730                 m_script->on_playerReceiveFields(playersao, formname, fields);
2731         }
2732         else
2733         {
2734                 infostream<<"Server::ProcessData(): Ignoring "
2735                                 "unknown command "<<command<<std::endl;
2736         }
2737
2738         } //try
2739         catch(SendFailedException &e)
2740         {
2741                 errorstream<<"Server::ProcessData(): SendFailedException: "
2742                                 <<"what="<<e.what()
2743                                 <<std::endl;
2744         }
2745 }
2746
2747 void Server::setTimeOfDay(u32 time)
2748 {
2749         m_env->setTimeOfDay(time);
2750         m_time_of_day_send_timer = 0;
2751 }
2752
2753 void Server::onMapEditEvent(MapEditEvent *event)
2754 {
2755         //infostream<<"Server::onMapEditEvent()"<<std::endl;
2756         if(m_ignore_map_edit_events)
2757                 return;
2758         if(m_ignore_map_edit_events_area.contains(event->getArea()))
2759                 return;
2760         MapEditEvent *e = event->clone();
2761         m_unsent_map_edit_queue.push_back(e);
2762 }
2763
2764 Inventory* Server::getInventory(const InventoryLocation &loc)
2765 {
2766         switch(loc.type){
2767         case InventoryLocation::UNDEFINED:
2768         {}
2769         break;
2770         case InventoryLocation::CURRENT_PLAYER:
2771         {}
2772         break;
2773         case InventoryLocation::PLAYER:
2774         {
2775                 Player *player = m_env->getPlayer(loc.name.c_str());
2776                 if(!player)
2777                         return NULL;
2778                 PlayerSAO *playersao = player->getPlayerSAO();
2779                 if(!playersao)
2780                         return NULL;
2781                 return playersao->getInventory();
2782         }
2783         break;
2784         case InventoryLocation::NODEMETA:
2785         {
2786                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2787                 if(!meta)
2788                         return NULL;
2789                 return meta->getInventory();
2790         }
2791         break;
2792         case InventoryLocation::DETACHED:
2793         {
2794                 if(m_detached_inventories.count(loc.name) == 0)
2795                         return NULL;
2796                 return m_detached_inventories[loc.name];
2797         }
2798         break;
2799         default:
2800                 assert(0);
2801         }
2802         return NULL;
2803 }
2804 void Server::setInventoryModified(const InventoryLocation &loc)
2805 {
2806         switch(loc.type){
2807         case InventoryLocation::UNDEFINED:
2808         {}
2809         break;
2810         case InventoryLocation::PLAYER:
2811         {
2812                 Player *player = m_env->getPlayer(loc.name.c_str());
2813                 if(!player)
2814                         return;
2815                 PlayerSAO *playersao = player->getPlayerSAO();
2816                 if(!playersao)
2817                         return;
2818                 playersao->m_inventory_not_sent = true;
2819                 playersao->m_wielded_item_not_sent = true;
2820         }
2821         break;
2822         case InventoryLocation::NODEMETA:
2823         {
2824                 v3s16 blockpos = getNodeBlockPos(loc.p);
2825
2826                 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2827                 if(block)
2828                         block->raiseModified(MOD_STATE_WRITE_NEEDED);
2829
2830                 setBlockNotSent(blockpos);
2831         }
2832         break;
2833         case InventoryLocation::DETACHED:
2834         {
2835                 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2836         }
2837         break;
2838         default:
2839                 assert(0);
2840         }
2841 }
2842
2843 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2844 {
2845         std::list<u16> clients = m_clients.getClientIDs();
2846         m_clients.Lock();
2847         // Set the modified blocks unsent for all the clients
2848         for (std::list<u16>::iterator
2849                  i = clients.begin();
2850                  i != clients.end(); ++i) {
2851                         RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2852                         if (client != NULL)
2853                                 client->SetBlocksNotSent(block);
2854                 }
2855         m_clients.Unlock();
2856 }
2857
2858 void Server::peerAdded(con::Peer *peer)
2859 {
2860         DSTACK(__FUNCTION_NAME);
2861         verbosestream<<"Server::peerAdded(): peer->id="
2862                         <<peer->id<<std::endl;
2863
2864         con::PeerChange c;
2865         c.type = con::PEER_ADDED;
2866         c.peer_id = peer->id;
2867         c.timeout = false;
2868         m_peer_change_queue.push_back(c);
2869 }
2870
2871 void Server::deletingPeer(con::Peer *peer, bool timeout)
2872 {
2873         DSTACK(__FUNCTION_NAME);
2874         verbosestream<<"Server::deletingPeer(): peer->id="
2875                         <<peer->id<<", timeout="<<timeout<<std::endl;
2876
2877         m_clients.event(peer->id, CSE_Disconnect);
2878         con::PeerChange c;
2879         c.type = con::PEER_REMOVED;
2880         c.peer_id = peer->id;
2881         c.timeout = timeout;
2882         m_peer_change_queue.push_back(c);
2883 }
2884
2885 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2886 {
2887         *retval = m_con.getPeerStat(peer_id,type);
2888         if (*retval == -1) return false;
2889         return true;
2890 }
2891
2892 bool Server::getClientInfo(
2893                 u16          peer_id,
2894                 ClientState* state,
2895                 u32*         uptime,
2896                 u8*          ser_vers,
2897                 u16*         prot_vers,
2898                 u8*          major,
2899                 u8*          minor,
2900                 u8*          patch,
2901                 std::string* vers_string
2902         )
2903 {
2904         *state = m_clients.getClientState(peer_id);
2905         m_clients.Lock();
2906         RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2907
2908         if (client == NULL) {
2909                 m_clients.Unlock();
2910                 return false;
2911         }
2912
2913         *uptime = client->uptime();
2914         *ser_vers = client->serialization_version;
2915         *prot_vers = client->net_proto_version;
2916
2917         *major = client->getMajor();
2918         *minor = client->getMinor();
2919         *patch = client->getPatch();
2920         *vers_string = client->getPatch();
2921
2922         m_clients.Unlock();
2923
2924         return true;
2925 }
2926
2927 void Server::handlePeerChanges()
2928 {
2929         while(m_peer_change_queue.size() > 0)
2930         {
2931                 con::PeerChange c = m_peer_change_queue.pop_front();
2932
2933                 verbosestream<<"Server: Handling peer change: "
2934                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2935                                 <<std::endl;
2936
2937                 switch(c.type)
2938                 {
2939                 case con::PEER_ADDED:
2940                         m_clients.CreateClient(c.peer_id);
2941                         break;
2942
2943                 case con::PEER_REMOVED:
2944                         DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2945                         break;
2946
2947                 default:
2948                         assert("Invalid peer change event received!" == 0);
2949                         break;
2950                 }
2951         }
2952 }
2953
2954 void Server::SendMovement(u16 peer_id)
2955 {
2956         DSTACK(__FUNCTION_NAME);
2957         std::ostringstream os(std::ios_base::binary);
2958
2959         writeU16(os, TOCLIENT_MOVEMENT);
2960         writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2961         writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2962         writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2963         writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2964         writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2965         writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2966         writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2967         writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2968         writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2969         writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2970         writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2971         writeF1000(os, g_settings->getFloat("movement_gravity"));
2972
2973         // Make data buffer
2974         std::string s = os.str();
2975         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2976         // Send as reliable
2977         m_clients.send(peer_id, 0, data, true);
2978 }
2979
2980 void Server::SendHP(u16 peer_id, u8 hp)
2981 {
2982         DSTACK(__FUNCTION_NAME);
2983         std::ostringstream os(std::ios_base::binary);
2984
2985         writeU16(os, TOCLIENT_HP);
2986         writeU8(os, hp);
2987
2988         // Make data buffer
2989         std::string s = os.str();
2990         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2991         // Send as reliable
2992         m_clients.send(peer_id, 0, data, true);
2993 }
2994
2995 void Server::SendBreath(u16 peer_id, u16 breath)
2996 {
2997         DSTACK(__FUNCTION_NAME);
2998         std::ostringstream os(std::ios_base::binary);
2999
3000         writeU16(os, TOCLIENT_BREATH);
3001         writeU16(os, breath);
3002
3003         // Make data buffer
3004         std::string s = os.str();
3005         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3006         // Send as reliable
3007         m_clients.send(peer_id, 0, data, true);
3008 }
3009
3010 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3011 {
3012         DSTACK(__FUNCTION_NAME);
3013         std::ostringstream os(std::ios_base::binary);
3014
3015         writeU16(os, TOCLIENT_ACCESS_DENIED);
3016         os<<serializeWideString(reason);
3017
3018         // Make data buffer
3019         std::string s = os.str();
3020         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3021         // Send as reliable
3022         m_clients.send(peer_id, 0, data, true);
3023 }
3024
3025 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3026                 v3f camera_point_target)
3027 {
3028         DSTACK(__FUNCTION_NAME);
3029         std::ostringstream os(std::ios_base::binary);
3030
3031         writeU16(os, TOCLIENT_DEATHSCREEN);
3032         writeU8(os, set_camera_point_target);
3033         writeV3F1000(os, camera_point_target);
3034
3035         // Make data buffer
3036         std::string s = os.str();
3037         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3038         // Send as reliable
3039         m_clients.send(peer_id, 0, data, true);
3040 }
3041
3042 void Server::SendItemDef(u16 peer_id,
3043                 IItemDefManager *itemdef, u16 protocol_version)
3044 {
3045         DSTACK(__FUNCTION_NAME);
3046         std::ostringstream os(std::ios_base::binary);
3047
3048         /*
3049                 u16 command
3050                 u32 length of the next item
3051                 zlib-compressed serialized ItemDefManager
3052         */
3053         writeU16(os, TOCLIENT_ITEMDEF);
3054         std::ostringstream tmp_os(std::ios::binary);
3055         itemdef->serialize(tmp_os, protocol_version);
3056         std::ostringstream tmp_os2(std::ios::binary);
3057         compressZlib(tmp_os.str(), tmp_os2);
3058         os<<serializeLongString(tmp_os2.str());
3059
3060         // Make data buffer
3061         std::string s = os.str();
3062         verbosestream<<"Server: Sending item definitions to id("<<peer_id
3063                         <<"): size="<<s.size()<<std::endl;
3064         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3065         // Send as reliable
3066         m_clients.send(peer_id, 0, data, true);
3067 }
3068
3069 void Server::SendNodeDef(u16 peer_id,
3070                 INodeDefManager *nodedef, u16 protocol_version)
3071 {
3072         DSTACK(__FUNCTION_NAME);
3073         std::ostringstream os(std::ios_base::binary);
3074
3075         /*
3076                 u16 command
3077                 u32 length of the next item
3078                 zlib-compressed serialized NodeDefManager
3079         */
3080         writeU16(os, TOCLIENT_NODEDEF);
3081         std::ostringstream tmp_os(std::ios::binary);
3082         nodedef->serialize(tmp_os, protocol_version);
3083         std::ostringstream tmp_os2(std::ios::binary);
3084         compressZlib(tmp_os.str(), tmp_os2);
3085         os<<serializeLongString(tmp_os2.str());
3086
3087         // Make data buffer
3088         std::string s = os.str();
3089         verbosestream<<"Server: Sending node definitions to id("<<peer_id
3090                         <<"): size="<<s.size()<<std::endl;
3091         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3092         // Send as reliable
3093         m_clients.send(peer_id, 0, data, true);
3094 }
3095
3096 /*
3097         Non-static send methods
3098 */
3099
3100 void Server::SendInventory(u16 peer_id)
3101 {
3102         DSTACK(__FUNCTION_NAME);
3103
3104         PlayerSAO *playersao = getPlayerSAO(peer_id);
3105         assert(playersao);
3106
3107         playersao->m_inventory_not_sent = false;
3108
3109         /*
3110                 Serialize it
3111         */
3112
3113         std::ostringstream os;
3114         playersao->getInventory()->serialize(os);
3115
3116         std::string s = os.str();
3117
3118         SharedBuffer<u8> data(s.size()+2);
3119         writeU16(&data[0], TOCLIENT_INVENTORY);
3120         memcpy(&data[2], s.c_str(), s.size());
3121
3122         // Send as reliable
3123         m_clients.send(peer_id, 0, data, true);
3124 }
3125
3126 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3127 {
3128         DSTACK(__FUNCTION_NAME);
3129
3130         std::ostringstream os(std::ios_base::binary);
3131         u8 buf[12];
3132
3133         // Write command
3134         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3135         os.write((char*)buf, 2);
3136
3137         // Write length
3138         writeU16(buf, message.size());
3139         os.write((char*)buf, 2);
3140
3141         // Write string
3142         for(u32 i=0; i<message.size(); i++)
3143         {
3144                 u16 w = message[i];
3145                 writeU16(buf, w);
3146                 os.write((char*)buf, 2);
3147         }
3148
3149         // Make data buffer
3150         std::string s = os.str();
3151         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3152
3153         if (peer_id != PEER_ID_INEXISTENT)
3154         {
3155                 // Send as reliable
3156                 m_clients.send(peer_id, 0, data, true);
3157         }
3158         else
3159         {
3160                 m_clients.sendToAll(0,data,true);
3161         }
3162 }
3163
3164 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3165                                      const std::string &formname)
3166 {
3167         DSTACK(__FUNCTION_NAME);
3168
3169         std::ostringstream os(std::ios_base::binary);
3170         u8 buf[12];
3171
3172
3173         // Write command
3174         writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3175         os.write((char*)buf, 2);
3176         os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3177         os<<serializeString(formname);
3178
3179         // Make data buffer
3180         std::string s = os.str();
3181         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3182         // Send as reliable
3183         m_clients.send(peer_id, 0, data, true);
3184 }
3185
3186 // Spawns a particle on peer with peer_id
3187 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3188                                 float expirationtime, float size, bool collisiondetection,
3189                                 bool vertical, std::string texture)
3190 {
3191         DSTACK(__FUNCTION_NAME);
3192
3193         std::ostringstream os(std::ios_base::binary);
3194         writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3195         writeV3F1000(os, pos);
3196         writeV3F1000(os, velocity);
3197         writeV3F1000(os, acceleration);
3198         writeF1000(os, expirationtime);
3199         writeF1000(os, size);
3200         writeU8(os,  collisiondetection);
3201         os<<serializeLongString(texture);
3202         writeU8(os, vertical);
3203
3204         // Make data buffer
3205         std::string s = os.str();
3206         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3207
3208         if (peer_id != PEER_ID_INEXISTENT)
3209         {
3210         // Send as reliable
3211                 m_clients.send(peer_id, 0, data, true);
3212         }
3213         else
3214         {
3215                 m_clients.sendToAll(0,data,true);
3216         }
3217 }
3218
3219 // Adds a ParticleSpawner on peer with peer_id
3220 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3221         v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3222         float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3223 {
3224         DSTACK(__FUNCTION_NAME);
3225
3226         std::ostringstream os(std::ios_base::binary);
3227         writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3228
3229         writeU16(os, amount);
3230         writeF1000(os, spawntime);
3231         writeV3F1000(os, minpos);
3232         writeV3F1000(os, maxpos);
3233         writeV3F1000(os, minvel);
3234         writeV3F1000(os, maxvel);
3235         writeV3F1000(os, minacc);
3236         writeV3F1000(os, maxacc);
3237         writeF1000(os, minexptime);
3238         writeF1000(os, maxexptime);
3239         writeF1000(os, minsize);
3240         writeF1000(os, maxsize);
3241         writeU8(os,  collisiondetection);
3242         os<<serializeLongString(texture);
3243         writeU32(os, id);
3244         writeU8(os, vertical);
3245
3246         // Make data buffer
3247         std::string s = os.str();
3248         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3249
3250         if (peer_id != PEER_ID_INEXISTENT)
3251         {
3252                 // Send as reliable
3253                 m_clients.send(peer_id, 0, data, true);
3254         }
3255         else {
3256                 m_clients.sendToAll(0,data,true);
3257         }
3258 }
3259
3260 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3261 {
3262         DSTACK(__FUNCTION_NAME);
3263
3264         std::ostringstream os(std::ios_base::binary);
3265         writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3266
3267         writeU16(os, id);
3268
3269         // Make data buffer
3270         std::string s = os.str();
3271         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3272
3273         if (peer_id != PEER_ID_INEXISTENT) {
3274                 // Send as reliable
3275                 m_clients.send(peer_id, 0, data, true);
3276         }
3277         else {
3278                 m_clients.sendToAll(0,data,true);
3279         }
3280
3281 }
3282
3283 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3284 {
3285         std::ostringstream os(std::ios_base::binary);
3286
3287         // Write command
3288         writeU16(os, TOCLIENT_HUDADD);
3289         writeU32(os, id);
3290         writeU8(os, (u8)form->type);
3291         writeV2F1000(os, form->pos);
3292         os << serializeString(form->name);
3293         writeV2F1000(os, form->scale);
3294         os << serializeString(form->text);
3295         writeU32(os, form->number);
3296         writeU32(os, form->item);
3297         writeU32(os, form->dir);
3298         writeV2F1000(os, form->align);
3299         writeV2F1000(os, form->offset);
3300         writeV3F1000(os, form->world_pos);
3301         writeV2S32(os,form->size);
3302
3303         // Make data buffer
3304         std::string s = os.str();
3305         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3306         // Send as reliable
3307         m_clients.send(peer_id, 1, data, true);
3308 }
3309
3310 void Server::SendHUDRemove(u16 peer_id, u32 id)
3311 {
3312         std::ostringstream os(std::ios_base::binary);
3313
3314         // Write command
3315         writeU16(os, TOCLIENT_HUDRM);
3316         writeU32(os, id);
3317
3318         // Make data buffer
3319         std::string s = os.str();
3320         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3321         // Send as reliable
3322
3323         m_clients.send(peer_id, 1, data, true);
3324 }
3325
3326 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3327 {
3328         std::ostringstream os(std::ios_base::binary);
3329
3330         // Write command
3331         writeU16(os, TOCLIENT_HUDCHANGE);
3332         writeU32(os, id);
3333         writeU8(os, (u8)stat);
3334         switch (stat) {
3335                 case HUD_STAT_POS:
3336                 case HUD_STAT_SCALE:
3337                 case HUD_STAT_ALIGN:
3338                 case HUD_STAT_OFFSET:
3339                         writeV2F1000(os, *(v2f *)value);
3340                         break;
3341                 case HUD_STAT_NAME:
3342                 case HUD_STAT_TEXT:
3343                         os << serializeString(*(std::string *)value);
3344                         break;
3345                 case HUD_STAT_WORLD_POS:
3346                         writeV3F1000(os, *(v3f *)value);
3347                         break;
3348                 case HUD_STAT_SIZE:
3349                         writeV2S32(os,*(v2s32 *)value);
3350                         break;
3351                 case HUD_STAT_NUMBER:
3352                 case HUD_STAT_ITEM:
3353                 case HUD_STAT_DIR:
3354                 default:
3355                         writeU32(os, *(u32 *)value);
3356                         break;
3357         }
3358
3359         // Make data buffer
3360         std::string s = os.str();
3361         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3362         // Send as reliable
3363         m_clients.send(peer_id, 0, data, true);
3364 }
3365
3366 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3367 {
3368         std::ostringstream os(std::ios_base::binary);
3369
3370         // Write command
3371         writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3372
3373         //////////////////////////// compatibility code to be removed //////////////
3374         flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3375         ////////////////////////////////////////////////////////////////////////////
3376         writeU32(os, flags);
3377         writeU32(os, mask);
3378
3379         // Make data buffer
3380         std::string s = os.str();
3381         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3382         // Send as reliable
3383         m_clients.send(peer_id, 0, data, true);
3384 }
3385
3386 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3387 {
3388         std::ostringstream os(std::ios_base::binary);
3389
3390         // Write command
3391         writeU16(os, TOCLIENT_HUD_SET_PARAM);
3392         writeU16(os, param);
3393         os<<serializeString(value);
3394
3395         // Make data buffer
3396         std::string s = os.str();
3397         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3398         // Send as reliable
3399         m_clients.send(peer_id, 0, data, true);
3400 }
3401
3402 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3403                 const std::string &type, const std::vector<std::string> &params)
3404 {
3405         std::ostringstream os(std::ios_base::binary);
3406
3407         // Write command
3408         writeU16(os, TOCLIENT_SET_SKY);
3409         writeARGB8(os, bgcolor);
3410         os<<serializeString(type);
3411         writeU16(os, params.size());
3412         for(size_t i=0; i<params.size(); i++)
3413                 os<<serializeString(params[i]);
3414
3415         // Make data buffer
3416         std::string s = os.str();
3417         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3418         // Send as reliable
3419         m_clients.send(peer_id, 0, data, true);
3420 }
3421
3422 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3423                 float ratio)
3424 {
3425         std::ostringstream os(std::ios_base::binary);
3426
3427         // Write command
3428         writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3429         writeU8(os, do_override);
3430         writeU16(os, ratio*65535);
3431
3432         // Make data buffer
3433         std::string s = os.str();
3434         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3435         // Send as reliable
3436         m_clients.send(peer_id, 0, data, true);
3437 }
3438
3439 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3440 {
3441         DSTACK(__FUNCTION_NAME);
3442
3443         // Make packet
3444         SharedBuffer<u8> data(2+2+4);
3445         writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3446         writeU16(&data[2], time);
3447         writeF1000(&data[4], time_speed);
3448
3449         if (peer_id == PEER_ID_INEXISTENT) {
3450                 m_clients.sendToAll(0,data,true);
3451         }
3452         else {
3453                 // Send as reliable
3454                 m_clients.send(peer_id, 0, data, true);
3455         }
3456 }
3457
3458 void Server::SendPlayerHP(u16 peer_id)
3459 {
3460         DSTACK(__FUNCTION_NAME);
3461         PlayerSAO *playersao = getPlayerSAO(peer_id);
3462         assert(playersao);
3463         playersao->m_hp_not_sent = false;
3464         SendHP(peer_id, playersao->getHP());
3465         m_script->player_event(playersao,"health_changed");
3466
3467         // Send to other clients
3468         std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3469         ActiveObjectMessage aom(playersao->getId(), true, str);
3470         playersao->m_messages_out.push_back(aom);
3471 }
3472
3473 void Server::SendPlayerBreath(u16 peer_id)
3474 {
3475         DSTACK(__FUNCTION_NAME);
3476         PlayerSAO *playersao = getPlayerSAO(peer_id);
3477         assert(playersao);
3478         playersao->m_breath_not_sent = false;
3479         m_script->player_event(playersao,"breath_changed");
3480         SendBreath(peer_id, playersao->getBreath());
3481 }
3482
3483 void Server::SendMovePlayer(u16 peer_id)
3484 {
3485         DSTACK(__FUNCTION_NAME);
3486         Player *player = m_env->getPlayer(peer_id);
3487         assert(player);
3488
3489         std::ostringstream os(std::ios_base::binary);
3490         writeU16(os, TOCLIENT_MOVE_PLAYER);
3491         writeV3F1000(os, player->getPosition());
3492         writeF1000(os, player->getPitch());
3493         writeF1000(os, player->getYaw());
3494
3495         {
3496                 v3f pos = player->getPosition();
3497                 f32 pitch = player->getPitch();
3498                 f32 yaw = player->getYaw();
3499                 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3500                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3501                                 <<" pitch="<<pitch
3502                                 <<" yaw="<<yaw
3503                                 <<std::endl;
3504         }
3505
3506         // Make data buffer
3507         std::string s = os.str();
3508         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3509         // Send as reliable
3510         m_clients.send(peer_id, 0, data, true);
3511 }
3512
3513 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3514 {
3515         std::ostringstream os(std::ios_base::binary);
3516
3517         writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3518         writeV2S32(os, animation_frames[0]);
3519         writeV2S32(os, animation_frames[1]);
3520         writeV2S32(os, animation_frames[2]);
3521         writeV2S32(os, animation_frames[3]);
3522         writeF1000(os, animation_speed);
3523
3524         // Make data buffer
3525         std::string s = os.str();
3526         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3527         // Send as reliable
3528         m_clients.send(peer_id, 0, data, true);
3529 }
3530
3531 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3532 {
3533         std::ostringstream os(std::ios_base::binary);
3534
3535         writeU16(os, TOCLIENT_EYE_OFFSET);
3536         writeV3F1000(os, first);
3537         writeV3F1000(os, third);
3538
3539         // Make data buffer
3540         std::string s = os.str();
3541         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3542         // Send as reliable
3543         m_clients.send(peer_id, 0, data, true);
3544 }
3545 void Server::SendPlayerPrivileges(u16 peer_id)
3546 {
3547         Player *player = m_env->getPlayer(peer_id);
3548         assert(player);
3549         if(player->peer_id == PEER_ID_INEXISTENT)
3550                 return;
3551
3552         std::set<std::string> privs;
3553         m_script->getAuth(player->getName(), NULL, &privs);
3554
3555         std::ostringstream os(std::ios_base::binary);
3556         writeU16(os, TOCLIENT_PRIVILEGES);
3557         writeU16(os, privs.size());
3558         for(std::set<std::string>::const_iterator i = privs.begin();
3559                         i != privs.end(); i++){
3560                 os<<serializeString(*i);
3561         }
3562
3563         // Make data buffer
3564         std::string s = os.str();
3565         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3566         // Send as reliable
3567         m_clients.send(peer_id, 0, data, true);
3568 }
3569
3570 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3571 {
3572         Player *player = m_env->getPlayer(peer_id);
3573         assert(player);
3574         if(player->peer_id == PEER_ID_INEXISTENT)
3575                 return;
3576
3577         std::ostringstream os(std::ios_base::binary);
3578         writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3579         os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3580
3581         // Make data buffer
3582         std::string s = os.str();
3583         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3584         // Send as reliable
3585         m_clients.send(peer_id, 0, data, true);
3586 }
3587
3588 s32 Server::playSound(const SimpleSoundSpec &spec,
3589                 const ServerSoundParams &params)
3590 {
3591         // Find out initial position of sound
3592         bool pos_exists = false;
3593         v3f pos = params.getPos(m_env, &pos_exists);
3594         // If position is not found while it should be, cancel sound
3595         if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3596                 return -1;
3597
3598         // Filter destination clients
3599         std::list<u16> dst_clients;
3600         if(params.to_player != "")
3601         {
3602                 Player *player = m_env->getPlayer(params.to_player.c_str());
3603                 if(!player){
3604                         infostream<<"Server::playSound: Player \""<<params.to_player
3605                                         <<"\" not found"<<std::endl;
3606                         return -1;
3607                 }
3608                 if(player->peer_id == PEER_ID_INEXISTENT){
3609                         infostream<<"Server::playSound: Player \""<<params.to_player
3610                                         <<"\" not connected"<<std::endl;
3611                         return -1;
3612                 }
3613                 dst_clients.push_back(player->peer_id);
3614         }
3615         else
3616         {
3617                 std::list<u16> clients = m_clients.getClientIDs();
3618
3619                 for(std::list<u16>::iterator
3620                                 i = clients.begin(); i != clients.end(); ++i)
3621                 {
3622                         Player *player = m_env->getPlayer(*i);
3623                         if(!player)
3624                                 continue;
3625                         if(pos_exists){
3626                                 if(player->getPosition().getDistanceFrom(pos) >
3627                                                 params.max_hear_distance)
3628                                         continue;
3629                         }
3630                         dst_clients.push_back(*i);
3631                 }
3632         }
3633         if(dst_clients.size() == 0)
3634                 return -1;
3635
3636         // Create the sound
3637         s32 id = m_next_sound_id++;
3638         // The sound will exist as a reference in m_playing_sounds
3639         m_playing_sounds[id] = ServerPlayingSound();
3640         ServerPlayingSound &psound = m_playing_sounds[id];
3641         psound.params = params;
3642         for(std::list<u16>::iterator i = dst_clients.begin();
3643                         i != dst_clients.end(); i++)
3644                 psound.clients.insert(*i);
3645         // Create packet
3646         std::ostringstream os(std::ios_base::binary);
3647         writeU16(os, TOCLIENT_PLAY_SOUND);
3648         writeS32(os, id);
3649         os<<serializeString(spec.name);
3650         writeF1000(os, spec.gain * params.gain);
3651         writeU8(os, params.type);
3652         writeV3F1000(os, pos);
3653         writeU16(os, params.object);
3654         writeU8(os, params.loop);
3655         // Make data buffer
3656         std::string s = os.str();
3657         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3658         // Send
3659         for(std::list<u16>::iterator i = dst_clients.begin();
3660                         i != dst_clients.end(); i++){
3661                 // Send as reliable
3662                 m_clients.send(*i, 0, data, true);
3663         }
3664         return id;
3665 }
3666 void Server::stopSound(s32 handle)
3667 {
3668         // Get sound reference
3669         std::map<s32, ServerPlayingSound>::iterator i =
3670                         m_playing_sounds.find(handle);
3671         if(i == m_playing_sounds.end())
3672                 return;
3673         ServerPlayingSound &psound = i->second;
3674         // Create packet
3675         std::ostringstream os(std::ios_base::binary);
3676         writeU16(os, TOCLIENT_STOP_SOUND);
3677         writeS32(os, handle);
3678         // Make data buffer
3679         std::string s = os.str();
3680         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3681         // Send
3682         for(std::set<u16>::iterator i = psound.clients.begin();
3683                         i != psound.clients.end(); i++){
3684                 // Send as reliable
3685                 m_clients.send(*i, 0, data, true);
3686         }
3687         // Remove sound reference
3688         m_playing_sounds.erase(i);
3689 }
3690
3691 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3692         std::list<u16> *far_players, float far_d_nodes)
3693 {
3694         float maxd = far_d_nodes*BS;
3695         v3f p_f = intToFloat(p, BS);
3696
3697         // Create packet
3698         u32 replysize = 8;
3699         SharedBuffer<u8> reply(replysize);
3700         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3701         writeS16(&reply[2], p.X);
3702         writeS16(&reply[4], p.Y);
3703         writeS16(&reply[6], p.Z);
3704
3705         std::list<u16> clients = m_clients.getClientIDs();
3706         for(std::list<u16>::iterator
3707                 i = clients.begin();
3708                 i != clients.end(); ++i)
3709         {
3710                 if(far_players)
3711                 {
3712                         // Get player
3713                         Player *player = m_env->getPlayer(*i);
3714                         if(player)
3715                         {
3716                                 // If player is far away, only set modified blocks not sent
3717                                 v3f player_pos = player->getPosition();
3718                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3719                                 {
3720                                         far_players->push_back(*i);
3721                                         continue;
3722                                 }
3723                         }
3724                 }
3725
3726                 // Send as reliable
3727                 m_clients.send(*i, 0, reply, true);
3728         }
3729 }
3730
3731 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3732                 std::list<u16> *far_players, float far_d_nodes,
3733                 bool remove_metadata)
3734 {
3735         float maxd = far_d_nodes*BS;
3736         v3f p_f = intToFloat(p, BS);
3737
3738         std::list<u16> clients = m_clients.getClientIDs();
3739                 for(std::list<u16>::iterator
3740                         i = clients.begin();
3741                         i != clients.end(); ++i)
3742                 {
3743
3744                 if(far_players)
3745                 {
3746                         // Get player
3747                         Player *player = m_env->getPlayer(*i);
3748                         if(player)
3749                         {
3750                                 // If player is far away, only set modified blocks not sent
3751                                 v3f player_pos = player->getPosition();
3752                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3753                                 {
3754                                         far_players->push_back(*i);
3755                                         continue;
3756                                 }
3757                         }
3758                 }
3759                 SharedBuffer<u8> reply(0);
3760                 m_clients.Lock();
3761                 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3762                 if (client != 0)
3763                 {
3764                         // Create packet
3765                         u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3766                         reply = SharedBuffer<u8>(replysize);
3767                         writeU16(&reply[0], TOCLIENT_ADDNODE);
3768                         writeS16(&reply[2], p.X);
3769                         writeS16(&reply[4], p.Y);
3770                         writeS16(&reply[6], p.Z);
3771                         n.serialize(&reply[8], client->serialization_version);
3772                         u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3773                         writeU8(&reply[index], remove_metadata ? 0 : 1);
3774
3775                         if (!remove_metadata) {
3776                                 if (client->net_proto_version <= 21) {
3777                                         // Old clients always clear metadata; fix it
3778                                         // by sending the full block again.
3779                                         client->SetBlockNotSent(p);
3780                                 }
3781                         }
3782                 }
3783                 m_clients.Unlock();
3784
3785                 // Send as reliable
3786                 if (reply.getSize() > 0)
3787                         m_clients.send(*i, 0, reply, true);
3788         }
3789 }
3790
3791 void Server::setBlockNotSent(v3s16 p)
3792 {
3793         std::list<u16> clients = m_clients.getClientIDs();
3794         m_clients.Lock();
3795         for(std::list<u16>::iterator
3796                 i = clients.begin();
3797                 i != clients.end(); ++i)
3798         {
3799                 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3800                 client->SetBlockNotSent(p);
3801         }
3802         m_clients.Unlock();
3803 }
3804
3805 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3806 {
3807         DSTACK(__FUNCTION_NAME);
3808
3809         v3s16 p = block->getPos();
3810
3811 #if 0
3812         // Analyze it a bit
3813         bool completely_air = true;
3814         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3815         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3816         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3817         {
3818                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3819                 {
3820                         completely_air = false;
3821                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3822                 }
3823         }
3824
3825         // Print result
3826         infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3827         if(completely_air)
3828                 infostream<<"[completely air] ";
3829         infostream<<std::endl;
3830 #endif
3831
3832         /*
3833                 Create a packet with the block in the right format
3834         */
3835
3836         std::ostringstream os(std::ios_base::binary);
3837         block->serialize(os, ver, false);
3838         block->serializeNetworkSpecific(os, net_proto_version);
3839         std::string s = os.str();
3840         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3841
3842         u32 replysize = 8 + blockdata.getSize();
3843         SharedBuffer<u8> reply(replysize);
3844         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3845         writeS16(&reply[2], p.X);
3846         writeS16(&reply[4], p.Y);
3847         writeS16(&reply[6], p.Z);
3848         memcpy(&reply[8], *blockdata, blockdata.getSize());
3849
3850         /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3851                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3852
3853         /*
3854                 Send packet
3855         */
3856         m_clients.send(peer_id, 2, reply, true);
3857 }
3858
3859 void Server::SendBlocks(float dtime)
3860 {
3861         DSTACK(__FUNCTION_NAME);
3862
3863         JMutexAutoLock envlock(m_env_mutex);
3864         //TODO check if one big lock could be faster then multiple small ones
3865
3866         ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3867
3868         std::vector<PrioritySortedBlockTransfer> queue;
3869
3870         s32 total_sending = 0;
3871
3872         {
3873                 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3874
3875                 std::list<u16> clients = m_clients.getClientIDs();
3876
3877                 m_clients.Lock();
3878                 for(std::list<u16>::iterator
3879                         i = clients.begin();
3880                         i != clients.end(); ++i)
3881                 {
3882                         RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3883
3884                         if (client == NULL)
3885                                 continue;
3886
3887                         total_sending += client->SendingCount();
3888                         client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3889                 }
3890                 m_clients.Unlock();
3891         }
3892
3893         // Sort.
3894         // Lowest priority number comes first.
3895         // Lowest is most important.
3896         std::sort(queue.begin(), queue.end());
3897
3898         m_clients.Lock();
3899         for(u32 i=0; i<queue.size(); i++)
3900         {
3901                 //TODO: Calculate limit dynamically
3902                 if(total_sending >= g_settings->getS32
3903                                 ("max_simultaneous_block_sends_server_total"))
3904                         break;
3905
3906                 PrioritySortedBlockTransfer q = queue[i];
3907
3908                 MapBlock *block = NULL;
3909                 try
3910                 {
3911                         block = m_env->getMap().getBlockNoCreate(q.pos);
3912                 }
3913                 catch(InvalidPositionException &e)
3914                 {
3915                         continue;
3916                 }
3917
3918                 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3919
3920                 if(!client)
3921                         continue;
3922
3923                 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3924
3925                 client->SentBlock(q.pos);
3926                 total_sending++;
3927         }
3928         m_clients.Unlock();
3929 }
3930
3931 void Server::fillMediaCache()
3932 {
3933         DSTACK(__FUNCTION_NAME);
3934
3935         infostream<<"Server: Calculating media file checksums"<<std::endl;
3936
3937         // Collect all media file paths
3938         std::list<std::string> paths;
3939         for(std::vector<ModSpec>::iterator i = m_mods.begin();
3940                         i != m_mods.end(); i++){
3941                 const ModSpec &mod = *i;
3942                 paths.push_back(mod.path + DIR_DELIM + "textures");
3943                 paths.push_back(mod.path + DIR_DELIM + "sounds");
3944                 paths.push_back(mod.path + DIR_DELIM + "media");
3945                 paths.push_back(mod.path + DIR_DELIM + "models");
3946         }
3947         paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3948
3949         // Collect media file information from paths into cache
3950         for(std::list<std::string>::iterator i = paths.begin();
3951                         i != paths.end(); i++)
3952         {
3953                 std::string mediapath = *i;
3954                 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3955                 for(u32 j=0; j<dirlist.size(); j++){
3956                         if(dirlist[j].dir) // Ignode dirs
3957                                 continue;
3958                         std::string filename = dirlist[j].name;
3959                         // If name contains illegal characters, ignore the file
3960                         if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3961                                 infostream<<"Server: ignoring illegal file name: \""
3962                                                 <<filename<<"\""<<std::endl;
3963                                 continue;
3964                         }
3965                         // If name is not in a supported format, ignore it
3966                         const char *supported_ext[] = {
3967                                 ".png", ".jpg", ".bmp", ".tga",
3968                                 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3969                                 ".ogg",
3970                                 ".x", ".b3d", ".md2", ".obj",
3971                                 NULL
3972                         };
3973                         if(removeStringEnd(filename, supported_ext) == ""){
3974                                 infostream<<"Server: ignoring unsupported file extension: \""
3975                                                 <<filename<<"\""<<std::endl;
3976                                 continue;
3977                         }
3978                         // Ok, attempt to load the file and add to cache
3979                         std::string filepath = mediapath + DIR_DELIM + filename;
3980                         // Read data
3981                         std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3982                         if(fis.good() == false){
3983                                 errorstream<<"Server::fillMediaCache(): Could not open \""
3984                                                 <<filename<<"\" for reading"<<std::endl;
3985                                 continue;
3986                         }
3987                         std::ostringstream tmp_os(std::ios_base::binary);
3988                         bool bad = false;
3989                         for(;;){
3990                                 char buf[1024];
3991                                 fis.read(buf, 1024);
3992                                 std::streamsize len = fis.gcount();
3993                                 tmp_os.write(buf, len);
3994                                 if(fis.eof())
3995                                         break;
3996                                 if(!fis.good()){
3997                                         bad = true;
3998                                         break;
3999                                 }
4000                         }
4001                         if(bad){
4002                                 errorstream<<"Server::fillMediaCache(): Failed to read \""
4003                                                 <<filename<<"\""<<std::endl;
4004                                 continue;
4005                         }
4006                         if(tmp_os.str().length() == 0){
4007                                 errorstream<<"Server::fillMediaCache(): Empty file \""
4008                                                 <<filepath<<"\""<<std::endl;
4009                                 continue;
4010                         }
4011
4012                         SHA1 sha1;
4013                         sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4014
4015                         unsigned char *digest = sha1.getDigest();
4016                         std::string sha1_base64 = base64_encode(digest, 20);
4017                         std::string sha1_hex = hex_encode((char*)digest, 20);
4018                         free(digest);
4019
4020                         // Put in list
4021                         this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4022                         verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4023                 }
4024         }
4025 }
4026
4027 struct SendableMediaAnnouncement
4028 {
4029         std::string name;
4030         std::string sha1_digest;
4031
4032         SendableMediaAnnouncement(const std::string &name_="",
4033                                   const std::string &sha1_digest_=""):
4034                 name(name_),
4035                 sha1_digest(sha1_digest_)
4036         {}
4037 };
4038
4039 void Server::sendMediaAnnouncement(u16 peer_id)
4040 {
4041         DSTACK(__FUNCTION_NAME);
4042
4043         verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4044                         <<std::endl;
4045
4046         std::list<SendableMediaAnnouncement> file_announcements;
4047
4048         for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4049                         i != m_media.end(); i++){
4050                 // Put in list
4051                 file_announcements.push_back(
4052                                 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4053         }
4054
4055         // Make packet
4056         std::ostringstream os(std::ios_base::binary);
4057
4058         /*
4059                 u16 command
4060                 u32 number of files
4061                 for each texture {
4062                         u16 length of name
4063                         string name
4064                         u16 length of sha1_digest
4065                         string sha1_digest
4066                 }
4067         */
4068
4069         writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4070         writeU16(os, file_announcements.size());
4071
4072         for(std::list<SendableMediaAnnouncement>::iterator
4073                         j = file_announcements.begin();
4074                         j != file_announcements.end(); ++j){
4075                 os<<serializeString(j->name);
4076                 os<<serializeString(j->sha1_digest);
4077         }
4078         os<<serializeString(g_settings->get("remote_media"));
4079
4080         // Make data buffer
4081         std::string s = os.str();
4082         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4083
4084         // Send as reliable
4085         m_clients.send(peer_id, 0, data, true);
4086 }
4087
4088 struct SendableMedia
4089 {
4090         std::string name;
4091         std::string path;
4092         std::string data;
4093
4094         SendableMedia(const std::string &name_="", const std::string &path_="",
4095                       const std::string &data_=""):
4096                 name(name_),
4097                 path(path_),
4098                 data(data_)
4099         {}
4100 };
4101
4102 void Server::sendRequestedMedia(u16 peer_id,
4103                 const std::list<std::string> &tosend)
4104 {
4105         DSTACK(__FUNCTION_NAME);
4106
4107         verbosestream<<"Server::sendRequestedMedia(): "
4108                         <<"Sending files to client"<<std::endl;
4109
4110         /* Read files */
4111
4112         // Put 5kB in one bunch (this is not accurate)
4113         u32 bytes_per_bunch = 5000;
4114
4115         std::vector< std::list<SendableMedia> > file_bunches;
4116         file_bunches.push_back(std::list<SendableMedia>());
4117
4118         u32 file_size_bunch_total = 0;
4119
4120         for(std::list<std::string>::const_iterator i = tosend.begin();
4121                         i != tosend.end(); ++i)
4122         {
4123                 const std::string &name = *i;
4124
4125                 if(m_media.find(name) == m_media.end()){
4126                         errorstream<<"Server::sendRequestedMedia(): Client asked for "
4127                                         <<"unknown file \""<<(name)<<"\""<<std::endl;
4128                         continue;
4129                 }
4130
4131                 //TODO get path + name
4132                 std::string tpath = m_media[name].path;
4133
4134                 // Read data
4135                 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4136                 if(fis.good() == false){
4137                         errorstream<<"Server::sendRequestedMedia(): Could not open \""
4138                                         <<tpath<<"\" for reading"<<std::endl;
4139                         continue;
4140                 }
4141                 std::ostringstream tmp_os(std::ios_base::binary);
4142                 bool bad = false;
4143                 for(;;){
4144                         char buf[1024];
4145                         fis.read(buf, 1024);
4146                         std::streamsize len = fis.gcount();
4147                         tmp_os.write(buf, len);
4148                         file_size_bunch_total += len;
4149                         if(fis.eof())
4150                                 break;
4151                         if(!fis.good()){
4152                                 bad = true;
4153                                 break;
4154                         }
4155                 }
4156                 if(bad){
4157                         errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4158                                         <<name<<"\""<<std::endl;
4159                         continue;
4160                 }
4161                 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4162                                 <<tname<<"\""<<std::endl;*/
4163                 // Put in list
4164                 file_bunches[file_bunches.size()-1].push_back(
4165                                 SendableMedia(name, tpath, tmp_os.str()));
4166
4167                 // Start next bunch if got enough data
4168                 if(file_size_bunch_total >= bytes_per_bunch){
4169                         file_bunches.push_back(std::list<SendableMedia>());
4170                         file_size_bunch_total = 0;
4171                 }
4172
4173         }
4174
4175         /* Create and send packets */
4176
4177         u32 num_bunches = file_bunches.size();
4178         for(u32 i=0; i<num_bunches; i++)
4179         {
4180                 std::ostringstream os(std::ios_base::binary);
4181
4182                 /*
4183                         u16 command
4184                         u16 total number of texture bunches
4185                         u16 index of this bunch
4186                         u32 number of files in this bunch
4187                         for each file {
4188                                 u16 length of name
4189                                 string name
4190                                 u32 length of data
4191                                 data
4192                         }
4193                 */
4194
4195                 writeU16(os, TOCLIENT_MEDIA);
4196                 writeU16(os, num_bunches);
4197                 writeU16(os, i);
4198                 writeU32(os, file_bunches[i].size());
4199
4200                 for(std::list<SendableMedia>::iterator
4201                                 j = file_bunches[i].begin();
4202                                 j != file_bunches[i].end(); ++j){
4203                         os<<serializeString(j->name);
4204                         os<<serializeLongString(j->data);
4205                 }
4206
4207                 // Make data buffer
4208                 std::string s = os.str();
4209                 verbosestream<<"Server::sendRequestedMedia(): bunch "
4210                                 <<i<<"/"<<num_bunches
4211                                 <<" files="<<file_bunches[i].size()
4212                                 <<" size=" <<s.size()<<std::endl;
4213                 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4214                 // Send as reliable
4215                 m_clients.send(peer_id, 2, data, true);
4216         }
4217 }
4218
4219 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4220 {
4221         if(m_detached_inventories.count(name) == 0){
4222                 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4223                 return;
4224         }
4225         Inventory *inv = m_detached_inventories[name];
4226
4227         std::ostringstream os(std::ios_base::binary);
4228         writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4229         os<<serializeString(name);
4230         inv->serialize(os);
4231
4232         // Make data buffer
4233         std::string s = os.str();
4234         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4235
4236         if (peer_id != PEER_ID_INEXISTENT)
4237         {
4238                 // Send as reliable
4239                 m_clients.send(peer_id, 0, data, true);
4240         }
4241         else
4242         {
4243                 m_clients.sendToAll(0,data,true);
4244         }
4245 }
4246
4247 void Server::sendDetachedInventories(u16 peer_id)
4248 {
4249         DSTACK(__FUNCTION_NAME);
4250
4251         for(std::map<std::string, Inventory*>::iterator
4252                         i = m_detached_inventories.begin();
4253                         i != m_detached_inventories.end(); i++){
4254                 const std::string &name = i->first;
4255                 //Inventory *inv = i->second;
4256                 sendDetachedInventory(name, peer_id);
4257         }
4258 }
4259
4260 /*
4261         Something random
4262 */
4263
4264 void Server::DiePlayer(u16 peer_id)
4265 {
4266         DSTACK(__FUNCTION_NAME);
4267
4268         PlayerSAO *playersao = getPlayerSAO(peer_id);
4269         assert(playersao);
4270
4271         infostream<<"Server::DiePlayer(): Player "
4272                         <<playersao->getPlayer()->getName()
4273                         <<" dies"<<std::endl;
4274
4275         playersao->setHP(0);
4276
4277         // Trigger scripted stuff
4278         m_script->on_dieplayer(playersao);
4279
4280         SendPlayerHP(peer_id);
4281         SendDeathscreen(peer_id, false, v3f(0,0,0));
4282 }
4283
4284 void Server::RespawnPlayer(u16 peer_id)
4285 {
4286         DSTACK(__FUNCTION_NAME);
4287
4288         PlayerSAO *playersao = getPlayerSAO(peer_id);
4289         assert(playersao);
4290
4291         infostream<<"Server::RespawnPlayer(): Player "
4292                         <<playersao->getPlayer()->getName()
4293                         <<" respawns"<<std::endl;
4294
4295         playersao->setHP(PLAYER_MAX_HP);
4296
4297         bool repositioned = m_script->on_respawnplayer(playersao);
4298         if(!repositioned){
4299                 v3f pos = findSpawnPos(m_env->getServerMap());
4300                 playersao->setPos(pos);
4301         }
4302 }
4303
4304 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4305 {
4306         DSTACK(__FUNCTION_NAME);
4307
4308         SendAccessDenied(peer_id, reason);
4309         m_clients.event(peer_id, CSE_SetDenied);
4310         m_con.DisconnectPeer(peer_id);
4311 }
4312
4313 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4314 {
4315         DSTACK(__FUNCTION_NAME);
4316         std::wstring message;
4317         {
4318                 /*
4319                         Clear references to playing sounds
4320                 */
4321                 for(std::map<s32, ServerPlayingSound>::iterator
4322                                 i = m_playing_sounds.begin();
4323                                 i != m_playing_sounds.end();)
4324                 {
4325                         ServerPlayingSound &psound = i->second;
4326                         psound.clients.erase(peer_id);
4327                         if(psound.clients.size() == 0)
4328                                 m_playing_sounds.erase(i++);
4329                         else
4330                                 i++;
4331                 }
4332
4333                 Player *player = m_env->getPlayer(peer_id);
4334
4335                 // Collect information about leaving in chat
4336                 {
4337                         if(player != NULL && reason != CDR_DENY)
4338                         {
4339                                 std::wstring name = narrow_to_wide(player->getName());
4340                                 message += L"*** ";
4341                                 message += name;
4342                                 message += L" left the game.";
4343                                 if(reason == CDR_TIMEOUT)
4344                                         message += L" (timed out)";
4345                         }
4346                 }
4347
4348                 /* Run scripts and remove from environment */
4349                 {
4350                         if(player != NULL)
4351                         {
4352                                 PlayerSAO *playersao = player->getPlayerSAO();
4353                                 assert(playersao);
4354
4355                                 m_script->on_leaveplayer(playersao);
4356
4357                                 playersao->disconnected();
4358                         }
4359                 }
4360
4361                 /*
4362                         Print out action
4363                 */
4364                 {
4365                         if(player != NULL && reason != CDR_DENY)
4366                         {
4367                                 std::ostringstream os(std::ios_base::binary);
4368                                 std::list<u16> clients = m_clients.getClientIDs();
4369
4370                                 for(std::list<u16>::iterator
4371                                         i = clients.begin();
4372                                         i != clients.end(); ++i)
4373                                 {
4374                                         // Get player
4375                                         Player *player = m_env->getPlayer(*i);
4376                                         if(!player)
4377                                                 continue;
4378                                         // Get name of player
4379                                         os<<player->getName()<<" ";
4380                                 }
4381
4382                                 actionstream<<player->getName()<<" "
4383                                                 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4384                                                 <<" List of players: "<<os.str()<<std::endl;
4385                         }
4386                 }
4387                 {
4388                         JMutexAutoLock env_lock(m_env_mutex);
4389                         m_clients.DeleteClient(peer_id);
4390                 }
4391         }
4392
4393         // Send leave chat message to all remaining clients
4394         if(message.length() != 0)
4395                 SendChatMessage(PEER_ID_INEXISTENT,message);
4396 }
4397
4398 void Server::UpdateCrafting(u16 peer_id)
4399 {
4400         DSTACK(__FUNCTION_NAME);
4401
4402         Player* player = m_env->getPlayer(peer_id);
4403         assert(player);
4404
4405         // Get a preview for crafting
4406         ItemStack preview;
4407         InventoryLocation loc;
4408         loc.setPlayer(player->getName());
4409         getCraftingResult(&player->inventory, preview, false, this);
4410         m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4411
4412         // Put the new preview in
4413         InventoryList *plist = player->inventory.getList("craftpreview");
4414         assert(plist);
4415         assert(plist->getSize() >= 1);
4416         plist->changeItem(0, preview);
4417 }
4418
4419 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4420 {
4421         RemoteClient *client = getClientNoEx(peer_id,state_min);
4422         if(!client)
4423                 throw ClientNotFoundException("Client not found");
4424
4425         return client;
4426 }
4427 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4428 {
4429         return m_clients.getClientNoEx(peer_id, state_min);
4430 }
4431
4432 std::string Server::getPlayerName(u16 peer_id)
4433 {
4434         Player *player = m_env->getPlayer(peer_id);
4435         if(player == NULL)
4436                 return "[id="+itos(peer_id)+"]";
4437         return player->getName();
4438 }
4439
4440 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4441 {
4442         Player *player = m_env->getPlayer(peer_id);
4443         if(player == NULL)
4444                 return NULL;
4445         return player->getPlayerSAO();
4446 }
4447
4448 std::wstring Server::getStatusString()
4449 {
4450         std::wostringstream os(std::ios_base::binary);
4451         os<<L"# Server: ";
4452         // Version
4453         os<<L"version="<<narrow_to_wide(minetest_version_simple);
4454         // Uptime
4455         os<<L", uptime="<<m_uptime.get();
4456         // Max lag estimate
4457         os<<L", max_lag="<<m_env->getMaxLagEstimate();
4458         // Information about clients
4459         bool first = true;
4460         os<<L", clients={";
4461         std::list<u16> clients = m_clients.getClientIDs();
4462         for(std::list<u16>::iterator i = clients.begin();
4463                 i != clients.end(); ++i)
4464         {
4465                 // Get player
4466                 Player *player = m_env->getPlayer(*i);
4467                 // Get name of player
4468                 std::wstring name = L"unknown";
4469                 if(player != NULL)
4470                         name = narrow_to_wide(player->getName());
4471                 // Add name to information string
4472                 if(!first)
4473                         os<<L",";
4474                 else
4475                         first = false;
4476                 os<<name;
4477         }
4478         os<<L"}";
4479         if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4480                 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4481         if(g_settings->get("motd") != "")
4482                 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4483         return os.str();
4484 }
4485
4486 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4487 {
4488         std::set<std::string> privs;
4489         m_script->getAuth(name, NULL, &privs);
4490         return privs;
4491 }
4492
4493 bool Server::checkPriv(const std::string &name, const std::string &priv)
4494 {
4495         std::set<std::string> privs = getPlayerEffectivePrivs(name);
4496         return (privs.count(priv) != 0);
4497 }
4498
4499 void Server::reportPrivsModified(const std::string &name)
4500 {
4501         if(name == ""){
4502                 std::list<u16> clients = m_clients.getClientIDs();
4503                 for(std::list<u16>::iterator
4504                                 i = clients.begin();
4505                                 i != clients.end(); ++i){
4506                         Player *player = m_env->getPlayer(*i);
4507                         reportPrivsModified(player->getName());
4508                 }
4509         } else {
4510                 Player *player = m_env->getPlayer(name.c_str());
4511                 if(!player)
4512                         return;
4513                 SendPlayerPrivileges(player->peer_id);
4514                 PlayerSAO *sao = player->getPlayerSAO();
4515                 if(!sao)
4516                         return;
4517                 sao->updatePrivileges(
4518                                 getPlayerEffectivePrivs(name),
4519                                 isSingleplayer());
4520         }
4521 }
4522
4523 void Server::reportInventoryFormspecModified(const std::string &name)
4524 {
4525         Player *player = m_env->getPlayer(name.c_str());
4526         if(!player)
4527                 return;
4528         SendPlayerInventoryFormspec(player->peer_id);
4529 }
4530
4531 void Server::setIpBanned(const std::string &ip, const std::string &name)
4532 {
4533         m_banmanager->add(ip, name);
4534 }
4535
4536 void Server::unsetIpBanned(const std::string &ip_or_name)
4537 {
4538         m_banmanager->remove(ip_or_name);
4539 }
4540
4541 std::string Server::getBanDescription(const std::string &ip_or_name)
4542 {
4543         return m_banmanager->getBanDescription(ip_or_name);
4544 }
4545
4546 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4547 {
4548         Player *player = m_env->getPlayer(name);
4549         if(!player)
4550                 return;
4551
4552         if (player->peer_id == PEER_ID_INEXISTENT)
4553                 return;
4554
4555         SendChatMessage(player->peer_id, msg);
4556 }
4557
4558 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4559 {
4560         Player *player = m_env->getPlayer(playername);
4561
4562         if(!player)
4563         {
4564                 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4565                 return false;
4566         }
4567
4568         SendShowFormspecMessage(player->peer_id, formspec, formname);
4569         return true;
4570 }
4571
4572 u32 Server::hudAdd(Player *player, HudElement *form) {
4573         if (!player)
4574                 return -1;
4575         
4576         u32 id = player->addHud(form);
4577
4578         SendHUDAdd(player->peer_id, id, form);
4579
4580         return id;
4581 }
4582
4583 bool Server::hudRemove(Player *player, u32 id) {
4584         if (!player)
4585                 return false;
4586
4587         HudElement* todel = player->removeHud(id);
4588
4589         if (!todel)
4590                 return false;
4591         
4592         delete todel;
4593
4594         SendHUDRemove(player->peer_id, id);
4595         return true;
4596 }
4597
4598 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4599         if (!player)
4600                 return false;
4601
4602         SendHUDChange(player->peer_id, id, stat, data);
4603         return true;
4604 }
4605
4606 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4607         if (!player)
4608                 return false;
4609
4610         SendHUDSetFlags(player->peer_id, flags, mask);
4611         player->hud_flags = flags;
4612         
4613         PlayerSAO* playersao = player->getPlayerSAO();
4614         
4615         if (playersao == NULL)
4616                 return false;
4617
4618         m_script->player_event(playersao, "hud_changed");
4619         return true;
4620 }
4621
4622 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4623         if (!player)
4624                 return false;
4625         if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4626                 return false;
4627
4628         std::ostringstream os(std::ios::binary);
4629         writeS32(os, hotbar_itemcount);
4630         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4631         return true;
4632 }
4633
4634 void Server::hudSetHotbarImage(Player *player, std::string name) {
4635         if (!player)
4636                 return;
4637
4638         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4639 }
4640
4641 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4642         if (!player)
4643                 return;
4644
4645         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4646 }
4647
4648 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4649 {
4650         if (!player)
4651                 return false;
4652
4653         SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4654         return true;
4655 }
4656
4657 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4658 {
4659         if (!player)
4660                 return false;
4661
4662         SendEyeOffset(player->peer_id, first, third);
4663         return true;
4664 }
4665
4666 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4667                 const std::string &type, const std::vector<std::string> &params)
4668 {
4669         if (!player)
4670                 return false;
4671
4672         SendSetSky(player->peer_id, bgcolor, type, params);
4673         return true;
4674 }
4675
4676 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4677                 float ratio)
4678 {
4679         if (!player)
4680                 return false;
4681
4682         SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4683         return true;
4684 }
4685
4686 void Server::notifyPlayers(const std::wstring &msg)
4687 {
4688         SendChatMessage(PEER_ID_INEXISTENT,msg);
4689 }
4690
4691 void Server::spawnParticle(const char *playername, v3f pos,
4692                 v3f velocity, v3f acceleration,
4693                 float expirationtime, float size, bool
4694                 collisiondetection, bool vertical, std::string texture)
4695 {
4696         Player *player = m_env->getPlayer(playername);
4697         if(!player)
4698                 return;
4699         SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4700                         expirationtime, size, collisiondetection, vertical, texture);
4701 }
4702
4703 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4704                 float expirationtime, float size,
4705                 bool collisiondetection, bool vertical, std::string texture)
4706 {
4707         SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4708                         expirationtime, size, collisiondetection, vertical, texture);
4709 }
4710
4711 u32 Server::addParticleSpawner(const char *playername,
4712                 u16 amount, float spawntime,
4713                 v3f minpos, v3f maxpos,
4714                 v3f minvel, v3f maxvel,
4715                 v3f minacc, v3f maxacc,
4716                 float minexptime, float maxexptime,
4717                 float minsize, float maxsize,
4718                 bool collisiondetection, bool vertical, std::string texture)
4719 {
4720         Player *player = m_env->getPlayer(playername);
4721         if(!player)
4722                 return -1;
4723
4724         u32 id = 0;
4725         for(;;) // look for unused particlespawner id
4726         {
4727                 id++;
4728                 if (std::find(m_particlespawner_ids.begin(),
4729                                 m_particlespawner_ids.end(), id)
4730                                 == m_particlespawner_ids.end())
4731                 {
4732                         m_particlespawner_ids.push_back(id);
4733                         break;
4734                 }
4735         }
4736
4737         SendAddParticleSpawner(player->peer_id, amount, spawntime,
4738                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4739                 minexptime, maxexptime, minsize, maxsize,
4740                 collisiondetection, vertical, texture, id);
4741
4742         return id;
4743 }
4744
4745 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4746                 v3f minpos, v3f maxpos,
4747                 v3f minvel, v3f maxvel,
4748                 v3f minacc, v3f maxacc,
4749                 float minexptime, float maxexptime,
4750                 float minsize, float maxsize,
4751                 bool collisiondetection, bool vertical, std::string texture)
4752 {
4753         u32 id = 0;
4754         for(;;) // look for unused particlespawner id
4755         {
4756                 id++;
4757                 if (std::find(m_particlespawner_ids.begin(),
4758                                 m_particlespawner_ids.end(), id)
4759                                 == m_particlespawner_ids.end())
4760                 {
4761                         m_particlespawner_ids.push_back(id);
4762                         break;
4763                 }
4764         }
4765
4766         SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4767                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4768                 minexptime, maxexptime, minsize, maxsize,
4769                 collisiondetection, vertical, texture, id);
4770
4771         return id;
4772 }
4773
4774 void Server::deleteParticleSpawner(const char *playername, u32 id)
4775 {
4776         Player *player = m_env->getPlayer(playername);
4777         if(!player)
4778                 return;
4779
4780         m_particlespawner_ids.erase(
4781                         std::remove(m_particlespawner_ids.begin(),
4782                         m_particlespawner_ids.end(), id),
4783                         m_particlespawner_ids.end());
4784         SendDeleteParticleSpawner(player->peer_id, id);
4785 }
4786
4787 void Server::deleteParticleSpawnerAll(u32 id)
4788 {
4789         m_particlespawner_ids.erase(
4790                         std::remove(m_particlespawner_ids.begin(),
4791                         m_particlespawner_ids.end(), id),
4792                         m_particlespawner_ids.end());
4793         SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4794 }
4795
4796 Inventory* Server::createDetachedInventory(const std::string &name)
4797 {
4798         if(m_detached_inventories.count(name) > 0){
4799                 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4800                 delete m_detached_inventories[name];
4801         } else {
4802                 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4803         }
4804         Inventory *inv = new Inventory(m_itemdef);
4805         assert(inv);
4806         m_detached_inventories[name] = inv;
4807         //TODO find a better way to do this
4808         sendDetachedInventory(name,PEER_ID_INEXISTENT);
4809         return inv;
4810 }
4811
4812 class BoolScopeSet
4813 {
4814 public:
4815         BoolScopeSet(bool *dst, bool val):
4816                 m_dst(dst)
4817         {
4818                 m_orig_state = *m_dst;
4819                 *m_dst = val;
4820         }
4821         ~BoolScopeSet()
4822         {
4823                 *m_dst = m_orig_state;
4824         }
4825 private:
4826         bool *m_dst;
4827         bool m_orig_state;
4828 };
4829
4830 // actions: time-reversed list
4831 // Return value: success/failure
4832 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4833                 std::list<std::string> *log)
4834 {
4835         infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4836         ServerMap *map = (ServerMap*)(&m_env->getMap());
4837         // Disable rollback report sink while reverting
4838         BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4839
4840         // Fail if no actions to handle
4841         if(actions.empty()){
4842                 log->push_back("Nothing to do.");
4843                 return false;
4844         }
4845
4846         int num_tried = 0;
4847         int num_failed = 0;
4848
4849         for(std::list<RollbackAction>::const_iterator
4850                         i = actions.begin();
4851                         i != actions.end(); i++)
4852         {
4853                 const RollbackAction &action = *i;
4854                 num_tried++;
4855                 bool success = action.applyRevert(map, this, this);
4856                 if(!success){
4857                         num_failed++;
4858                         std::ostringstream os;
4859                         os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4860                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4861                         if(log)
4862                                 log->push_back(os.str());
4863                 }else{
4864                         std::ostringstream os;
4865                         os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4866                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4867                         if(log)
4868                                 log->push_back(os.str());
4869                 }
4870         }
4871
4872         infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4873                         <<" failed"<<std::endl;
4874
4875         // Call it done if less than half failed
4876         return num_failed <= num_tried/2;
4877 }
4878
4879 // IGameDef interface
4880 // Under envlock
4881 IItemDefManager* Server::getItemDefManager()
4882 {
4883         return m_itemdef;
4884 }
4885 INodeDefManager* Server::getNodeDefManager()
4886 {
4887         return m_nodedef;
4888 }
4889 ICraftDefManager* Server::getCraftDefManager()
4890 {
4891         return m_craftdef;
4892 }
4893 ITextureSource* Server::getTextureSource()
4894 {
4895         return NULL;
4896 }
4897 IShaderSource* Server::getShaderSource()
4898 {
4899         return NULL;
4900 }
4901 scene::ISceneManager* Server::getSceneManager()
4902 {
4903         return NULL;
4904 }
4905
4906 u16 Server::allocateUnknownNodeId(const std::string &name)
4907 {
4908         return m_nodedef->allocateDummy(name);
4909 }
4910 ISoundManager* Server::getSoundManager()
4911 {
4912         return &dummySoundManager;
4913 }
4914 MtEventManager* Server::getEventManager()
4915 {
4916         return m_event;
4917 }
4918 IRollbackReportSink* Server::getRollbackReportSink()
4919 {
4920         if(!m_enable_rollback_recording)
4921                 return NULL;
4922         if(!m_rollback_sink_enabled)
4923                 return NULL;
4924         return m_rollback;
4925 }
4926
4927 IWritableItemDefManager* Server::getWritableItemDefManager()
4928 {
4929         return m_itemdef;
4930 }
4931 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4932 {
4933         return m_nodedef;
4934 }
4935 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4936 {
4937         return m_craftdef;
4938 }
4939
4940 const ModSpec* Server::getModSpec(const std::string &modname)
4941 {
4942         for(std::vector<ModSpec>::iterator i = m_mods.begin();
4943                         i != m_mods.end(); i++){
4944                 const ModSpec &mod = *i;
4945                 if(mod.name == modname)
4946                         return &mod;
4947         }
4948         return NULL;
4949 }
4950 void Server::getModNames(std::list<std::string> &modlist)
4951 {
4952         for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4953         {
4954                 modlist.push_back(i->name);
4955         }
4956 }
4957 std::string Server::getBuiltinLuaPath()
4958 {
4959         return porting::path_share + DIR_DELIM + "builtin";
4960 }
4961
4962 v3f findSpawnPos(ServerMap &map)
4963 {
4964         //return v3f(50,50,50)*BS;
4965
4966         v3s16 nodepos;
4967
4968 #if 0
4969         nodepos = v2s16(0,0);
4970         groundheight = 20;
4971 #endif
4972
4973 #if 1
4974         s16 water_level = map.getWaterLevel();
4975
4976         // Try to find a good place a few times
4977         for(s32 i=0; i<1000; i++)
4978         {
4979                 s32 range = 1 + i;
4980                 // We're going to try to throw the player to this position
4981                 v2s16 nodepos2d = v2s16(
4982                                 -range + (myrand() % (range * 2)),
4983                                 -range + (myrand() % (range * 2)));
4984
4985                 // Get ground height at point
4986                 s16 groundheight = map.findGroundLevel(nodepos2d);
4987                 if (groundheight <= water_level) // Don't go underwater
4988                         continue;
4989                 if (groundheight > water_level + 6) // Don't go to high places
4990                         continue;
4991
4992                 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4993                 bool is_good = false;
4994                 s32 air_count = 0;
4995                 for (s32 i = 0; i < 10; i++) {
4996                         v3s16 blockpos = getNodeBlockPos(nodepos);
4997                         map.emergeBlock(blockpos, true);
4998                         content_t c = map.getNodeNoEx(nodepos).getContent();
4999                         if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5000                                 air_count++;
5001                                 if (air_count >= 2){
5002                                         is_good = true;
5003                                         break;
5004                                 }
5005                         }
5006                         nodepos.Y++;
5007                 }
5008                 if(is_good){
5009                         // Found a good place
5010                         //infostream<<"Searched through "<<i<<" places."<<std::endl;
5011                         break;
5012                 }
5013         }
5014 #endif
5015
5016         return intToFloat(nodepos, BS);
5017 }
5018
5019 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5020 {
5021         RemotePlayer *player = NULL;
5022         bool newplayer = false;
5023
5024         /*
5025                 Try to get an existing player
5026         */
5027         player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5028
5029         // If player is already connected, cancel
5030         if(player != NULL && player->peer_id != 0)
5031         {
5032                 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5033                 return NULL;
5034         }
5035
5036         /*
5037                 If player with the wanted peer_id already exists, cancel.
5038         */
5039         if(m_env->getPlayer(peer_id) != NULL)
5040         {
5041                 infostream<<"emergePlayer(): Player with wrong name but same"
5042                                 " peer_id already exists"<<std::endl;
5043                 return NULL;
5044         }
5045
5046         // Load player if it isn't already loaded
5047         if (!player) {
5048                 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5049         }
5050
5051         // Create player if it doesn't exist
5052         if (!player) {
5053                 newplayer = true;
5054                 player = new RemotePlayer(this, name);
5055                 // Set player position
5056                 infostream<<"Server: Finding spawn place for player \""
5057                                 <<name<<"\""<<std::endl;
5058                 v3f pos = findSpawnPos(m_env->getServerMap());
5059                 player->setPosition(pos);
5060
5061                 // Make sure the player is saved
5062                 player->setModified(true);
5063
5064                 // Add player to environment
5065                 m_env->addPlayer(player);
5066         }
5067
5068         // Create a new player active object
5069         PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5070                         getPlayerEffectivePrivs(player->getName()),
5071                         isSingleplayer());
5072
5073         /* Clean up old HUD elements from previous sessions */
5074         player->clearHud();
5075
5076         /* Add object to environment */
5077         m_env->addActiveObject(playersao);
5078
5079         /* Run scripts */
5080         if (newplayer) {
5081                 m_script->on_newplayer(playersao);
5082         }
5083
5084         return playersao;
5085 }
5086
5087 void dedicated_server_loop(Server &server, bool &kill)
5088 {
5089         DSTACK(__FUNCTION_NAME);
5090
5091         verbosestream<<"dedicated_server_loop()"<<std::endl;
5092
5093         IntervalLimiter m_profiler_interval;
5094
5095         for(;;)
5096         {
5097                 float steplen = g_settings->getFloat("dedicated_server_step");
5098                 // This is kind of a hack but can be done like this
5099                 // because server.step() is very light
5100                 {
5101                         ScopeProfiler sp(g_profiler, "dedicated server sleep");
5102                         sleep_ms((int)(steplen*1000.0));
5103                 }
5104                 server.step(steplen);
5105
5106                 if(server.getShutdownRequested() || kill)
5107                 {
5108                         infostream<<"Dedicated server quitting"<<std::endl;
5109 #if USE_CURL
5110                         if(g_settings->getBool("server_announce") == true)
5111                                 ServerList::sendAnnounce("delete");
5112 #endif
5113                         break;
5114                 }
5115
5116                 /*
5117                         Profiler
5118                 */
5119                 float profiler_print_interval =
5120                                 g_settings->getFloat("profiler_print_interval");
5121                 if(profiler_print_interval != 0)
5122                 {
5123                         if(m_profiler_interval.step(steplen, profiler_print_interval))
5124                         {
5125                                 infostream<<"Profiler:"<<std::endl;
5126                                 g_profiler->print(infostream);
5127                                 g_profiler->clear();
5128                         }
5129                 }
5130         }
5131 }
5132
5133