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