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