]> git.lizzy.rs Git - dragonfireclient.git/blob - src/server.cpp
Add third person view
[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::SendPlayerPrivileges(u16 peer_id)
3506 {
3507         Player *player = m_env->getPlayer(peer_id);
3508         assert(player);
3509         if(player->peer_id == PEER_ID_INEXISTENT)
3510                 return;
3511
3512         std::set<std::string> privs;
3513         m_script->getAuth(player->getName(), NULL, &privs);
3514
3515         std::ostringstream os(std::ios_base::binary);
3516         writeU16(os, TOCLIENT_PRIVILEGES);
3517         writeU16(os, privs.size());
3518         for(std::set<std::string>::const_iterator i = privs.begin();
3519                         i != privs.end(); i++){
3520                 os<<serializeString(*i);
3521         }
3522
3523         // Make data buffer
3524         std::string s = os.str();
3525         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3526         // Send as reliable
3527         m_clients.send(peer_id, 0, data, true);
3528 }
3529
3530 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3531 {
3532         Player *player = m_env->getPlayer(peer_id);
3533         assert(player);
3534         if(player->peer_id == PEER_ID_INEXISTENT)
3535                 return;
3536
3537         std::ostringstream os(std::ios_base::binary);
3538         writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3539         os<<serializeLongString(player->inventory_formspec);
3540
3541         // Make data buffer
3542         std::string s = os.str();
3543         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3544         // Send as reliable
3545         m_clients.send(peer_id, 0, data, true);
3546 }
3547
3548 s32 Server::playSound(const SimpleSoundSpec &spec,
3549                 const ServerSoundParams &params)
3550 {
3551         // Find out initial position of sound
3552         bool pos_exists = false;
3553         v3f pos = params.getPos(m_env, &pos_exists);
3554         // If position is not found while it should be, cancel sound
3555         if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3556                 return -1;
3557
3558         // Filter destination clients
3559         std::list<u16> dst_clients;
3560         if(params.to_player != "")
3561         {
3562                 Player *player = m_env->getPlayer(params.to_player.c_str());
3563                 if(!player){
3564                         infostream<<"Server::playSound: Player \""<<params.to_player
3565                                         <<"\" not found"<<std::endl;
3566                         return -1;
3567                 }
3568                 if(player->peer_id == PEER_ID_INEXISTENT){
3569                         infostream<<"Server::playSound: Player \""<<params.to_player
3570                                         <<"\" not connected"<<std::endl;
3571                         return -1;
3572                 }
3573                 dst_clients.push_back(player->peer_id);
3574         }
3575         else
3576         {
3577                 std::list<u16> clients = m_clients.getClientIDs();
3578
3579                 for(std::list<u16>::iterator
3580                                 i = clients.begin(); i != clients.end(); ++i)
3581                 {
3582                         Player *player = m_env->getPlayer(*i);
3583                         if(!player)
3584                                 continue;
3585                         if(pos_exists){
3586                                 if(player->getPosition().getDistanceFrom(pos) >
3587                                                 params.max_hear_distance)
3588                                         continue;
3589                         }
3590                         dst_clients.push_back(*i);
3591                 }
3592         }
3593         if(dst_clients.size() == 0)
3594                 return -1;
3595
3596         // Create the sound
3597         s32 id = m_next_sound_id++;
3598         // The sound will exist as a reference in m_playing_sounds
3599         m_playing_sounds[id] = ServerPlayingSound();
3600         ServerPlayingSound &psound = m_playing_sounds[id];
3601         psound.params = params;
3602         for(std::list<u16>::iterator i = dst_clients.begin();
3603                         i != dst_clients.end(); i++)
3604                 psound.clients.insert(*i);
3605         // Create packet
3606         std::ostringstream os(std::ios_base::binary);
3607         writeU16(os, TOCLIENT_PLAY_SOUND);
3608         writeS32(os, id);
3609         os<<serializeString(spec.name);
3610         writeF1000(os, spec.gain * params.gain);
3611         writeU8(os, params.type);
3612         writeV3F1000(os, pos);
3613         writeU16(os, params.object);
3614         writeU8(os, params.loop);
3615         // Make data buffer
3616         std::string s = os.str();
3617         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3618         // Send
3619         for(std::list<u16>::iterator i = dst_clients.begin();
3620                         i != dst_clients.end(); i++){
3621                 // Send as reliable
3622                 m_clients.send(*i, 0, data, true);
3623         }
3624         return id;
3625 }
3626 void Server::stopSound(s32 handle)
3627 {
3628         // Get sound reference
3629         std::map<s32, ServerPlayingSound>::iterator i =
3630                         m_playing_sounds.find(handle);
3631         if(i == m_playing_sounds.end())
3632                 return;
3633         ServerPlayingSound &psound = i->second;
3634         // Create packet
3635         std::ostringstream os(std::ios_base::binary);
3636         writeU16(os, TOCLIENT_STOP_SOUND);
3637         writeS32(os, handle);
3638         // Make data buffer
3639         std::string s = os.str();
3640         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3641         // Send
3642         for(std::set<u16>::iterator i = psound.clients.begin();
3643                         i != psound.clients.end(); i++){
3644                 // Send as reliable
3645                 m_clients.send(*i, 0, data, true);
3646         }
3647         // Remove sound reference
3648         m_playing_sounds.erase(i);
3649 }
3650
3651 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3652         std::list<u16> *far_players, float far_d_nodes)
3653 {
3654         float maxd = far_d_nodes*BS;
3655         v3f p_f = intToFloat(p, BS);
3656
3657         // Create packet
3658         u32 replysize = 8;
3659         SharedBuffer<u8> reply(replysize);
3660         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3661         writeS16(&reply[2], p.X);
3662         writeS16(&reply[4], p.Y);
3663         writeS16(&reply[6], p.Z);
3664
3665         std::list<u16> clients = m_clients.getClientIDs();
3666         for(std::list<u16>::iterator
3667                 i = clients.begin();
3668                 i != clients.end(); ++i)
3669         {
3670                 if(far_players)
3671                 {
3672                         // Get player
3673                         Player *player = m_env->getPlayer(*i);
3674                         if(player)
3675                         {
3676                                 // If player is far away, only set modified blocks not sent
3677                                 v3f player_pos = player->getPosition();
3678                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3679                                 {
3680                                         far_players->push_back(*i);
3681                                         continue;
3682                                 }
3683                         }
3684                 }
3685
3686                 // Send as reliable
3687                 m_clients.send(*i, 0, reply, true);
3688         }
3689 }
3690
3691 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3692                 std::list<u16> *far_players, float far_d_nodes,
3693                 bool remove_metadata)
3694 {
3695         float maxd = far_d_nodes*BS;
3696         v3f p_f = intToFloat(p, BS);
3697
3698         std::list<u16> clients = m_clients.getClientIDs();
3699                 for(std::list<u16>::iterator
3700                         i = clients.begin();
3701                         i != clients.end(); ++i)
3702                 {
3703
3704                 if(far_players)
3705                 {
3706                         // Get player
3707                         Player *player = m_env->getPlayer(*i);
3708                         if(player)
3709                         {
3710                                 // If player is far away, only set modified blocks not sent
3711                                 v3f player_pos = player->getPosition();
3712                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3713                                 {
3714                                         far_players->push_back(*i);
3715                                         continue;
3716                                 }
3717                         }
3718                 }
3719                 SharedBuffer<u8> reply(0);
3720                 m_clients.Lock();
3721                 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3722                 if (client != 0)
3723                 {
3724                         // Create packet
3725                         u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3726                         reply = SharedBuffer<u8>(replysize);
3727                         writeU16(&reply[0], TOCLIENT_ADDNODE);
3728                         writeS16(&reply[2], p.X);
3729                         writeS16(&reply[4], p.Y);
3730                         writeS16(&reply[6], p.Z);
3731                         n.serialize(&reply[8], client->serialization_version);
3732                         u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3733                         writeU8(&reply[index], remove_metadata ? 0 : 1);
3734
3735                         if (!remove_metadata) {
3736                                 if (client->net_proto_version <= 21) {
3737                                         // Old clients always clear metadata; fix it
3738                                         // by sending the full block again.
3739                                         client->SetBlockNotSent(p);
3740                                 }
3741                         }
3742                 }
3743                 m_clients.Unlock();
3744
3745                 // Send as reliable
3746                 if (reply.getSize() > 0)
3747                         m_clients.send(*i, 0, reply, true);
3748         }
3749 }
3750
3751 void Server::setBlockNotSent(v3s16 p)
3752 {
3753         std::list<u16> clients = m_clients.getClientIDs();
3754         m_clients.Lock();
3755         for(std::list<u16>::iterator
3756                 i = clients.begin();
3757                 i != clients.end(); ++i)
3758         {
3759                 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3760                 client->SetBlockNotSent(p);
3761         }
3762         m_clients.Unlock();
3763 }
3764
3765 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3766 {
3767         DSTACK(__FUNCTION_NAME);
3768
3769         v3s16 p = block->getPos();
3770
3771 #if 0
3772         // Analyze it a bit
3773         bool completely_air = true;
3774         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3775         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3776         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3777         {
3778                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3779                 {
3780                         completely_air = false;
3781                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3782                 }
3783         }
3784
3785         // Print result
3786         infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3787         if(completely_air)
3788                 infostream<<"[completely air] ";
3789         infostream<<std::endl;
3790 #endif
3791
3792         /*
3793                 Create a packet with the block in the right format
3794         */
3795
3796         std::ostringstream os(std::ios_base::binary);
3797         block->serialize(os, ver, false);
3798         block->serializeNetworkSpecific(os, net_proto_version);
3799         std::string s = os.str();
3800         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3801
3802         u32 replysize = 8 + blockdata.getSize();
3803         SharedBuffer<u8> reply(replysize);
3804         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3805         writeS16(&reply[2], p.X);
3806         writeS16(&reply[4], p.Y);
3807         writeS16(&reply[6], p.Z);
3808         memcpy(&reply[8], *blockdata, blockdata.getSize());
3809
3810         /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3811                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3812
3813         /*
3814                 Send packet
3815         */
3816         m_clients.send(peer_id, 2, reply, true);
3817 }
3818
3819 void Server::SendBlocks(float dtime)
3820 {
3821         DSTACK(__FUNCTION_NAME);
3822
3823         JMutexAutoLock envlock(m_env_mutex);
3824         //TODO check if one big lock could be faster then multiple small ones
3825
3826         ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3827
3828         std::vector<PrioritySortedBlockTransfer> queue;
3829
3830         s32 total_sending = 0;
3831
3832         {
3833                 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3834
3835                 std::list<u16> clients = m_clients.getClientIDs();
3836
3837                 m_clients.Lock();
3838                 for(std::list<u16>::iterator
3839                         i = clients.begin();
3840                         i != clients.end(); ++i)
3841                 {
3842                         RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3843
3844                         if (client == NULL)
3845                                 return;
3846
3847                         total_sending += client->SendingCount();
3848                         client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3849                 }
3850                 m_clients.Unlock();
3851         }
3852
3853         // Sort.
3854         // Lowest priority number comes first.
3855         // Lowest is most important.
3856         std::sort(queue.begin(), queue.end());
3857
3858         m_clients.Lock();
3859         for(u32 i=0; i<queue.size(); i++)
3860         {
3861                 //TODO: Calculate limit dynamically
3862                 if(total_sending >= g_settings->getS32
3863                                 ("max_simultaneous_block_sends_server_total"))
3864                         break;
3865
3866                 PrioritySortedBlockTransfer q = queue[i];
3867
3868                 MapBlock *block = NULL;
3869                 try
3870                 {
3871                         block = m_env->getMap().getBlockNoCreate(q.pos);
3872                 }
3873                 catch(InvalidPositionException &e)
3874                 {
3875                         continue;
3876                 }
3877
3878                 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3879
3880                 if(!client)
3881                         continue;
3882
3883                 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3884
3885                 client->SentBlock(q.pos);
3886                 total_sending++;
3887         }
3888         m_clients.Unlock();
3889 }
3890
3891 void Server::fillMediaCache()
3892 {
3893         DSTACK(__FUNCTION_NAME);
3894
3895         infostream<<"Server: Calculating media file checksums"<<std::endl;
3896
3897         // Collect all media file paths
3898         std::list<std::string> paths;
3899         for(std::vector<ModSpec>::iterator i = m_mods.begin();
3900                         i != m_mods.end(); i++){
3901                 const ModSpec &mod = *i;
3902                 paths.push_back(mod.path + DIR_DELIM + "textures");
3903                 paths.push_back(mod.path + DIR_DELIM + "sounds");
3904                 paths.push_back(mod.path + DIR_DELIM + "media");
3905                 paths.push_back(mod.path + DIR_DELIM + "models");
3906         }
3907         paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3908
3909         // Collect media file information from paths into cache
3910         for(std::list<std::string>::iterator i = paths.begin();
3911                         i != paths.end(); i++)
3912         {
3913                 std::string mediapath = *i;
3914                 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3915                 for(u32 j=0; j<dirlist.size(); j++){
3916                         if(dirlist[j].dir) // Ignode dirs
3917                                 continue;
3918                         std::string filename = dirlist[j].name;
3919                         // If name contains illegal characters, ignore the file
3920                         if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3921                                 infostream<<"Server: ignoring illegal file name: \""
3922                                                 <<filename<<"\""<<std::endl;
3923                                 continue;
3924                         }
3925                         // If name is not in a supported format, ignore it
3926                         const char *supported_ext[] = {
3927                                 ".png", ".jpg", ".bmp", ".tga",
3928                                 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3929                                 ".ogg",
3930                                 ".x", ".b3d", ".md2", ".obj",
3931                                 NULL
3932                         };
3933                         if(removeStringEnd(filename, supported_ext) == ""){
3934                                 infostream<<"Server: ignoring unsupported file extension: \""
3935                                                 <<filename<<"\""<<std::endl;
3936                                 continue;
3937                         }
3938                         // Ok, attempt to load the file and add to cache
3939                         std::string filepath = mediapath + DIR_DELIM + filename;
3940                         // Read data
3941                         std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3942                         if(fis.good() == false){
3943                                 errorstream<<"Server::fillMediaCache(): Could not open \""
3944                                                 <<filename<<"\" for reading"<<std::endl;
3945                                 continue;
3946                         }
3947                         std::ostringstream tmp_os(std::ios_base::binary);
3948                         bool bad = false;
3949                         for(;;){
3950                                 char buf[1024];
3951                                 fis.read(buf, 1024);
3952                                 std::streamsize len = fis.gcount();
3953                                 tmp_os.write(buf, len);
3954                                 if(fis.eof())
3955                                         break;
3956                                 if(!fis.good()){
3957                                         bad = true;
3958                                         break;
3959                                 }
3960                         }
3961                         if(bad){
3962                                 errorstream<<"Server::fillMediaCache(): Failed to read \""
3963                                                 <<filename<<"\""<<std::endl;
3964                                 continue;
3965                         }
3966                         if(tmp_os.str().length() == 0){
3967                                 errorstream<<"Server::fillMediaCache(): Empty file \""
3968                                                 <<filepath<<"\""<<std::endl;
3969                                 continue;
3970                         }
3971
3972                         SHA1 sha1;
3973                         sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3974
3975                         unsigned char *digest = sha1.getDigest();
3976                         std::string sha1_base64 = base64_encode(digest, 20);
3977                         std::string sha1_hex = hex_encode((char*)digest, 20);
3978                         free(digest);
3979
3980                         // Put in list
3981                         this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3982                         verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3983                 }
3984         }
3985 }
3986
3987 struct SendableMediaAnnouncement
3988 {
3989         std::string name;
3990         std::string sha1_digest;
3991
3992         SendableMediaAnnouncement(const std::string &name_="",
3993                                   const std::string &sha1_digest_=""):
3994                 name(name_),
3995                 sha1_digest(sha1_digest_)
3996         {}
3997 };
3998
3999 void Server::sendMediaAnnouncement(u16 peer_id)
4000 {
4001         DSTACK(__FUNCTION_NAME);
4002
4003         verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4004                         <<std::endl;
4005
4006         std::list<SendableMediaAnnouncement> file_announcements;
4007
4008         for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4009                         i != m_media.end(); i++){
4010                 // Put in list
4011                 file_announcements.push_back(
4012                                 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4013         }
4014
4015         // Make packet
4016         std::ostringstream os(std::ios_base::binary);
4017
4018         /*
4019                 u16 command
4020                 u32 number of files
4021                 for each texture {
4022                         u16 length of name
4023                         string name
4024                         u16 length of sha1_digest
4025                         string sha1_digest
4026                 }
4027         */
4028
4029         writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4030         writeU16(os, file_announcements.size());
4031
4032         for(std::list<SendableMediaAnnouncement>::iterator
4033                         j = file_announcements.begin();
4034                         j != file_announcements.end(); ++j){
4035                 os<<serializeString(j->name);
4036                 os<<serializeString(j->sha1_digest);
4037         }
4038         os<<serializeString(g_settings->get("remote_media"));
4039
4040         // Make data buffer
4041         std::string s = os.str();
4042         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4043
4044         // Send as reliable
4045         m_clients.send(peer_id, 0, data, true);
4046 }
4047
4048 struct SendableMedia
4049 {
4050         std::string name;
4051         std::string path;
4052         std::string data;
4053
4054         SendableMedia(const std::string &name_="", const std::string &path_="",
4055                       const std::string &data_=""):
4056                 name(name_),
4057                 path(path_),
4058                 data(data_)
4059         {}
4060 };
4061
4062 void Server::sendRequestedMedia(u16 peer_id,
4063                 const std::list<std::string> &tosend)
4064 {
4065         DSTACK(__FUNCTION_NAME);
4066
4067         verbosestream<<"Server::sendRequestedMedia(): "
4068                         <<"Sending files to client"<<std::endl;
4069
4070         /* Read files */
4071
4072         // Put 5kB in one bunch (this is not accurate)
4073         u32 bytes_per_bunch = 5000;
4074
4075         std::vector< std::list<SendableMedia> > file_bunches;
4076         file_bunches.push_back(std::list<SendableMedia>());
4077
4078         u32 file_size_bunch_total = 0;
4079
4080         for(std::list<std::string>::const_iterator i = tosend.begin();
4081                         i != tosend.end(); ++i)
4082         {
4083                 const std::string &name = *i;
4084
4085                 if(m_media.find(name) == m_media.end()){
4086                         errorstream<<"Server::sendRequestedMedia(): Client asked for "
4087                                         <<"unknown file \""<<(name)<<"\""<<std::endl;
4088                         continue;
4089                 }
4090
4091                 //TODO get path + name
4092                 std::string tpath = m_media[name].path;
4093
4094                 // Read data
4095                 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4096                 if(fis.good() == false){
4097                         errorstream<<"Server::sendRequestedMedia(): Could not open \""
4098                                         <<tpath<<"\" for reading"<<std::endl;
4099                         continue;
4100                 }
4101                 std::ostringstream tmp_os(std::ios_base::binary);
4102                 bool bad = false;
4103                 for(;;){
4104                         char buf[1024];
4105                         fis.read(buf, 1024);
4106                         std::streamsize len = fis.gcount();
4107                         tmp_os.write(buf, len);
4108                         file_size_bunch_total += len;
4109                         if(fis.eof())
4110                                 break;
4111                         if(!fis.good()){
4112                                 bad = true;
4113                                 break;
4114                         }
4115                 }
4116                 if(bad){
4117                         errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4118                                         <<name<<"\""<<std::endl;
4119                         continue;
4120                 }
4121                 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4122                                 <<tname<<"\""<<std::endl;*/
4123                 // Put in list
4124                 file_bunches[file_bunches.size()-1].push_back(
4125                                 SendableMedia(name, tpath, tmp_os.str()));
4126
4127                 // Start next bunch if got enough data
4128                 if(file_size_bunch_total >= bytes_per_bunch){
4129                         file_bunches.push_back(std::list<SendableMedia>());
4130                         file_size_bunch_total = 0;
4131                 }
4132
4133         }
4134
4135         /* Create and send packets */
4136
4137         u32 num_bunches = file_bunches.size();
4138         for(u32 i=0; i<num_bunches; i++)
4139         {
4140                 std::ostringstream os(std::ios_base::binary);
4141
4142                 /*
4143                         u16 command
4144                         u16 total number of texture bunches
4145                         u16 index of this bunch
4146                         u32 number of files in this bunch
4147                         for each file {
4148                                 u16 length of name
4149                                 string name
4150                                 u32 length of data
4151                                 data
4152                         }
4153                 */
4154
4155                 writeU16(os, TOCLIENT_MEDIA);
4156                 writeU16(os, num_bunches);
4157                 writeU16(os, i);
4158                 writeU32(os, file_bunches[i].size());
4159
4160                 for(std::list<SendableMedia>::iterator
4161                                 j = file_bunches[i].begin();
4162                                 j != file_bunches[i].end(); ++j){
4163                         os<<serializeString(j->name);
4164                         os<<serializeLongString(j->data);
4165                 }
4166
4167                 // Make data buffer
4168                 std::string s = os.str();
4169                 verbosestream<<"Server::sendRequestedMedia(): bunch "
4170                                 <<i<<"/"<<num_bunches
4171                                 <<" files="<<file_bunches[i].size()
4172                                 <<" size=" <<s.size()<<std::endl;
4173                 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4174                 // Send as reliable
4175                 m_clients.send(peer_id, 2, data, true);
4176         }
4177 }
4178
4179 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4180 {
4181         if(m_detached_inventories.count(name) == 0){
4182                 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4183                 return;
4184         }
4185         Inventory *inv = m_detached_inventories[name];
4186
4187         std::ostringstream os(std::ios_base::binary);
4188         writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4189         os<<serializeString(name);
4190         inv->serialize(os);
4191
4192         // Make data buffer
4193         std::string s = os.str();
4194         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4195
4196         if (peer_id != PEER_ID_INEXISTENT)
4197         {
4198                 // Send as reliable
4199                 m_clients.send(peer_id, 0, data, true);
4200         }
4201         else
4202         {
4203                 m_clients.sendToAll(0,data,true);
4204         }
4205 }
4206
4207 void Server::sendDetachedInventories(u16 peer_id)
4208 {
4209         DSTACK(__FUNCTION_NAME);
4210
4211         for(std::map<std::string, Inventory*>::iterator
4212                         i = m_detached_inventories.begin();
4213                         i != m_detached_inventories.end(); i++){
4214                 const std::string &name = i->first;
4215                 //Inventory *inv = i->second;
4216                 sendDetachedInventory(name, peer_id);
4217         }
4218 }
4219
4220 /*
4221         Something random
4222 */
4223
4224 void Server::DiePlayer(u16 peer_id)
4225 {
4226         DSTACK(__FUNCTION_NAME);
4227
4228         PlayerSAO *playersao = getPlayerSAO(peer_id);
4229         assert(playersao);
4230
4231         infostream<<"Server::DiePlayer(): Player "
4232                         <<playersao->getPlayer()->getName()
4233                         <<" dies"<<std::endl;
4234
4235         playersao->setHP(0);
4236
4237         // Trigger scripted stuff
4238         m_script->on_dieplayer(playersao);
4239
4240         SendPlayerHP(peer_id);
4241         SendDeathscreen(peer_id, false, v3f(0,0,0));
4242 }
4243
4244 void Server::RespawnPlayer(u16 peer_id)
4245 {
4246         DSTACK(__FUNCTION_NAME);
4247
4248         PlayerSAO *playersao = getPlayerSAO(peer_id);
4249         assert(playersao);
4250
4251         infostream<<"Server::RespawnPlayer(): Player "
4252                         <<playersao->getPlayer()->getName()
4253                         <<" respawns"<<std::endl;
4254
4255         playersao->setHP(PLAYER_MAX_HP);
4256
4257         bool repositioned = m_script->on_respawnplayer(playersao);
4258         if(!repositioned){
4259                 v3f pos = findSpawnPos(m_env->getServerMap());
4260                 playersao->setPos(pos);
4261         }
4262 }
4263
4264 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4265 {
4266         DSTACK(__FUNCTION_NAME);
4267
4268         SendAccessDenied(peer_id, reason);
4269         m_clients.event(peer_id,SetDenied);
4270         m_con.DisconnectPeer(peer_id);
4271 }
4272
4273 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4274 {
4275         DSTACK(__FUNCTION_NAME);
4276         std::wstring message;
4277         {
4278                 /*
4279                         Clear references to playing sounds
4280                 */
4281                 for(std::map<s32, ServerPlayingSound>::iterator
4282                                 i = m_playing_sounds.begin();
4283                                 i != m_playing_sounds.end();)
4284                 {
4285                         ServerPlayingSound &psound = i->second;
4286                         psound.clients.erase(peer_id);
4287                         if(psound.clients.size() == 0)
4288                                 m_playing_sounds.erase(i++);
4289                         else
4290                                 i++;
4291                 }
4292
4293                 Player *player = m_env->getPlayer(peer_id);
4294
4295                 // Collect information about leaving in chat
4296                 {
4297                         if(player != NULL && reason != CDR_DENY)
4298                         {
4299                                 std::wstring name = narrow_to_wide(player->getName());
4300                                 message += L"*** ";
4301                                 message += name;
4302                                 message += L" left the game.";
4303                                 if(reason == CDR_TIMEOUT)
4304                                         message += L" (timed out)";
4305                         }
4306                 }
4307
4308                 /* Run scripts and remove from environment */
4309                 {
4310                         if(player != NULL)
4311                         {
4312                                 PlayerSAO *playersao = player->getPlayerSAO();
4313                                 assert(playersao);
4314
4315                                 m_script->on_leaveplayer(playersao);
4316
4317                                 playersao->disconnected();
4318                         }
4319                 }
4320
4321                 /*
4322                         Print out action
4323                 */
4324                 {
4325                         if(player != NULL && reason != CDR_DENY)
4326                         {
4327                                 std::ostringstream os(std::ios_base::binary);
4328                                 std::list<u16> clients = m_clients.getClientIDs();
4329
4330                                 for(std::list<u16>::iterator
4331                                         i = clients.begin();
4332                                         i != clients.end(); ++i)
4333                                 {
4334                                         // Get player
4335                                         Player *player = m_env->getPlayer(*i);
4336                                         if(!player)
4337                                                 continue;
4338                                         // Get name of player
4339                                         os<<player->getName()<<" ";
4340                                 }
4341
4342                                 actionstream<<player->getName()<<" "
4343                                                 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4344                                                 <<" List of players: "<<os.str()<<std::endl;
4345                         }
4346                 }
4347                 {
4348                         JMutexAutoLock env_lock(m_env_mutex);
4349                         m_clients.DeleteClient(peer_id);
4350                 }
4351         }
4352
4353         // Send leave chat message to all remaining clients
4354         if(message.length() != 0)
4355                 SendChatMessage(PEER_ID_INEXISTENT,message);
4356 }
4357
4358 void Server::UpdateCrafting(u16 peer_id)
4359 {
4360         DSTACK(__FUNCTION_NAME);
4361
4362         Player* player = m_env->getPlayer(peer_id);
4363         assert(player);
4364
4365         // Get a preview for crafting
4366         ItemStack preview;
4367         InventoryLocation loc;
4368         loc.setPlayer(player->getName());
4369         getCraftingResult(&player->inventory, preview, false, this);
4370         m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4371
4372         // Put the new preview in
4373         InventoryList *plist = player->inventory.getList("craftpreview");
4374         assert(plist);
4375         assert(plist->getSize() >= 1);
4376         plist->changeItem(0, preview);
4377 }
4378
4379 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4380 {
4381         RemoteClient *client = getClientNoEx(peer_id,state_min);
4382         if(!client)
4383                 throw ClientNotFoundException("Client not found");
4384
4385         return client;
4386 }
4387 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4388 {
4389         return m_clients.getClientNoEx(peer_id, state_min);
4390 }
4391
4392 std::string Server::getPlayerName(u16 peer_id)
4393 {
4394         Player *player = m_env->getPlayer(peer_id);
4395         if(player == NULL)
4396                 return "[id="+itos(peer_id)+"]";
4397         return player->getName();
4398 }
4399
4400 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4401 {
4402         Player *player = m_env->getPlayer(peer_id);
4403         if(player == NULL)
4404                 return NULL;
4405         return player->getPlayerSAO();
4406 }
4407
4408 std::wstring Server::getStatusString()
4409 {
4410         std::wostringstream os(std::ios_base::binary);
4411         os<<L"# Server: ";
4412         // Version
4413         os<<L"version="<<narrow_to_wide(minetest_version_simple);
4414         // Uptime
4415         os<<L", uptime="<<m_uptime.get();
4416         // Max lag estimate
4417         os<<L", max_lag="<<m_env->getMaxLagEstimate();
4418         // Information about clients
4419         bool first = true;
4420         os<<L", clients={";
4421         std::list<u16> clients = m_clients.getClientIDs();
4422         for(std::list<u16>::iterator i = clients.begin();
4423                 i != clients.end(); ++i)
4424         {
4425                 // Get player
4426                 Player *player = m_env->getPlayer(*i);
4427                 // Get name of player
4428                 std::wstring name = L"unknown";
4429                 if(player != NULL)
4430                         name = narrow_to_wide(player->getName());
4431                 // Add name to information string
4432                 if(!first)
4433                         os<<L",";
4434                 else
4435                         first = false;
4436                 os<<name;
4437         }
4438         os<<L"}";
4439         if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4440                 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4441         if(g_settings->get("motd") != "")
4442                 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4443         return os.str();
4444 }
4445
4446 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4447 {
4448         std::set<std::string> privs;
4449         m_script->getAuth(name, NULL, &privs);
4450         return privs;
4451 }
4452
4453 bool Server::checkPriv(const std::string &name, const std::string &priv)
4454 {
4455         std::set<std::string> privs = getPlayerEffectivePrivs(name);
4456         return (privs.count(priv) != 0);
4457 }
4458
4459 void Server::reportPrivsModified(const std::string &name)
4460 {
4461         if(name == ""){
4462                 std::list<u16> clients = m_clients.getClientIDs();
4463                 for(std::list<u16>::iterator
4464                                 i = clients.begin();
4465                                 i != clients.end(); ++i){
4466                         Player *player = m_env->getPlayer(*i);
4467                         reportPrivsModified(player->getName());
4468                 }
4469         } else {
4470                 Player *player = m_env->getPlayer(name.c_str());
4471                 if(!player)
4472                         return;
4473                 SendPlayerPrivileges(player->peer_id);
4474                 PlayerSAO *sao = player->getPlayerSAO();
4475                 if(!sao)
4476                         return;
4477                 sao->updatePrivileges(
4478                                 getPlayerEffectivePrivs(name),
4479                                 isSingleplayer());
4480         }
4481 }
4482
4483 void Server::reportInventoryFormspecModified(const std::string &name)
4484 {
4485         Player *player = m_env->getPlayer(name.c_str());
4486         if(!player)
4487                 return;
4488         SendPlayerInventoryFormspec(player->peer_id);
4489 }
4490
4491 void Server::setIpBanned(const std::string &ip, const std::string &name)
4492 {
4493         m_banmanager->add(ip, name);
4494 }
4495
4496 void Server::unsetIpBanned(const std::string &ip_or_name)
4497 {
4498         m_banmanager->remove(ip_or_name);
4499 }
4500
4501 std::string Server::getBanDescription(const std::string &ip_or_name)
4502 {
4503         return m_banmanager->getBanDescription(ip_or_name);
4504 }
4505
4506 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4507 {
4508         Player *player = m_env->getPlayer(name);
4509         if(!player)
4510                 return;
4511
4512         if (player->peer_id == PEER_ID_INEXISTENT)
4513                 return;
4514
4515         SendChatMessage(player->peer_id, msg);
4516 }
4517
4518 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4519 {
4520         Player *player = m_env->getPlayer(playername);
4521
4522         if(!player)
4523         {
4524                 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4525                 return false;
4526         }
4527
4528         SendShowFormspecMessage(player->peer_id, formspec, formname);
4529         return true;
4530 }
4531
4532 u32 Server::hudAdd(Player *player, HudElement *form) {
4533         if (!player)
4534                 return -1;
4535
4536         u32 id = player->getFreeHudID();
4537         if (id < player->hud.size())
4538                 player->hud[id] = form;
4539         else
4540                 player->hud.push_back(form);
4541         
4542         SendHUDAdd(player->peer_id, id, form);
4543         return id;
4544 }
4545
4546 bool Server::hudRemove(Player *player, u32 id) {
4547         if (!player || id >= player->hud.size() || !player->hud[id])
4548                 return false;
4549
4550         delete player->hud[id];
4551         player->hud[id] = NULL;
4552         
4553         SendHUDRemove(player->peer_id, id);
4554         return true;
4555 }
4556
4557 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4558         if (!player)
4559                 return false;
4560
4561         SendHUDChange(player->peer_id, id, stat, data);
4562         return true;
4563 }
4564
4565 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4566         if (!player)
4567                 return false;
4568
4569         SendHUDSetFlags(player->peer_id, flags, mask);
4570         return true;
4571 }
4572
4573 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4574         if (!player)
4575                 return false;
4576         if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4577                 return false;
4578
4579         std::ostringstream os(std::ios::binary);
4580         writeS32(os, hotbar_itemcount);
4581         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4582         return true;
4583 }
4584
4585 void Server::hudSetHotbarImage(Player *player, std::string name) {
4586         if (!player)
4587                 return;
4588
4589         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4590 }
4591
4592 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4593         if (!player)
4594                 return;
4595
4596         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4597 }
4598
4599 bool Server::setLocalPlayerAnimations(Player *player, v2f animation_frames[4], f32 frame_speed)
4600 {
4601         if (!player)
4602                 return false;
4603
4604         SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4605         return true;
4606 }
4607
4608 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4609                 const std::string &type, const std::vector<std::string> &params)
4610 {
4611         if (!player)
4612                 return false;
4613
4614         SendSetSky(player->peer_id, bgcolor, type, params);
4615         return true;
4616 }
4617
4618 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4619                 float ratio)
4620 {
4621         if (!player)
4622                 return false;
4623
4624         SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4625         return true;
4626 }
4627
4628 void Server::notifyPlayers(const std::wstring &msg)
4629 {
4630         SendChatMessage(PEER_ID_INEXISTENT,msg);
4631 }
4632
4633 void Server::spawnParticle(const char *playername, v3f pos,
4634                 v3f velocity, v3f acceleration,
4635                 float expirationtime, float size, bool
4636                 collisiondetection, bool vertical, std::string texture)
4637 {
4638         Player *player = m_env->getPlayer(playername);
4639         if(!player)
4640                 return;
4641         SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4642                         expirationtime, size, collisiondetection, vertical, texture);
4643 }
4644
4645 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4646                 float expirationtime, float size,
4647                 bool collisiondetection, bool vertical, std::string texture)
4648 {
4649         SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4650                         expirationtime, size, collisiondetection, vertical, texture);
4651 }
4652
4653 u32 Server::addParticleSpawner(const char *playername,
4654                 u16 amount, float spawntime,
4655                 v3f minpos, v3f maxpos,
4656                 v3f minvel, v3f maxvel,
4657                 v3f minacc, v3f maxacc,
4658                 float minexptime, float maxexptime,
4659                 float minsize, float maxsize,
4660                 bool collisiondetection, bool vertical, std::string texture)
4661 {
4662         Player *player = m_env->getPlayer(playername);
4663         if(!player)
4664                 return -1;
4665
4666         u32 id = 0;
4667         for(;;) // look for unused particlespawner id
4668         {
4669                 id++;
4670                 if (std::find(m_particlespawner_ids.begin(),
4671                                 m_particlespawner_ids.end(), id)
4672                                 == m_particlespawner_ids.end())
4673                 {
4674                         m_particlespawner_ids.push_back(id);
4675                         break;
4676                 }
4677         }
4678
4679         SendAddParticleSpawner(player->peer_id, amount, spawntime,
4680                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4681                 minexptime, maxexptime, minsize, maxsize,
4682                 collisiondetection, vertical, texture, id);
4683
4684         return id;
4685 }
4686
4687 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4688                 v3f minpos, v3f maxpos,
4689                 v3f minvel, v3f maxvel,
4690                 v3f minacc, v3f maxacc,
4691                 float minexptime, float maxexptime,
4692                 float minsize, float maxsize,
4693                 bool collisiondetection, bool vertical, std::string texture)
4694 {
4695         u32 id = 0;
4696         for(;;) // look for unused particlespawner id
4697         {
4698                 id++;
4699                 if (std::find(m_particlespawner_ids.begin(),
4700                                 m_particlespawner_ids.end(), id)
4701                                 == m_particlespawner_ids.end())
4702                 {
4703                         m_particlespawner_ids.push_back(id);
4704                         break;
4705                 }
4706         }
4707
4708         SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4709                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4710                 minexptime, maxexptime, minsize, maxsize,
4711                 collisiondetection, vertical, texture, id);
4712
4713         return id;
4714 }
4715
4716 void Server::deleteParticleSpawner(const char *playername, u32 id)
4717 {
4718         Player *player = m_env->getPlayer(playername);
4719         if(!player)
4720                 return;
4721
4722         m_particlespawner_ids.erase(
4723                         std::remove(m_particlespawner_ids.begin(),
4724                         m_particlespawner_ids.end(), id),
4725                         m_particlespawner_ids.end());
4726         SendDeleteParticleSpawner(player->peer_id, id);
4727 }
4728
4729 void Server::deleteParticleSpawnerAll(u32 id)
4730 {
4731         m_particlespawner_ids.erase(
4732                         std::remove(m_particlespawner_ids.begin(),
4733                         m_particlespawner_ids.end(), id),
4734                         m_particlespawner_ids.end());
4735         SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4736 }
4737
4738 Inventory* Server::createDetachedInventory(const std::string &name)
4739 {
4740         if(m_detached_inventories.count(name) > 0){
4741                 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4742                 delete m_detached_inventories[name];
4743         } else {
4744                 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4745         }
4746         Inventory *inv = new Inventory(m_itemdef);
4747         assert(inv);
4748         m_detached_inventories[name] = inv;
4749         //TODO find a better way to do this
4750         sendDetachedInventory(name,PEER_ID_INEXISTENT);
4751         return inv;
4752 }
4753
4754 class BoolScopeSet
4755 {
4756 public:
4757         BoolScopeSet(bool *dst, bool val):
4758                 m_dst(dst)
4759         {
4760                 m_orig_state = *m_dst;
4761                 *m_dst = val;
4762         }
4763         ~BoolScopeSet()
4764         {
4765                 *m_dst = m_orig_state;
4766         }
4767 private:
4768         bool *m_dst;
4769         bool m_orig_state;
4770 };
4771
4772 // actions: time-reversed list
4773 // Return value: success/failure
4774 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4775                 std::list<std::string> *log)
4776 {
4777         infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4778         ServerMap *map = (ServerMap*)(&m_env->getMap());
4779         // Disable rollback report sink while reverting
4780         BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4781
4782         // Fail if no actions to handle
4783         if(actions.empty()){
4784                 log->push_back("Nothing to do.");
4785                 return false;
4786         }
4787
4788         int num_tried = 0;
4789         int num_failed = 0;
4790
4791         for(std::list<RollbackAction>::const_iterator
4792                         i = actions.begin();
4793                         i != actions.end(); i++)
4794         {
4795                 const RollbackAction &action = *i;
4796                 num_tried++;
4797                 bool success = action.applyRevert(map, this, this);
4798                 if(!success){
4799                         num_failed++;
4800                         std::ostringstream os;
4801                         os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4802                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4803                         if(log)
4804                                 log->push_back(os.str());
4805                 }else{
4806                         std::ostringstream os;
4807                         os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4808                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4809                         if(log)
4810                                 log->push_back(os.str());
4811                 }
4812         }
4813
4814         infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4815                         <<" failed"<<std::endl;
4816
4817         // Call it done if less than half failed
4818         return num_failed <= num_tried/2;
4819 }
4820
4821 // IGameDef interface
4822 // Under envlock
4823 IItemDefManager* Server::getItemDefManager()
4824 {
4825         return m_itemdef;
4826 }
4827 INodeDefManager* Server::getNodeDefManager()
4828 {
4829         return m_nodedef;
4830 }
4831 ICraftDefManager* Server::getCraftDefManager()
4832 {
4833         return m_craftdef;
4834 }
4835 ITextureSource* Server::getTextureSource()
4836 {
4837         return NULL;
4838 }
4839 IShaderSource* Server::getShaderSource()
4840 {
4841         return NULL;
4842 }
4843 u16 Server::allocateUnknownNodeId(const std::string &name)
4844 {
4845         return m_nodedef->allocateDummy(name);
4846 }
4847 ISoundManager* Server::getSoundManager()
4848 {
4849         return &dummySoundManager;
4850 }
4851 MtEventManager* Server::getEventManager()
4852 {
4853         return m_event;
4854 }
4855 IRollbackReportSink* Server::getRollbackReportSink()
4856 {
4857         if(!m_enable_rollback_recording)
4858                 return NULL;
4859         if(!m_rollback_sink_enabled)
4860                 return NULL;
4861         return m_rollback;
4862 }
4863
4864 IWritableItemDefManager* Server::getWritableItemDefManager()
4865 {
4866         return m_itemdef;
4867 }
4868 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4869 {
4870         return m_nodedef;
4871 }
4872 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4873 {
4874         return m_craftdef;
4875 }
4876
4877 const ModSpec* Server::getModSpec(const std::string &modname)
4878 {
4879         for(std::vector<ModSpec>::iterator i = m_mods.begin();
4880                         i != m_mods.end(); i++){
4881                 const ModSpec &mod = *i;
4882                 if(mod.name == modname)
4883                         return &mod;
4884         }
4885         return NULL;
4886 }
4887 void Server::getModNames(std::list<std::string> &modlist)
4888 {
4889         for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4890         {
4891                 modlist.push_back(i->name);
4892         }
4893 }
4894 std::string Server::getBuiltinLuaPath()
4895 {
4896         return porting::path_share + DIR_DELIM + "builtin";
4897 }
4898
4899 v3f findSpawnPos(ServerMap &map)
4900 {
4901         //return v3f(50,50,50)*BS;
4902
4903         v3s16 nodepos;
4904
4905 #if 0
4906         nodepos = v2s16(0,0);
4907         groundheight = 20;
4908 #endif
4909
4910 #if 1
4911         s16 water_level = map.getWaterLevel();
4912
4913         // Try to find a good place a few times
4914         for(s32 i=0; i<1000; i++)
4915         {
4916                 s32 range = 1 + i;
4917                 // We're going to try to throw the player to this position
4918                 v2s16 nodepos2d = v2s16(
4919                                 -range + (myrand() % (range * 2)),
4920                                 -range + (myrand() % (range * 2)));
4921
4922                 // Get ground height at point
4923                 s16 groundheight = map.findGroundLevel(nodepos2d);
4924                 if (groundheight <= water_level) // Don't go underwater
4925                         continue;
4926                 if (groundheight > water_level + 6) // Don't go to high places
4927                         continue;
4928
4929                 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4930                 bool is_good = false;
4931                 s32 air_count = 0;
4932                 for (s32 i = 0; i < 10; i++) {
4933                         v3s16 blockpos = getNodeBlockPos(nodepos);
4934                         map.emergeBlock(blockpos, true);
4935                         content_t c = map.getNodeNoEx(nodepos).getContent();
4936                         if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4937                                 air_count++;
4938                                 if (air_count >= 2){
4939                                         is_good = true;
4940                                         break;
4941                                 }
4942                         }
4943                         nodepos.Y++;
4944                 }
4945                 if(is_good){
4946                         // Found a good place
4947                         //infostream<<"Searched through "<<i<<" places."<<std::endl;
4948                         break;
4949                 }
4950         }
4951 #endif
4952
4953         return intToFloat(nodepos, BS);
4954 }
4955
4956 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4957 {
4958         RemotePlayer *player = NULL;
4959         bool newplayer = false;
4960
4961         /*
4962                 Try to get an existing player
4963         */
4964         player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4965
4966         // If player is already connected, cancel
4967         if(player != NULL && player->peer_id != 0)
4968         {
4969                 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4970                 return NULL;
4971         }
4972
4973         /*
4974                 If player with the wanted peer_id already exists, cancel.
4975         */
4976         if(m_env->getPlayer(peer_id) != NULL)
4977         {
4978                 infostream<<"emergePlayer(): Player with wrong name but same"
4979                                 " peer_id already exists"<<std::endl;
4980                 return NULL;
4981         }
4982
4983         /*
4984                 Create a new player if it doesn't exist yet
4985         */
4986         if(player == NULL)
4987         {
4988                 newplayer = true;
4989                 player = new RemotePlayer(this);
4990                 player->updateName(name);
4991
4992                 /* Set player position */
4993                 infostream<<"Server: Finding spawn place for player \""
4994                                 <<name<<"\""<<std::endl;
4995                 v3f pos = findSpawnPos(m_env->getServerMap());
4996                 player->setPosition(pos);
4997
4998                 /* Add player to environment */
4999                 m_env->addPlayer(player);
5000         }
5001
5002         /*
5003                 Create a new player active object
5004         */
5005         PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5006                         getPlayerEffectivePrivs(player->getName()),
5007                         isSingleplayer());
5008
5009         /* Clean up old HUD elements from previous sessions */
5010         player->hud.clear();
5011
5012         /* Add object to environment */
5013         m_env->addActiveObject(playersao);
5014
5015         /* Run scripts */
5016         if(newplayer)
5017                 m_script->on_newplayer(playersao);
5018
5019         return playersao;
5020 }
5021
5022 void dedicated_server_loop(Server &server, bool &kill)
5023 {
5024         DSTACK(__FUNCTION_NAME);
5025
5026         verbosestream<<"dedicated_server_loop()"<<std::endl;
5027
5028         IntervalLimiter m_profiler_interval;
5029
5030         for(;;)
5031         {
5032                 float steplen = g_settings->getFloat("dedicated_server_step");
5033                 // This is kind of a hack but can be done like this
5034                 // because server.step() is very light
5035                 {
5036                         ScopeProfiler sp(g_profiler, "dedicated server sleep");
5037                         sleep_ms((int)(steplen*1000.0));
5038                 }
5039                 server.step(steplen);
5040
5041                 if(server.getShutdownRequested() || kill)
5042                 {
5043                         infostream<<"Dedicated server quitting"<<std::endl;
5044 #if USE_CURL
5045                         if(g_settings->getBool("server_announce") == true)
5046                                 ServerList::sendAnnounce("delete");
5047 #endif
5048                         break;
5049                 }
5050
5051                 /*
5052                         Profiler
5053                 */
5054                 float profiler_print_interval =
5055                                 g_settings->getFloat("profiler_print_interval");
5056                 if(profiler_print_interval != 0)
5057                 {
5058                         if(m_profiler_interval.step(steplen, profiler_print_interval))
5059                         {
5060                                 infostream<<"Profiler:"<<std::endl;
5061                                 g_profiler->print(infostream);
5062                                 g_profiler->clear();
5063                         }
5064                 }
5065         }
5066 }
5067
5068