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