]> git.lizzy.rs Git - dragonfireclient.git/blob - src/server.cpp
Add missing ip address to player join log entry
[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         Address addr = getPeerAddress(player->peer_id);
1284         std::string ip_str = addr.serializeString();
1285         actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1286         /*
1287                 Print out action
1288         */
1289         {
1290                 std::vector<std::string> names = m_clients.getPlayerNames();
1291
1292                 actionstream<<player->getName() <<" joins game. List of players: ";
1293
1294                 for (std::vector<std::string>::iterator i = names.begin();
1295                                 i != names.end(); i++)
1296                 {
1297                         actionstream << *i << " ";
1298                 }
1299
1300                 actionstream<<std::endl;
1301         }
1302         return playersao;
1303 }
1304
1305 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1306 {
1307         DSTACK(__FUNCTION_NAME);
1308         // Environment is locked first.
1309         JMutexAutoLock envlock(m_env_mutex);
1310
1311         ScopeProfiler sp(g_profiler, "Server::ProcessData");
1312
1313         std::string addr_s;
1314         try{
1315                 Address address = getPeerAddress(peer_id);
1316                 addr_s = address.serializeString();
1317
1318                 // drop player if is ip is banned
1319                 if(m_banmanager->isIpBanned(addr_s)){
1320                         std::string ban_name = m_banmanager->getBanName(addr_s);
1321                         infostream<<"Server: A banned client tried to connect from "
1322                                         <<addr_s<<"; banned name was "
1323                                         <<ban_name<<std::endl;
1324                         // This actually doesn't seem to transfer to the client
1325                         DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1326                                         +narrow_to_wide(ban_name));
1327                         return;
1328                 }
1329         }
1330         catch(con::PeerNotFoundException &e)
1331         {
1332                 /*
1333                  * no peer for this packet found
1334                  * most common reason is peer timeout, e.g. peer didn't
1335                  * respond for some time, your server was overloaded or
1336                  * things like that.
1337                  */
1338                 infostream<<"Server::ProcessData(): Cancelling: peer "
1339                                 <<peer_id<<" not found"<<std::endl;
1340                 return;
1341         }
1342
1343         try
1344         {
1345
1346         if(datasize < 2)
1347                 return;
1348
1349         ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1350
1351         if(command == TOSERVER_INIT)
1352         {
1353                 // [0] u16 TOSERVER_INIT
1354                 // [2] u8 SER_FMT_VER_HIGHEST_READ
1355                 // [3] u8[20] player_name
1356                 // [23] u8[28] password <--- can be sent without this, from old versions
1357
1358                 if(datasize < 2+1+PLAYERNAME_SIZE)
1359                         return;
1360
1361                 RemoteClient* client = getClient(peer_id,Created);
1362
1363                 // If net_proto_version is set, this client has already been handled
1364                 if(client->getState() > Created)
1365                 {
1366                         verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1367                                         <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1368                         return;
1369                 }
1370
1371                 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1372                                 <<peer_id<<")"<<std::endl;
1373
1374                 // Do not allow multiple players in simple singleplayer mode.
1375                 // This isn't a perfect way to do it, but will suffice for now
1376                 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1377                         infostream<<"Server: Not allowing another client ("<<addr_s
1378                                         <<") to connect in simple singleplayer mode"<<std::endl;
1379                         DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1380                         return;
1381                 }
1382
1383                 // First byte after command is maximum supported
1384                 // serialization version
1385                 u8 client_max = data[2];
1386                 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1387                 // Use the highest version supported by both
1388                 u8 deployed = std::min(client_max, our_max);
1389                 // If it's lower than the lowest supported, give up.
1390                 if(deployed < SER_FMT_VER_LOWEST)
1391                         deployed = SER_FMT_VER_INVALID;
1392
1393                 if(deployed == SER_FMT_VER_INVALID)
1394                 {
1395                         actionstream<<"Server: A mismatched client tried to connect from "
1396                                         <<addr_s<<std::endl;
1397                         infostream<<"Server: Cannot negotiate serialization version with "
1398                                         <<addr_s<<std::endl;
1399                         DenyAccess(peer_id, std::wstring(
1400                                         L"Your client's version is not supported.\n"
1401                                         L"Server version is ")
1402                                         + narrow_to_wide(minetest_version_simple) + L"."
1403                         );
1404                         return;
1405                 }
1406
1407                 client->setPendingSerializationVersion(deployed);
1408
1409                 /*
1410                         Read and check network protocol version
1411                 */
1412
1413                 u16 min_net_proto_version = 0;
1414                 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1415                         min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1416
1417                 // Use same version as minimum and maximum if maximum version field
1418                 // doesn't exist (backwards compatibility)
1419                 u16 max_net_proto_version = min_net_proto_version;
1420                 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1421                         max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1422
1423                 // Start with client's maximum version
1424                 u16 net_proto_version = max_net_proto_version;
1425
1426                 // Figure out a working version if it is possible at all
1427                 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1428                                 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1429                 {
1430                         // If maximum is larger than our maximum, go with our maximum
1431                         if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1432                                 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1433                         // Else go with client's maximum
1434                         else
1435                                 net_proto_version = max_net_proto_version;
1436                 }
1437
1438                 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1439                                 <<min_net_proto_version<<", max: "<<max_net_proto_version
1440                                 <<", chosen: "<<net_proto_version<<std::endl;
1441
1442                 client->net_proto_version = net_proto_version;
1443
1444                 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1445                                 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1446                 {
1447                         actionstream<<"Server: A mismatched client tried to connect from "
1448                                         <<addr_s<<std::endl;
1449                         DenyAccess(peer_id, std::wstring(
1450                                         L"Your client's version is not supported.\n"
1451                                         L"Server version is ")
1452                                         + narrow_to_wide(minetest_version_simple) + L",\n"
1453                                         + L"server's PROTOCOL_VERSION is "
1454                                         + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1455                                         + L"..."
1456                                         + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1457                                         + L", client's PROTOCOL_VERSION is "
1458                                         + narrow_to_wide(itos(min_net_proto_version))
1459                                         + L"..."
1460                                         + narrow_to_wide(itos(max_net_proto_version))
1461                         );
1462                         return;
1463                 }
1464
1465                 if(g_settings->getBool("strict_protocol_version_checking"))
1466                 {
1467                         if(net_proto_version != LATEST_PROTOCOL_VERSION)
1468                         {
1469                                 actionstream<<"Server: A mismatched (strict) client tried to "
1470                                                 <<"connect from "<<addr_s<<std::endl;
1471                                 DenyAccess(peer_id, std::wstring(
1472                                                 L"Your client's version is not supported.\n"
1473                                                 L"Server version is ")
1474                                                 + narrow_to_wide(minetest_version_simple) + L",\n"
1475                                                 + L"server's PROTOCOL_VERSION (strict) is "
1476                                                 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1477                                                 + L", client's PROTOCOL_VERSION is "
1478                                                 + narrow_to_wide(itos(min_net_proto_version))
1479                                                 + L"..."
1480                                                 + narrow_to_wide(itos(max_net_proto_version))
1481                                 );
1482                                 return;
1483                         }
1484                 }
1485
1486                 /*
1487                         Set up player
1488                 */
1489
1490                 // Get player name
1491                 char playername[PLAYERNAME_SIZE];
1492                 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1493                 {
1494                         playername[i] = data[3+i];
1495                 }
1496                 playername[PLAYERNAME_SIZE-1] = 0;
1497
1498                 if(playername[0]=='\0')
1499                 {
1500                         actionstream<<"Server: Player with an empty name "
1501                                         <<"tried to connect from "<<addr_s<<std::endl;
1502                         DenyAccess(peer_id, L"Empty name");
1503                         return;
1504                 }
1505
1506                 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1507                 {
1508                         actionstream<<"Server: Player with an invalid name "
1509                                         <<"tried to connect from "<<addr_s<<std::endl;
1510                         DenyAccess(peer_id, L"Name contains unallowed characters");
1511                         return;
1512                 }
1513
1514                 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1515                 {
1516                         actionstream<<"Server: Player with the name \"singleplayer\" "
1517                                         <<"tried to connect from "<<addr_s<<std::endl;
1518                         DenyAccess(peer_id, L"Name is not allowed");
1519                         return;
1520                 }
1521
1522                 {
1523                         std::string reason;
1524                         if(m_script->on_prejoinplayer(playername, addr_s, reason))
1525                         {
1526                                 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1527                                                 <<"tried to connect from "<<addr_s<<" "
1528                                                 <<"but it was disallowed for the following reason: "
1529                                                 <<reason<<std::endl;
1530                                 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1531                                 return;
1532                         }
1533                 }
1534
1535                 infostream<<"Server: New connection: \""<<playername<<"\" from "
1536                                 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1537
1538                 // Get password
1539                 char given_password[PASSWORD_SIZE];
1540                 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1541                 {
1542                         // old version - assume blank password
1543                         given_password[0] = 0;
1544                 }
1545                 else
1546                 {
1547                         for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1548                         {
1549                                 given_password[i] = data[23+i];
1550                         }
1551                         given_password[PASSWORD_SIZE-1] = 0;
1552                 }
1553
1554                 if(!base64_is_valid(given_password)){
1555                         actionstream<<"Server: "<<playername
1556                                         <<" supplied invalid password hash"<<std::endl;
1557                         DenyAccess(peer_id, L"Invalid password hash");
1558                         return;
1559                 }
1560
1561                 // Enforce user limit.
1562                 // Don't enforce for users that have some admin right
1563                 if(m_clients.getClientIDs(Created).size() >= g_settings->getU16("max_users") &&
1564                                 !checkPriv(playername, "server") &&
1565                                 !checkPriv(playername, "ban") &&
1566                                 !checkPriv(playername, "privs") &&
1567                                 !checkPriv(playername, "password") &&
1568                                 playername != g_settings->get("name"))
1569                 {
1570                         actionstream<<"Server: "<<playername<<" tried to join, but there"
1571                                         <<" are already max_users="
1572                                         <<g_settings->getU16("max_users")<<" players."<<std::endl;
1573                         DenyAccess(peer_id, L"Too many users.");
1574                         return;
1575                 }
1576
1577                 std::string checkpwd; // Password hash to check against
1578                 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1579
1580                 // If no authentication info exists for user, create it
1581                 if(!has_auth){
1582                         if(!isSingleplayer() &&
1583                                         g_settings->getBool("disallow_empty_password") &&
1584                                         std::string(given_password) == ""){
1585                                 actionstream<<"Server: "<<playername
1586                                                 <<" supplied empty password"<<std::endl;
1587                                 DenyAccess(peer_id, L"Empty passwords are "
1588                                                 L"disallowed. Set a password and try again.");
1589                                 return;
1590                         }
1591                         std::wstring raw_default_password =
1592                                 narrow_to_wide(g_settings->get("default_password"));
1593                         std::string initial_password =
1594                                 translatePassword(playername, raw_default_password);
1595
1596                         // If default_password is empty, allow any initial password
1597                         if (raw_default_password.length() == 0)
1598                                 initial_password = given_password;
1599
1600                         m_script->createAuth(playername, initial_password);
1601                 }
1602
1603                 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1604
1605                 if(!has_auth){
1606                         actionstream<<"Server: "<<playername<<" cannot be authenticated"
1607                                         <<" (auth handler does not work?)"<<std::endl;
1608                         DenyAccess(peer_id, L"Not allowed to login");
1609                         return;
1610                 }
1611
1612                 if(given_password != checkpwd){
1613                         actionstream<<"Server: "<<playername<<" supplied wrong password"
1614                                         <<std::endl;
1615                         DenyAccess(peer_id, L"Wrong password");
1616                         return;
1617                 }
1618
1619                 RemotePlayer *player =
1620                                 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1621
1622                 if(player && player->peer_id != 0){
1623                         errorstream<<"Server: "<<playername<<": Failed to emerge player"
1624                                         <<" (player allocated to an another client)"<<std::endl;
1625                         DenyAccess(peer_id, L"Another client is connected with this "
1626                                         L"name. If your client closed unexpectedly, try again in "
1627                                         L"a minute.");
1628                 }
1629
1630                 m_clients.setPlayerName(peer_id,playername);
1631
1632                 /*
1633                         Answer with a TOCLIENT_INIT
1634                 */
1635                 {
1636                         SharedBuffer<u8> reply(2+1+6+8+4);
1637                         writeU16(&reply[0], TOCLIENT_INIT);
1638                         writeU8(&reply[2], deployed);
1639                         //send dummy pos for legacy reasons only
1640                         writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1641                         writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1642                         writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1643
1644                         // Send as reliable
1645                         m_clients.send(peer_id, 0, reply, true);
1646                         m_clients.event(peer_id, Init);
1647                 }
1648
1649                 return;
1650         }
1651
1652         if(command == TOSERVER_INIT2)
1653         {
1654
1655                 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1656                                 <<peer_id<<std::endl;
1657
1658                 m_clients.event(peer_id, GotInit2);
1659                 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1660
1661
1662                 ///// begin compatibility code
1663                 PlayerSAO* playersao = NULL;
1664                 if (protocol_version <= 22) {
1665                         playersao = StageTwoClientInit(peer_id);
1666
1667                         if (playersao == NULL) {
1668                                 errorstream
1669                                         << "TOSERVER_INIT2 stage 2 client init failed for peer "
1670                                         << peer_id << std::endl;
1671                                 return;
1672                         }
1673                 }
1674                 ///// end compatibility code
1675
1676                 /*
1677                         Send some initialization data
1678                 */
1679
1680                 infostream<<"Server: Sending content to "
1681                                 <<getPlayerName(peer_id)<<std::endl;
1682
1683                 // Send player movement settings
1684                 SendMovement(peer_id);
1685
1686                 // Send item definitions
1687                 SendItemDef(peer_id, m_itemdef, protocol_version);
1688
1689                 // Send node definitions
1690                 SendNodeDef(peer_id, m_nodedef, protocol_version);
1691
1692                 m_clients.event(peer_id, SetDefinitionsSent);
1693
1694                 // Send media announcement
1695                 sendMediaAnnouncement(peer_id);
1696
1697                 // Send detached inventories
1698                 sendDetachedInventories(peer_id);
1699
1700                 // Send time of day
1701                 u16 time = m_env->getTimeOfDay();
1702                 float time_speed = g_settings->getFloat("time_speed");
1703                 SendTimeOfDay(peer_id, time, time_speed);
1704
1705                 ///// begin compatibility code
1706                 if (protocol_version <= 22) {
1707                         m_clients.event(peer_id, SetClientReady);
1708                         m_script->on_joinplayer(playersao);
1709                 }
1710                 ///// end compatibility code
1711
1712                 // Warnings about protocol version can be issued here
1713                 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1714                 {
1715                         SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1716                                         L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1717                 }
1718
1719                 return;
1720         }
1721
1722         u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
1723         u16 peer_proto_ver = getClient(peer_id,InitDone)->net_proto_version;
1724
1725         if(peer_ser_ver == SER_FMT_VER_INVALID)
1726         {
1727                 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1728                                 " serialization format invalid or not initialized."
1729                                 " Skipping incoming command="<<command<<std::endl;
1730                 return;
1731         }
1732
1733         /* Handle commands relate to client startup */
1734         if(command == TOSERVER_REQUEST_MEDIA) {
1735                 std::string datastring((char*)&data[2], datasize-2);
1736                 std::istringstream is(datastring, std::ios_base::binary);
1737
1738                 std::list<std::string> tosend;
1739                 u16 numfiles = readU16(is);
1740
1741                 infostream<<"Sending "<<numfiles<<" files to "
1742                                 <<getPlayerName(peer_id)<<std::endl;
1743                 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1744
1745                 for(int i = 0; i < numfiles; i++) {
1746                         std::string name = deSerializeString(is);
1747                         tosend.push_back(name);
1748                         verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1749                                         <<name<<std::endl;
1750                 }
1751
1752                 sendRequestedMedia(peer_id, tosend);
1753                 return;
1754         }
1755         else if(command == TOSERVER_RECEIVED_MEDIA) {
1756                 return;
1757         }
1758         else if(command == TOSERVER_CLIENT_READY) {
1759                 // clients <= protocol version 22 did not send ready message,
1760                 // they're already initialized
1761                 assert(peer_proto_ver > 22);
1762
1763                 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1764
1765                 if (playersao == NULL) {
1766                         errorstream
1767                                 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer "
1768                                 << peer_id << std::endl;
1769                         return;
1770                 }
1771
1772
1773                 if(datasize < 2+8)
1774                         return;
1775
1776                 m_clients.setClientVersion(
1777                                 peer_id,
1778                                 data[2], data[3], data[4],
1779                                 std::string((char*) &data[8],(u16) data[6]));
1780
1781                 m_clients.event(peer_id, SetClientReady);
1782                 m_script->on_joinplayer(playersao);
1783
1784         }
1785         else if(command == TOSERVER_GOTBLOCKS)
1786         {
1787                 if(datasize < 2+1)
1788                         return;
1789
1790                 /*
1791                         [0] u16 command
1792                         [2] u8 count
1793                         [3] v3s16 pos_0
1794                         [3+6] v3s16 pos_1
1795                         ...
1796                 */
1797
1798                 u16 count = data[2];
1799                 for(u16 i=0; i<count; i++)
1800                 {
1801                         if((s16)datasize < 2+1+(i+1)*6)
1802                                 throw con::InvalidIncomingDataException
1803                                         ("GOTBLOCKS length is too short");
1804                         v3s16 p = readV3S16(&data[2+1+i*6]);
1805                         /*infostream<<"Server: GOTBLOCKS ("
1806                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1807                         RemoteClient *client = getClient(peer_id);
1808                         client->GotBlock(p);
1809                 }
1810                 return;
1811         }
1812
1813         if (m_clients.getClientState(peer_id) < Active)
1814         {
1815                 if (command == TOSERVER_PLAYERPOS) return;
1816
1817                 errorstream<<"Got packet command: " << command << " for peer id "
1818                                 << peer_id << " but client isn't active yet. Dropping packet "
1819                                 <<std::endl;
1820                 return;
1821         }
1822
1823         Player *player = m_env->getPlayer(peer_id);
1824         if(player == NULL){
1825                 errorstream<<"Server::ProcessData(): Cancelling: "
1826                                 "No player for peer_id="<<peer_id
1827                                 <<std::endl;
1828                 return;
1829         }
1830
1831         PlayerSAO *playersao = player->getPlayerSAO();
1832         if(playersao == NULL){
1833                 errorstream<<"Server::ProcessData(): Cancelling: "
1834                                 "No player object for peer_id="<<peer_id
1835                                 <<std::endl;
1836                 return;
1837         }
1838
1839         if(command == TOSERVER_PLAYERPOS)
1840         {
1841                 if(datasize < 2+12+12+4+4)
1842                         return;
1843
1844                 u32 start = 0;
1845                 v3s32 ps = readV3S32(&data[start+2]);
1846                 v3s32 ss = readV3S32(&data[start+2+12]);
1847                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1848                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1849                 u32 keyPressed = 0;
1850                 if(datasize >= 2+12+12+4+4+4)
1851                         keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1852                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1853                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1854                 pitch = wrapDegrees(pitch);
1855                 yaw = wrapDegrees(yaw);
1856
1857                 player->setPosition(position);
1858                 player->setSpeed(speed);
1859                 player->setPitch(pitch);
1860                 player->setYaw(yaw);
1861                 player->keyPressed=keyPressed;
1862                 player->control.up = (bool)(keyPressed&1);
1863                 player->control.down = (bool)(keyPressed&2);
1864                 player->control.left = (bool)(keyPressed&4);
1865                 player->control.right = (bool)(keyPressed&8);
1866                 player->control.jump = (bool)(keyPressed&16);
1867                 player->control.aux1 = (bool)(keyPressed&32);
1868                 player->control.sneak = (bool)(keyPressed&64);
1869                 player->control.LMB = (bool)(keyPressed&128);
1870                 player->control.RMB = (bool)(keyPressed&256);
1871
1872                 bool cheated = playersao->checkMovementCheat();
1873                 if(cheated){
1874                         // Call callbacks
1875                         m_script->on_cheat(playersao, "moved_too_fast");
1876                 }
1877
1878                 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1879                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1880                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1881         }
1882         else if(command == TOSERVER_DELETEDBLOCKS)
1883         {
1884                 if(datasize < 2+1)
1885                         return;
1886
1887                 /*
1888                         [0] u16 command
1889                         [2] u8 count
1890                         [3] v3s16 pos_0
1891                         [3+6] v3s16 pos_1
1892                         ...
1893                 */
1894
1895                 u16 count = data[2];
1896                 for(u16 i=0; i<count; i++)
1897                 {
1898                         if((s16)datasize < 2+1+(i+1)*6)
1899                                 throw con::InvalidIncomingDataException
1900                                         ("DELETEDBLOCKS length is too short");
1901                         v3s16 p = readV3S16(&data[2+1+i*6]);
1902                         /*infostream<<"Server: DELETEDBLOCKS ("
1903                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1904                         RemoteClient *client = getClient(peer_id);
1905                         client->SetBlockNotSent(p);
1906                 }
1907         }
1908         else if(command == TOSERVER_CLICK_OBJECT)
1909         {
1910                 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1911                 return;
1912         }
1913         else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1914         {
1915                 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1916                 return;
1917         }
1918         else if(command == TOSERVER_GROUND_ACTION)
1919         {
1920                 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1921                 return;
1922
1923         }
1924         else if(command == TOSERVER_RELEASE)
1925         {
1926                 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1927                 return;
1928         }
1929         else if(command == TOSERVER_SIGNTEXT)
1930         {
1931                 infostream<<"Server: SIGNTEXT not supported anymore"
1932                                 <<std::endl;
1933                 return;
1934         }
1935         else if(command == TOSERVER_SIGNNODETEXT)
1936         {
1937                 infostream<<"Server: SIGNNODETEXT not supported anymore"
1938                                 <<std::endl;
1939                 return;
1940         }
1941         else if(command == TOSERVER_INVENTORY_ACTION)
1942         {
1943                 // Strip command and create a stream
1944                 std::string datastring((char*)&data[2], datasize-2);
1945                 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1946                 std::istringstream is(datastring, std::ios_base::binary);
1947                 // Create an action
1948                 InventoryAction *a = InventoryAction::deSerialize(is);
1949                 if(a == NULL)
1950                 {
1951                         infostream<<"TOSERVER_INVENTORY_ACTION: "
1952                                         <<"InventoryAction::deSerialize() returned NULL"
1953                                         <<std::endl;
1954                         return;
1955                 }
1956
1957                 // If something goes wrong, this player is to blame
1958                 RollbackScopeActor rollback_scope(m_rollback,
1959                                 std::string("player:")+player->getName());
1960
1961                 /*
1962                         Note: Always set inventory not sent, to repair cases
1963                         where the client made a bad prediction.
1964                 */
1965
1966                 /*
1967                         Handle restrictions and special cases of the move action
1968                 */
1969                 if(a->getType() == IACTION_MOVE)
1970                 {
1971                         IMoveAction *ma = (IMoveAction*)a;
1972
1973                         ma->from_inv.applyCurrentPlayer(player->getName());
1974                         ma->to_inv.applyCurrentPlayer(player->getName());
1975
1976                         setInventoryModified(ma->from_inv);
1977                         setInventoryModified(ma->to_inv);
1978
1979                         bool from_inv_is_current_player =
1980                                 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1981                                 (ma->from_inv.name == player->getName());
1982
1983                         bool to_inv_is_current_player =
1984                                 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1985                                 (ma->to_inv.name == player->getName());
1986
1987                         /*
1988                                 Disable moving items out of craftpreview
1989                         */
1990                         if(ma->from_list == "craftpreview")
1991                         {
1992                                 infostream<<"Ignoring IMoveAction from "
1993                                                 <<(ma->from_inv.dump())<<":"<<ma->from_list
1994                                                 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1995                                                 <<" because src is "<<ma->from_list<<std::endl;
1996                                 delete a;
1997                                 return;
1998                         }
1999
2000                         /*
2001                                 Disable moving items into craftresult and craftpreview
2002                         */
2003                         if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2004                         {
2005                                 infostream<<"Ignoring IMoveAction from "
2006                                                 <<(ma->from_inv.dump())<<":"<<ma->from_list
2007                                                 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2008                                                 <<" because dst is "<<ma->to_list<<std::endl;
2009                                 delete a;
2010                                 return;
2011                         }
2012
2013                         // Disallow moving items in elsewhere than player's inventory
2014                         // if not allowed to interact
2015                         if(!checkPriv(player->getName(), "interact") &&
2016                                         (!from_inv_is_current_player ||
2017                                         !to_inv_is_current_player))
2018                         {
2019                                 infostream<<"Cannot move outside of player's inventory: "
2020                                                 <<"No interact privilege"<<std::endl;
2021                                 delete a;
2022                                 return;
2023                         }
2024                 }
2025                 /*
2026                         Handle restrictions and special cases of the drop action
2027                 */
2028                 else if(a->getType() == IACTION_DROP)
2029                 {
2030                         IDropAction *da = (IDropAction*)a;
2031
2032                         da->from_inv.applyCurrentPlayer(player->getName());
2033
2034                         setInventoryModified(da->from_inv);
2035
2036                         /*
2037                                 Disable dropping items out of craftpreview
2038                         */
2039                         if(da->from_list == "craftpreview")
2040                         {
2041                                 infostream<<"Ignoring IDropAction from "
2042                                                 <<(da->from_inv.dump())<<":"<<da->from_list
2043                                                 <<" because src is "<<da->from_list<<std::endl;
2044                                 delete a;
2045                                 return;
2046                         }
2047
2048                         // Disallow dropping items if not allowed to interact
2049                         if(!checkPriv(player->getName(), "interact"))
2050                         {
2051                                 delete a;
2052                                 return;
2053                         }
2054                 }
2055                 /*
2056                         Handle restrictions and special cases of the craft action
2057                 */
2058                 else if(a->getType() == IACTION_CRAFT)
2059                 {
2060                         ICraftAction *ca = (ICraftAction*)a;
2061
2062                         ca->craft_inv.applyCurrentPlayer(player->getName());
2063
2064                         setInventoryModified(ca->craft_inv);
2065
2066                         //bool craft_inv_is_current_player =
2067                         //      (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2068                         //      (ca->craft_inv.name == player->getName());
2069
2070                         // Disallow crafting if not allowed to interact
2071                         if(!checkPriv(player->getName(), "interact"))
2072                         {
2073                                 infostream<<"Cannot craft: "
2074                                                 <<"No interact privilege"<<std::endl;
2075                                 delete a;
2076                                 return;
2077                         }
2078                 }
2079
2080                 // Do the action
2081                 a->apply(this, playersao, this);
2082                 // Eat the action
2083                 delete a;
2084         }
2085         else if(command == TOSERVER_CHAT_MESSAGE)
2086         {
2087                 /*
2088                         u16 command
2089                         u16 length
2090                         wstring message
2091                 */
2092                 u8 buf[6];
2093                 std::string datastring((char*)&data[2], datasize-2);
2094                 std::istringstream is(datastring, std::ios_base::binary);
2095
2096                 // Read stuff
2097                 is.read((char*)buf, 2);
2098                 u16 len = readU16(buf);
2099
2100                 std::wstring message;
2101                 for(u16 i=0; i<len; i++)
2102                 {
2103                         is.read((char*)buf, 2);
2104                         message += (wchar_t)readU16(buf);
2105                 }
2106
2107                 // If something goes wrong, this player is to blame
2108                 RollbackScopeActor rollback_scope(m_rollback,
2109                                 std::string("player:")+player->getName());
2110
2111                 // Get player name of this client
2112                 std::wstring name = narrow_to_wide(player->getName());
2113
2114                 // Run script hook
2115                 bool ate = m_script->on_chat_message(player->getName(),
2116                                 wide_to_narrow(message));
2117                 // If script ate the message, don't proceed
2118                 if(ate)
2119                         return;
2120
2121                 // Line to send to players
2122                 std::wstring line;
2123                 // Whether to send to the player that sent the line
2124                 bool send_to_sender_only = false;
2125
2126                 // Commands are implemented in Lua, so only catch invalid
2127                 // commands that were not "eaten" and send an error back
2128                 if(message[0] == L'/')
2129                 {
2130                         message = message.substr(1);
2131                         send_to_sender_only = true;
2132                         if(message.length() == 0)
2133                                 line += L"-!- Empty command";
2134                         else
2135                                 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2136                 }
2137                 else
2138                 {
2139                         if(checkPriv(player->getName(), "shout")){
2140                                 line += L"<";
2141                                 line += name;
2142                                 line += L"> ";
2143                                 line += message;
2144                         } else {
2145                                 line += L"-!- You don't have permission to shout.";
2146                                 send_to_sender_only = true;
2147                         }
2148                 }
2149
2150                 if(line != L"")
2151                 {
2152                         /*
2153                                 Send the message to sender
2154                         */
2155                         if (send_to_sender_only)
2156                         {
2157                                 SendChatMessage(peer_id, line);
2158                         }
2159                         /*
2160                                 Send the message to others
2161                         */
2162                         else
2163                         {
2164                                 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2165
2166                                 std::list<u16> clients = m_clients.getClientIDs();
2167
2168                                 for(std::list<u16>::iterator
2169                                         i = clients.begin();
2170                                         i != clients.end(); ++i)
2171                                 {
2172                                         if (*i != peer_id)
2173                                                 SendChatMessage(*i, line);
2174                                 }
2175                         }
2176                 }
2177         }
2178         else if(command == TOSERVER_DAMAGE)
2179         {
2180                 std::string datastring((char*)&data[2], datasize-2);
2181                 std::istringstream is(datastring, std::ios_base::binary);
2182                 u8 damage = readU8(is);
2183
2184                 if(g_settings->getBool("enable_damage"))
2185                 {
2186                         actionstream<<player->getName()<<" damaged by "
2187                                         <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2188                                         <<std::endl;
2189
2190                         playersao->setHP(playersao->getHP() - damage);
2191
2192                         if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2193                                 DiePlayer(peer_id);
2194
2195                         if(playersao->m_hp_not_sent)
2196                                 SendPlayerHP(peer_id);
2197                 }
2198         }
2199         else if(command == TOSERVER_BREATH)
2200         {
2201                 std::string datastring((char*)&data[2], datasize-2);
2202                 std::istringstream is(datastring, std::ios_base::binary);
2203                 u16 breath = readU16(is);
2204                 playersao->setBreath(breath);
2205         }
2206         else if(command == TOSERVER_PASSWORD)
2207         {
2208                 /*
2209                         [0] u16 TOSERVER_PASSWORD
2210                         [2] u8[28] old password
2211                         [30] u8[28] new password
2212                 */
2213
2214                 if(datasize != 2+PASSWORD_SIZE*2)
2215                         return;
2216                 /*char password[PASSWORD_SIZE];
2217                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2218                         password[i] = data[2+i];
2219                 password[PASSWORD_SIZE-1] = 0;*/
2220                 std::string oldpwd;
2221                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2222                 {
2223                         char c = data[2+i];
2224                         if(c == 0)
2225                                 break;
2226                         oldpwd += c;
2227                 }
2228                 std::string newpwd;
2229                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2230                 {
2231                         char c = data[2+PASSWORD_SIZE+i];
2232                         if(c == 0)
2233                                 break;
2234                         newpwd += c;
2235                 }
2236
2237                 if(!base64_is_valid(newpwd)){
2238                         infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2239                         // Wrong old password supplied!!
2240                         SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2241                         return;
2242                 }
2243
2244                 infostream<<"Server: Client requests a password change from "
2245                                 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2246
2247                 std::string playername = player->getName();
2248
2249                 std::string checkpwd;
2250                 m_script->getAuth(playername, &checkpwd, NULL);
2251
2252                 if(oldpwd != checkpwd)
2253                 {
2254                         infostream<<"Server: invalid old password"<<std::endl;
2255                         // Wrong old password supplied!!
2256                         SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2257                         return;
2258                 }
2259
2260                 bool success = m_script->setPassword(playername, newpwd);
2261                 if(success){
2262                         actionstream<<player->getName()<<" changes password"<<std::endl;
2263                         SendChatMessage(peer_id, L"Password change successful.");
2264                 } else {
2265                         actionstream<<player->getName()<<" tries to change password but "
2266                                         <<"it fails"<<std::endl;
2267                         SendChatMessage(peer_id, L"Password change failed or inavailable.");
2268                 }
2269         }
2270         else if(command == TOSERVER_PLAYERITEM)
2271         {
2272                 if (datasize < 2+2)
2273                         return;
2274
2275                 u16 item = readU16(&data[2]);
2276                 playersao->setWieldIndex(item);
2277         }
2278         else if(command == TOSERVER_RESPAWN)
2279         {
2280                 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2281                         return;
2282
2283                 RespawnPlayer(peer_id);
2284
2285                 actionstream<<player->getName()<<" respawns at "
2286                                 <<PP(player->getPosition()/BS)<<std::endl;
2287
2288                 // ActiveObject is added to environment in AsyncRunStep after
2289                 // the previous addition has been succesfully removed
2290         }
2291         else if(command == TOSERVER_INTERACT)
2292         {
2293                 std::string datastring((char*)&data[2], datasize-2);
2294                 std::istringstream is(datastring, std::ios_base::binary);
2295
2296                 /*
2297                         [0] u16 command
2298                         [2] u8 action
2299                         [3] u16 item
2300                         [5] u32 length of the next item
2301                         [9] serialized PointedThing
2302                         actions:
2303                         0: start digging (from undersurface) or use
2304                         1: stop digging (all parameters ignored)
2305                         2: digging completed
2306                         3: place block or item (to abovesurface)
2307                         4: use item
2308                 */
2309                 u8 action = readU8(is);
2310                 u16 item_i = readU16(is);
2311                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2312                 PointedThing pointed;
2313                 pointed.deSerialize(tmp_is);
2314
2315                 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2316                                 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2317
2318                 if(player->hp == 0)
2319                 {
2320                         verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2321                                 <<" tried to interact, but is dead!"<<std::endl;
2322                         return;
2323                 }
2324
2325                 v3f player_pos = playersao->getLastGoodPosition();
2326
2327                 // Update wielded item
2328                 playersao->setWieldIndex(item_i);
2329
2330                 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2331                 v3s16 p_under = pointed.node_undersurface;
2332                 v3s16 p_above = pointed.node_abovesurface;
2333
2334                 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2335                 ServerActiveObject *pointed_object = NULL;
2336                 if(pointed.type == POINTEDTHING_OBJECT)
2337                 {
2338                         pointed_object = m_env->getActiveObject(pointed.object_id);
2339                         if(pointed_object == NULL)
2340                         {
2341                                 verbosestream<<"TOSERVER_INTERACT: "
2342                                         "pointed object is NULL"<<std::endl;
2343                                 return;
2344                         }
2345
2346                 }
2347
2348                 v3f pointed_pos_under = player_pos;
2349                 v3f pointed_pos_above = player_pos;
2350                 if(pointed.type == POINTEDTHING_NODE)
2351                 {
2352                         pointed_pos_under = intToFloat(p_under, BS);
2353                         pointed_pos_above = intToFloat(p_above, BS);
2354                 }
2355                 else if(pointed.type == POINTEDTHING_OBJECT)
2356                 {
2357                         pointed_pos_under = pointed_object->getBasePosition();
2358                         pointed_pos_above = pointed_pos_under;
2359                 }
2360
2361                 /*
2362                         Check that target is reasonably close
2363                         (only when digging or placing things)
2364                 */
2365                 if(action == 0 || action == 2 || action == 3)
2366                 {
2367                         float d = player_pos.getDistanceFrom(pointed_pos_under);
2368                         float max_d = BS * 14; // Just some large enough value
2369                         if(d > max_d){
2370                                 actionstream<<"Player "<<player->getName()
2371                                                 <<" tried to access "<<pointed.dump()
2372                                                 <<" from too far: "
2373                                                 <<"d="<<d<<", max_d="<<max_d
2374                                                 <<". ignoring."<<std::endl;
2375                                 // Re-send block to revert change on client-side
2376                                 RemoteClient *client = getClient(peer_id);
2377                                 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2378                                 client->SetBlockNotSent(blockpos);
2379                                 // Call callbacks
2380                                 m_script->on_cheat(playersao, "interacted_too_far");
2381                                 // Do nothing else
2382                                 return;
2383                         }
2384                 }
2385
2386                 /*
2387                         Make sure the player is allowed to do it
2388                 */
2389                 if(!checkPriv(player->getName(), "interact"))
2390                 {
2391                         actionstream<<player->getName()<<" attempted to interact with "
2392                                         <<pointed.dump()<<" without 'interact' privilege"
2393                                         <<std::endl;
2394                         // Re-send block to revert change on client-side
2395                         RemoteClient *client = getClient(peer_id);
2396                         // Digging completed -> under
2397                         if(action == 2){
2398                                 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2399                                 client->SetBlockNotSent(blockpos);
2400                         }
2401                         // Placement -> above
2402                         if(action == 3){
2403                                 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2404                                 client->SetBlockNotSent(blockpos);
2405                         }
2406                         return;
2407                 }
2408
2409                 /*
2410                         If something goes wrong, this player is to blame
2411                 */
2412                 RollbackScopeActor rollback_scope(m_rollback,
2413                                 std::string("player:")+player->getName());
2414
2415                 /*
2416                         0: start digging or punch object
2417                 */
2418                 if(action == 0)
2419                 {
2420                         if(pointed.type == POINTEDTHING_NODE)
2421                         {
2422                                 /*
2423                                         NOTE: This can be used in the future to check if
2424                                         somebody is cheating, by checking the timing.
2425                                 */
2426                                 MapNode n(CONTENT_IGNORE);
2427                                 try
2428                                 {
2429                                         n = m_env->getMap().getNode(p_under);
2430                                 }
2431                                 catch(InvalidPositionException &e)
2432                                 {
2433                                         infostream<<"Server: Not punching: Node not found."
2434                                                         <<" Adding block to emerge queue."
2435                                                         <<std::endl;
2436                                         m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2437                                 }
2438                                 if(n.getContent() != CONTENT_IGNORE)
2439                                         m_script->node_on_punch(p_under, n, playersao, pointed);
2440                                 // Cheat prevention
2441                                 playersao->noCheatDigStart(p_under);
2442                         }
2443                         else if(pointed.type == POINTEDTHING_OBJECT)
2444                         {
2445                                 // Skip if object has been removed
2446                                 if(pointed_object->m_removed)
2447                                         return;
2448
2449                                 actionstream<<player->getName()<<" punches object "
2450                                                 <<pointed.object_id<<": "
2451                                                 <<pointed_object->getDescription()<<std::endl;
2452
2453                                 ItemStack punchitem = playersao->getWieldedItem();
2454                                 ToolCapabilities toolcap =
2455                                                 punchitem.getToolCapabilities(m_itemdef);
2456                                 v3f dir = (pointed_object->getBasePosition() -
2457                                                 (player->getPosition() + player->getEyeOffset())
2458                                                         ).normalize();
2459                                 float time_from_last_punch =
2460                                         playersao->resetTimeFromLastPunch();
2461                                 pointed_object->punch(dir, &toolcap, playersao,
2462                                                 time_from_last_punch);
2463                         }
2464
2465                 } // action == 0
2466
2467                 /*
2468                         1: stop digging
2469                 */
2470                 else if(action == 1)
2471                 {
2472                 } // action == 1
2473
2474                 /*
2475                         2: Digging completed
2476                 */
2477                 else if(action == 2)
2478                 {
2479                         // Only digging of nodes
2480                         if(pointed.type == POINTEDTHING_NODE)
2481                         {
2482                                 MapNode n(CONTENT_IGNORE);
2483                                 try
2484                                 {
2485                                         n = m_env->getMap().getNode(p_under);
2486                                 }
2487                                 catch(InvalidPositionException &e)
2488                                 {
2489                                         infostream<<"Server: Not finishing digging: Node not found."
2490                                                         <<" Adding block to emerge queue."
2491                                                         <<std::endl;
2492                                         m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2493                                 }
2494
2495                                 /* Cheat prevention */
2496                                 bool is_valid_dig = true;
2497                                 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2498                                 {
2499                                         v3s16 nocheat_p = playersao->getNoCheatDigPos();
2500                                         float nocheat_t = playersao->getNoCheatDigTime();
2501                                         playersao->noCheatDigEnd();
2502                                         // If player didn't start digging this, ignore dig
2503                                         if(nocheat_p != p_under){
2504                                                 infostream<<"Server: NoCheat: "<<player->getName()
2505                                                                 <<" started digging "
2506                                                                 <<PP(nocheat_p)<<" and completed digging "
2507                                                                 <<PP(p_under)<<"; not digging."<<std::endl;
2508                                                 is_valid_dig = false;
2509                                                 // Call callbacks
2510                                                 m_script->on_cheat(playersao, "finished_unknown_dig");
2511                                         }
2512                                         // Get player's wielded item
2513                                         ItemStack playeritem;
2514                                         InventoryList *mlist = playersao->getInventory()->getList("main");
2515                                         if(mlist != NULL)
2516                                                 playeritem = mlist->getItem(playersao->getWieldIndex());
2517                                         ToolCapabilities playeritem_toolcap =
2518                                                         playeritem.getToolCapabilities(m_itemdef);
2519                                         // Get diggability and expected digging time
2520                                         DigParams params = getDigParams(m_nodedef->get(n).groups,
2521                                                         &playeritem_toolcap);
2522                                         // If can't dig, try hand
2523                                         if(!params.diggable){
2524                                                 const ItemDefinition &hand = m_itemdef->get("");
2525                                                 const ToolCapabilities *tp = hand.tool_capabilities;
2526                                                 if(tp)
2527                                                         params = getDigParams(m_nodedef->get(n).groups, tp);
2528                                         }
2529                                         // If can't dig, ignore dig
2530                                         if(!params.diggable){
2531                                                 infostream<<"Server: NoCheat: "<<player->getName()
2532                                                                 <<" completed digging "<<PP(p_under)
2533                                                                 <<", which is not diggable with tool. not digging."
2534                                                                 <<std::endl;
2535                                                 is_valid_dig = false;
2536                                                 // Call callbacks
2537                                                 m_script->on_cheat(playersao, "dug_unbreakable");
2538                                         }
2539                                         // Check digging time
2540                                         // If already invalidated, we don't have to
2541                                         if(!is_valid_dig){
2542                                                 // Well not our problem then
2543                                         }
2544                                         // Clean and long dig
2545                                         else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2546                                                 // All is good, but grab time from pool; don't care if
2547                                                 // it's actually available
2548                                                 playersao->getDigPool().grab(params.time);
2549                                         }
2550                                         // Short or laggy dig
2551                                         // Try getting the time from pool
2552                                         else if(playersao->getDigPool().grab(params.time)){
2553                                                 // All is good
2554                                         }
2555                                         // Dig not possible
2556                                         else{
2557                                                 infostream<<"Server: NoCheat: "<<player->getName()
2558                                                                 <<" completed digging "<<PP(p_under)
2559                                                                 <<"too fast; not digging."<<std::endl;
2560                                                 is_valid_dig = false;
2561                                                 // Call callbacks
2562                                                 m_script->on_cheat(playersao, "dug_too_fast");
2563                                         }
2564                                 }
2565
2566                                 /* Actually dig node */
2567
2568                                 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2569                                         m_script->node_on_dig(p_under, n, playersao);
2570
2571                                 // Send unusual result (that is, node not being removed)
2572                                 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2573                                 {
2574                                         // Re-send block to revert change on client-side
2575                                         RemoteClient *client = getClient(peer_id);
2576                                         v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2577                                         client->SetBlockNotSent(blockpos);
2578                                 }
2579                         }
2580                 } // action == 2
2581
2582                 /*
2583                         3: place block or right-click object
2584                 */
2585                 else if(action == 3)
2586                 {
2587                         ItemStack item = playersao->getWieldedItem();
2588
2589                         // Reset build time counter
2590                         if(pointed.type == POINTEDTHING_NODE &&
2591                                         item.getDefinition(m_itemdef).type == ITEM_NODE)
2592                                 getClient(peer_id)->m_time_from_building = 0.0;
2593
2594                         if(pointed.type == POINTEDTHING_OBJECT)
2595                         {
2596                                 // Right click object
2597
2598                                 // Skip if object has been removed
2599                                 if(pointed_object->m_removed)
2600                                         return;
2601
2602                                 actionstream<<player->getName()<<" right-clicks object "
2603                                                 <<pointed.object_id<<": "
2604                                                 <<pointed_object->getDescription()<<std::endl;
2605
2606                                 // Do stuff
2607                                 pointed_object->rightClick(playersao);
2608                         }
2609                         else if(m_script->item_OnPlace(
2610                                         item, playersao, pointed))
2611                         {
2612                                 // Placement was handled in lua
2613
2614                                 // Apply returned ItemStack
2615                                 playersao->setWieldedItem(item);
2616                         }
2617
2618                         // If item has node placement prediction, always send the
2619                         // blocks to make sure the client knows what exactly happened
2620                         if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2621                                 RemoteClient *client = getClient(peer_id);
2622                                 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2623                                 client->SetBlockNotSent(blockpos);
2624                                 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2625                                 if(blockpos2 != blockpos){
2626                                         client->SetBlockNotSent(blockpos2);
2627                                 }
2628                         }
2629                 } // action == 3
2630
2631                 /*
2632                         4: use
2633                 */
2634                 else if(action == 4)
2635                 {
2636                         ItemStack item = playersao->getWieldedItem();
2637
2638                         actionstream<<player->getName()<<" uses "<<item.name
2639                                         <<", pointing at "<<pointed.dump()<<std::endl;
2640
2641                         if(m_script->item_OnUse(
2642                                         item, playersao, pointed))
2643                         {
2644                                 // Apply returned ItemStack
2645                                 playersao->setWieldedItem(item);
2646                         }
2647
2648                 } // action == 4
2649                 
2650
2651                 /*
2652                         Catch invalid actions
2653                 */
2654                 else
2655                 {
2656                         infostream<<"WARNING: Server: Invalid action "
2657                                         <<action<<std::endl;
2658                 }
2659         }
2660         else if(command == TOSERVER_REMOVED_SOUNDS)
2661         {
2662                 std::string datastring((char*)&data[2], datasize-2);
2663                 std::istringstream is(datastring, std::ios_base::binary);
2664
2665                 int num = readU16(is);
2666                 for(int k=0; k<num; k++){
2667                         s32 id = readS32(is);
2668                         std::map<s32, ServerPlayingSound>::iterator i =
2669                                         m_playing_sounds.find(id);
2670                         if(i == m_playing_sounds.end())
2671                                 continue;
2672                         ServerPlayingSound &psound = i->second;
2673                         psound.clients.erase(peer_id);
2674                         if(psound.clients.size() == 0)
2675                                 m_playing_sounds.erase(i++);
2676                 }
2677         }
2678         else if(command == TOSERVER_NODEMETA_FIELDS)
2679         {
2680                 std::string datastring((char*)&data[2], datasize-2);
2681                 std::istringstream is(datastring, std::ios_base::binary);
2682
2683                 v3s16 p = readV3S16(is);
2684                 std::string formname = deSerializeString(is);
2685                 int num = readU16(is);
2686                 std::map<std::string, std::string> fields;
2687                 for(int k=0; k<num; k++){
2688                         std::string fieldname = deSerializeString(is);
2689                         std::string fieldvalue = deSerializeLongString(is);
2690                         fields[fieldname] = fieldvalue;
2691                 }
2692
2693                 // If something goes wrong, this player is to blame
2694                 RollbackScopeActor rollback_scope(m_rollback,
2695                                 std::string("player:")+player->getName());
2696
2697                 // Check the target node for rollback data; leave others unnoticed
2698                 RollbackNode rn_old(&m_env->getMap(), p, this);
2699
2700                 m_script->node_on_receive_fields(p, formname, fields,playersao);
2701
2702                 // Report rollback data
2703                 RollbackNode rn_new(&m_env->getMap(), p, this);
2704                 if(rollback() && rn_new != rn_old){
2705                         RollbackAction action;
2706                         action.setSetNode(p, rn_old, rn_new);
2707                         rollback()->reportAction(action);
2708                 }
2709         }
2710         else if(command == TOSERVER_INVENTORY_FIELDS)
2711         {
2712                 std::string datastring((char*)&data[2], datasize-2);
2713                 std::istringstream is(datastring, std::ios_base::binary);
2714
2715                 std::string formname = deSerializeString(is);
2716                 int num = readU16(is);
2717                 std::map<std::string, std::string> fields;
2718                 for(int k=0; k<num; k++){
2719                         std::string fieldname = deSerializeString(is);
2720                         std::string fieldvalue = deSerializeLongString(is);
2721                         fields[fieldname] = fieldvalue;
2722                 }
2723
2724                 m_script->on_playerReceiveFields(playersao, formname, fields);
2725         }
2726         else
2727         {
2728                 infostream<<"Server::ProcessData(): Ignoring "
2729                                 "unknown command "<<command<<std::endl;
2730         }
2731
2732         } //try
2733         catch(SendFailedException &e)
2734         {
2735                 errorstream<<"Server::ProcessData(): SendFailedException: "
2736                                 <<"what="<<e.what()
2737                                 <<std::endl;
2738         }
2739 }
2740
2741 void Server::setTimeOfDay(u32 time)
2742 {
2743         m_env->setTimeOfDay(time);
2744         m_time_of_day_send_timer = 0;
2745 }
2746
2747 void Server::onMapEditEvent(MapEditEvent *event)
2748 {
2749         //infostream<<"Server::onMapEditEvent()"<<std::endl;
2750         if(m_ignore_map_edit_events)
2751                 return;
2752         if(m_ignore_map_edit_events_area.contains(event->getArea()))
2753                 return;
2754         MapEditEvent *e = event->clone();
2755         m_unsent_map_edit_queue.push_back(e);
2756 }
2757
2758 Inventory* Server::getInventory(const InventoryLocation &loc)
2759 {
2760         switch(loc.type){
2761         case InventoryLocation::UNDEFINED:
2762         {}
2763         break;
2764         case InventoryLocation::CURRENT_PLAYER:
2765         {}
2766         break;
2767         case InventoryLocation::PLAYER:
2768         {
2769                 Player *player = m_env->getPlayer(loc.name.c_str());
2770                 if(!player)
2771                         return NULL;
2772                 PlayerSAO *playersao = player->getPlayerSAO();
2773                 if(!playersao)
2774                         return NULL;
2775                 return playersao->getInventory();
2776         }
2777         break;
2778         case InventoryLocation::NODEMETA:
2779         {
2780                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2781                 if(!meta)
2782                         return NULL;
2783                 return meta->getInventory();
2784         }
2785         break;
2786         case InventoryLocation::DETACHED:
2787         {
2788                 if(m_detached_inventories.count(loc.name) == 0)
2789                         return NULL;
2790                 return m_detached_inventories[loc.name];
2791         }
2792         break;
2793         default:
2794                 assert(0);
2795         }
2796         return NULL;
2797 }
2798 void Server::setInventoryModified(const InventoryLocation &loc)
2799 {
2800         switch(loc.type){
2801         case InventoryLocation::UNDEFINED:
2802         {}
2803         break;
2804         case InventoryLocation::PLAYER:
2805         {
2806                 Player *player = m_env->getPlayer(loc.name.c_str());
2807                 if(!player)
2808                         return;
2809                 PlayerSAO *playersao = player->getPlayerSAO();
2810                 if(!playersao)
2811                         return;
2812                 playersao->m_inventory_not_sent = true;
2813                 playersao->m_wielded_item_not_sent = true;
2814         }
2815         break;
2816         case InventoryLocation::NODEMETA:
2817         {
2818                 v3s16 blockpos = getNodeBlockPos(loc.p);
2819
2820                 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2821                 if(block)
2822                         block->raiseModified(MOD_STATE_WRITE_NEEDED);
2823
2824                 setBlockNotSent(blockpos);
2825         }
2826         break;
2827         case InventoryLocation::DETACHED:
2828         {
2829                 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2830         }
2831         break;
2832         default:
2833                 assert(0);
2834         }
2835 }
2836
2837 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2838 {
2839         std::list<u16> clients = m_clients.getClientIDs();
2840         m_clients.Lock();
2841         // Set the modified blocks unsent for all the clients
2842         for (std::list<u16>::iterator
2843                  i = clients.begin();
2844                  i != clients.end(); ++i) {
2845                         RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2846                         if (client != NULL)
2847                                 client->SetBlocksNotSent(block);
2848                 }
2849         m_clients.Unlock();
2850 }
2851
2852 void Server::peerAdded(con::Peer *peer)
2853 {
2854         DSTACK(__FUNCTION_NAME);
2855         verbosestream<<"Server::peerAdded(): peer->id="
2856                         <<peer->id<<std::endl;
2857
2858         con::PeerChange c;
2859         c.type = con::PEER_ADDED;
2860         c.peer_id = peer->id;
2861         c.timeout = false;
2862         m_peer_change_queue.push_back(c);
2863 }
2864
2865 void Server::deletingPeer(con::Peer *peer, bool timeout)
2866 {
2867         DSTACK(__FUNCTION_NAME);
2868         verbosestream<<"Server::deletingPeer(): peer->id="
2869                         <<peer->id<<", timeout="<<timeout<<std::endl;
2870
2871         m_clients.event(peer->id,Disconnect);
2872         con::PeerChange c;
2873         c.type = con::PEER_REMOVED;
2874         c.peer_id = peer->id;
2875         c.timeout = timeout;
2876         m_peer_change_queue.push_back(c);
2877 }
2878
2879 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2880 {
2881         *retval = m_con.getPeerStat(peer_id,type);
2882         if (*retval == -1) return false;
2883         return true;
2884 }
2885
2886 bool Server::getClientInfo(
2887                 u16          peer_id,
2888                 ClientState* state,
2889                 u32*         uptime,
2890                 u8*          ser_vers,
2891                 u16*         prot_vers,
2892                 u8*          major,
2893                 u8*          minor,
2894                 u8*          patch,
2895                 std::string* vers_string
2896         )
2897 {
2898         *state = m_clients.getClientState(peer_id);
2899         m_clients.Lock();
2900         RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,Invalid);
2901
2902         if (client == NULL)
2903                 return false;
2904
2905         *uptime = client->uptime();
2906         *ser_vers = client->serialization_version;
2907         *prot_vers = client->net_proto_version;
2908
2909         *major = client->getMajor();
2910         *minor = client->getMinor();
2911         *patch = client->getPatch();
2912         *vers_string = client->getPatch();
2913
2914         m_clients.Unlock();
2915
2916         return true;
2917 }
2918
2919 void Server::handlePeerChanges()
2920 {
2921         while(m_peer_change_queue.size() > 0)
2922         {
2923                 con::PeerChange c = m_peer_change_queue.pop_front();
2924
2925                 verbosestream<<"Server: Handling peer change: "
2926                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2927                                 <<std::endl;
2928
2929                 switch(c.type)
2930                 {
2931                 case con::PEER_ADDED:
2932                         m_clients.CreateClient(c.peer_id);
2933                         break;
2934
2935                 case con::PEER_REMOVED:
2936                         DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2937                         break;
2938
2939                 default:
2940                         assert("Invalid peer change event received!" == 0);
2941                         break;
2942                 }
2943         }
2944 }
2945
2946 void Server::SendMovement(u16 peer_id)
2947 {
2948         DSTACK(__FUNCTION_NAME);
2949         std::ostringstream os(std::ios_base::binary);
2950
2951         writeU16(os, TOCLIENT_MOVEMENT);
2952         writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2953         writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2954         writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2955         writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2956         writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2957         writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2958         writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2959         writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2960         writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2961         writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2962         writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2963         writeF1000(os, g_settings->getFloat("movement_gravity"));
2964
2965         // Make data buffer
2966         std::string s = os.str();
2967         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2968         // Send as reliable
2969         m_clients.send(peer_id, 0, data, true);
2970 }
2971
2972 void Server::SendHP(u16 peer_id, u8 hp)
2973 {
2974         DSTACK(__FUNCTION_NAME);
2975         std::ostringstream os(std::ios_base::binary);
2976
2977         writeU16(os, TOCLIENT_HP);
2978         writeU8(os, hp);
2979
2980         // Make data buffer
2981         std::string s = os.str();
2982         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2983         // Send as reliable
2984         m_clients.send(peer_id, 0, data, true);
2985 }
2986
2987 void Server::SendBreath(u16 peer_id, u16 breath)
2988 {
2989         DSTACK(__FUNCTION_NAME);
2990         std::ostringstream os(std::ios_base::binary);
2991
2992         writeU16(os, TOCLIENT_BREATH);
2993         writeU16(os, breath);
2994
2995         // Make data buffer
2996         std::string s = os.str();
2997         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2998         // Send as reliable
2999         m_clients.send(peer_id, 0, data, true);
3000 }
3001
3002 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3003 {
3004         DSTACK(__FUNCTION_NAME);
3005         std::ostringstream os(std::ios_base::binary);
3006
3007         writeU16(os, TOCLIENT_ACCESS_DENIED);
3008         os<<serializeWideString(reason);
3009
3010         // Make data buffer
3011         std::string s = os.str();
3012         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3013         // Send as reliable
3014         m_clients.send(peer_id, 0, data, true);
3015 }
3016
3017 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3018                 v3f camera_point_target)
3019 {
3020         DSTACK(__FUNCTION_NAME);
3021         std::ostringstream os(std::ios_base::binary);
3022
3023         writeU16(os, TOCLIENT_DEATHSCREEN);
3024         writeU8(os, set_camera_point_target);
3025         writeV3F1000(os, camera_point_target);
3026
3027         // Make data buffer
3028         std::string s = os.str();
3029         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3030         // Send as reliable
3031         m_clients.send(peer_id, 0, data, true);
3032 }
3033
3034 void Server::SendItemDef(u16 peer_id,
3035                 IItemDefManager *itemdef, u16 protocol_version)
3036 {
3037         DSTACK(__FUNCTION_NAME);
3038         std::ostringstream os(std::ios_base::binary);
3039
3040         /*
3041                 u16 command
3042                 u32 length of the next item
3043                 zlib-compressed serialized ItemDefManager
3044         */
3045         writeU16(os, TOCLIENT_ITEMDEF);
3046         std::ostringstream tmp_os(std::ios::binary);
3047         itemdef->serialize(tmp_os, protocol_version);
3048         std::ostringstream tmp_os2(std::ios::binary);
3049         compressZlib(tmp_os.str(), tmp_os2);
3050         os<<serializeLongString(tmp_os2.str());
3051
3052         // Make data buffer
3053         std::string s = os.str();
3054         verbosestream<<"Server: Sending item definitions to id("<<peer_id
3055                         <<"): size="<<s.size()<<std::endl;
3056         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3057         // Send as reliable
3058         m_clients.send(peer_id, 0, data, true);
3059 }
3060
3061 void Server::SendNodeDef(u16 peer_id,
3062                 INodeDefManager *nodedef, u16 protocol_version)
3063 {
3064         DSTACK(__FUNCTION_NAME);
3065         std::ostringstream os(std::ios_base::binary);
3066
3067         /*
3068                 u16 command
3069                 u32 length of the next item
3070                 zlib-compressed serialized NodeDefManager
3071         */
3072         writeU16(os, TOCLIENT_NODEDEF);
3073         std::ostringstream tmp_os(std::ios::binary);
3074         nodedef->serialize(tmp_os, protocol_version);
3075         std::ostringstream tmp_os2(std::ios::binary);
3076         compressZlib(tmp_os.str(), tmp_os2);
3077         os<<serializeLongString(tmp_os2.str());
3078
3079         // Make data buffer
3080         std::string s = os.str();
3081         verbosestream<<"Server: Sending node definitions to id("<<peer_id
3082                         <<"): size="<<s.size()<<std::endl;
3083         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3084         // Send as reliable
3085         m_clients.send(peer_id, 0, data, true);
3086 }
3087
3088 /*
3089         Non-static send methods
3090 */
3091
3092 void Server::SendInventory(u16 peer_id)
3093 {
3094         DSTACK(__FUNCTION_NAME);
3095
3096         PlayerSAO *playersao = getPlayerSAO(peer_id);
3097         assert(playersao);
3098
3099         playersao->m_inventory_not_sent = false;
3100
3101         /*
3102                 Serialize it
3103         */
3104
3105         std::ostringstream os;
3106         playersao->getInventory()->serialize(os);
3107
3108         std::string s = os.str();
3109
3110         SharedBuffer<u8> data(s.size()+2);
3111         writeU16(&data[0], TOCLIENT_INVENTORY);
3112         memcpy(&data[2], s.c_str(), s.size());
3113
3114         // Send as reliable
3115         m_clients.send(peer_id, 0, data, true);
3116 }
3117
3118 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3119 {
3120         DSTACK(__FUNCTION_NAME);
3121
3122         std::ostringstream os(std::ios_base::binary);
3123         u8 buf[12];
3124
3125         // Write command
3126         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3127         os.write((char*)buf, 2);
3128
3129         // Write length
3130         writeU16(buf, message.size());
3131         os.write((char*)buf, 2);
3132
3133         // Write string
3134         for(u32 i=0; i<message.size(); i++)
3135         {
3136                 u16 w = message[i];
3137                 writeU16(buf, w);
3138                 os.write((char*)buf, 2);
3139         }
3140
3141         // Make data buffer
3142         std::string s = os.str();
3143         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3144
3145         if (peer_id != PEER_ID_INEXISTENT)
3146         {
3147                 // Send as reliable
3148                 m_clients.send(peer_id, 0, data, true);
3149         }
3150         else
3151         {
3152                 m_clients.sendToAll(0,data,true);
3153         }
3154 }
3155
3156 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3157                                      const std::string &formname)
3158 {
3159         DSTACK(__FUNCTION_NAME);
3160
3161         std::ostringstream os(std::ios_base::binary);
3162         u8 buf[12];
3163
3164         // Write command
3165         writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3166         os.write((char*)buf, 2);
3167         os<<serializeLongString(formspec);
3168         os<<serializeString(formname);
3169
3170         // Make data buffer
3171         std::string s = os.str();
3172         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3173         // Send as reliable
3174         m_clients.send(peer_id, 0, data, true);
3175 }
3176
3177 // Spawns a particle on peer with peer_id
3178 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3179                                 float expirationtime, float size, bool collisiondetection,
3180                                 bool vertical, std::string texture)
3181 {
3182         DSTACK(__FUNCTION_NAME);
3183
3184         std::ostringstream os(std::ios_base::binary);
3185         writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3186         writeV3F1000(os, pos);
3187         writeV3F1000(os, velocity);
3188         writeV3F1000(os, acceleration);
3189         writeF1000(os, expirationtime);
3190         writeF1000(os, size);
3191         writeU8(os,  collisiondetection);
3192         os<<serializeLongString(texture);
3193         writeU8(os, vertical);
3194
3195         // Make data buffer
3196         std::string s = os.str();
3197         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3198
3199         if (peer_id != PEER_ID_INEXISTENT)
3200         {
3201         // Send as reliable
3202                 m_clients.send(peer_id, 0, data, true);
3203         }
3204         else
3205         {
3206                 m_clients.sendToAll(0,data,true);
3207         }
3208 }
3209
3210 // Adds a ParticleSpawner on peer with peer_id
3211 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3212         v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3213         float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3214 {
3215         DSTACK(__FUNCTION_NAME);
3216
3217         std::ostringstream os(std::ios_base::binary);
3218         writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3219
3220         writeU16(os, amount);
3221         writeF1000(os, spawntime);
3222         writeV3F1000(os, minpos);
3223         writeV3F1000(os, maxpos);
3224         writeV3F1000(os, minvel);
3225         writeV3F1000(os, maxvel);
3226         writeV3F1000(os, minacc);
3227         writeV3F1000(os, maxacc);
3228         writeF1000(os, minexptime);
3229         writeF1000(os, maxexptime);
3230         writeF1000(os, minsize);
3231         writeF1000(os, maxsize);
3232         writeU8(os,  collisiondetection);
3233         os<<serializeLongString(texture);
3234         writeU32(os, id);
3235         writeU8(os, vertical);
3236
3237         // Make data buffer
3238         std::string s = os.str();
3239         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3240
3241         if (peer_id != PEER_ID_INEXISTENT)
3242         {
3243                 // Send as reliable
3244                 m_clients.send(peer_id, 0, data, true);
3245         }
3246         else {
3247                 m_clients.sendToAll(0,data,true);
3248         }
3249 }
3250
3251 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3252 {
3253         DSTACK(__FUNCTION_NAME);
3254
3255         std::ostringstream os(std::ios_base::binary);
3256         writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3257
3258         writeU16(os, id);
3259
3260         // Make data buffer
3261         std::string s = os.str();
3262         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3263
3264         if (peer_id != PEER_ID_INEXISTENT) {
3265                 // Send as reliable
3266                 m_clients.send(peer_id, 0, data, true);
3267         }
3268         else {
3269                 m_clients.sendToAll(0,data,true);
3270         }
3271
3272 }
3273
3274 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3275 {
3276         std::ostringstream os(std::ios_base::binary);
3277
3278         // Write command
3279         writeU16(os, TOCLIENT_HUDADD);
3280         writeU32(os, id);
3281         writeU8(os, (u8)form->type);
3282         writeV2F1000(os, form->pos);
3283         os << serializeString(form->name);
3284         writeV2F1000(os, form->scale);
3285         os << serializeString(form->text);
3286         writeU32(os, form->number);
3287         writeU32(os, form->item);
3288         writeU32(os, form->dir);
3289         writeV2F1000(os, form->align);
3290         writeV2F1000(os, form->offset);
3291         writeV3F1000(os, form->world_pos);
3292
3293         // Make data buffer
3294         std::string s = os.str();
3295         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3296         // Send as reliable
3297         m_clients.send(peer_id, 1, data, true);
3298 }
3299
3300 void Server::SendHUDRemove(u16 peer_id, u32 id)
3301 {
3302         std::ostringstream os(std::ios_base::binary);
3303
3304         // Write command
3305         writeU16(os, TOCLIENT_HUDRM);
3306         writeU32(os, id);
3307
3308         // Make data buffer
3309         std::string s = os.str();
3310         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3311         // Send as reliable
3312
3313         m_clients.send(peer_id, 1, data, true);
3314 }
3315
3316 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3317 {
3318         std::ostringstream os(std::ios_base::binary);
3319
3320         // Write command
3321         writeU16(os, TOCLIENT_HUDCHANGE);
3322         writeU32(os, id);
3323         writeU8(os, (u8)stat);
3324         switch (stat) {
3325                 case HUD_STAT_POS:
3326                 case HUD_STAT_SCALE:
3327                 case HUD_STAT_ALIGN:
3328                 case HUD_STAT_OFFSET:
3329                         writeV2F1000(os, *(v2f *)value);
3330                         break;
3331                 case HUD_STAT_NAME:
3332                 case HUD_STAT_TEXT:
3333                         os << serializeString(*(std::string *)value);
3334                         break;
3335                 case HUD_STAT_WORLD_POS:
3336                         writeV3F1000(os, *(v3f *)value);
3337                         break;
3338                 case HUD_STAT_NUMBER:
3339                 case HUD_STAT_ITEM:
3340                 case HUD_STAT_DIR:
3341                 default:
3342                         writeU32(os, *(u32 *)value);
3343                         break;
3344         }
3345
3346         // Make data buffer
3347         std::string s = os.str();
3348         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3349         // Send as reliable
3350         m_clients.send(peer_id, 0, data, true);
3351 }
3352
3353 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3354 {
3355         std::ostringstream os(std::ios_base::binary);
3356
3357         // Write command
3358         writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3359         writeU32(os, flags);
3360         writeU32(os, mask);
3361
3362         // Make data buffer
3363         std::string s = os.str();
3364         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3365         // Send as reliable
3366         m_clients.send(peer_id, 0, data, true);
3367 }
3368
3369 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3370 {
3371         std::ostringstream os(std::ios_base::binary);
3372
3373         // Write command
3374         writeU16(os, TOCLIENT_HUD_SET_PARAM);
3375         writeU16(os, param);
3376         os<<serializeString(value);
3377
3378         // Make data buffer
3379         std::string s = os.str();
3380         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3381         // Send as reliable
3382         m_clients.send(peer_id, 0, data, true);
3383 }
3384
3385 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3386                 const std::string &type, const std::vector<std::string> &params)
3387 {
3388         std::ostringstream os(std::ios_base::binary);
3389
3390         // Write command
3391         writeU16(os, TOCLIENT_SET_SKY);
3392         writeARGB8(os, bgcolor);
3393         os<<serializeString(type);
3394         writeU16(os, params.size());
3395         for(size_t i=0; i<params.size(); i++)
3396                 os<<serializeString(params[i]);
3397
3398         // Make data buffer
3399         std::string s = os.str();
3400         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3401         // Send as reliable
3402         m_clients.send(peer_id, 0, data, true);
3403 }
3404
3405 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3406                 float ratio)
3407 {
3408         std::ostringstream os(std::ios_base::binary);
3409
3410         // Write command
3411         writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3412         writeU8(os, do_override);
3413         writeU16(os, ratio*65535);
3414
3415         // Make data buffer
3416         std::string s = os.str();
3417         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3418         // Send as reliable
3419         m_clients.send(peer_id, 0, data, true);
3420 }
3421
3422 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3423 {
3424         DSTACK(__FUNCTION_NAME);
3425
3426         // Make packet
3427         SharedBuffer<u8> data(2+2+4);
3428         writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3429         writeU16(&data[2], time);
3430         writeF1000(&data[4], time_speed);
3431
3432         if (peer_id == PEER_ID_INEXISTENT) {
3433                 m_clients.sendToAll(0,data,true);
3434         }
3435         else {
3436                 // Send as reliable
3437                 m_clients.send(peer_id, 0, data, true);
3438         }
3439 }
3440
3441 void Server::SendPlayerHP(u16 peer_id)
3442 {
3443         DSTACK(__FUNCTION_NAME);
3444         PlayerSAO *playersao = getPlayerSAO(peer_id);
3445         assert(playersao);
3446         playersao->m_hp_not_sent = false;
3447         SendHP(peer_id, playersao->getHP());
3448
3449         // Send to other clients
3450         std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3451         ActiveObjectMessage aom(playersao->getId(), true, str);
3452         playersao->m_messages_out.push_back(aom);
3453 }
3454
3455 void Server::SendPlayerBreath(u16 peer_id)
3456 {
3457         DSTACK(__FUNCTION_NAME);
3458         PlayerSAO *playersao = getPlayerSAO(peer_id);
3459         assert(playersao);
3460         playersao->m_breath_not_sent = false;
3461         SendBreath(peer_id, playersao->getBreath());
3462 }
3463
3464 void Server::SendMovePlayer(u16 peer_id)
3465 {
3466         DSTACK(__FUNCTION_NAME);
3467         Player *player = m_env->getPlayer(peer_id);
3468         assert(player);
3469
3470         std::ostringstream os(std::ios_base::binary);
3471         writeU16(os, TOCLIENT_MOVE_PLAYER);
3472         writeV3F1000(os, player->getPosition());
3473         writeF1000(os, player->getPitch());
3474         writeF1000(os, player->getYaw());
3475
3476         {
3477                 v3f pos = player->getPosition();
3478                 f32 pitch = player->getPitch();
3479                 f32 yaw = player->getYaw();
3480                 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3481                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3482                                 <<" pitch="<<pitch
3483                                 <<" yaw="<<yaw
3484                                 <<std::endl;
3485         }
3486
3487         // Make data buffer
3488         std::string s = os.str();
3489         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3490         // Send as reliable
3491         m_clients.send(peer_id, 0, data, true);
3492 }
3493
3494 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3495 {
3496         std::ostringstream os(std::ios_base::binary);
3497
3498         writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3499         writeV2S32(os, animation_frames[0]);
3500         writeV2S32(os, animation_frames[1]);
3501         writeV2S32(os, animation_frames[2]);
3502         writeV2S32(os, animation_frames[3]);
3503         writeF1000(os, animation_speed);
3504
3505         // Make data buffer
3506         std::string s = os.str();
3507         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3508         // Send as reliable
3509         m_clients.send(peer_id, 0, data, true);
3510 }
3511
3512 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3513 {
3514         std::ostringstream os(std::ios_base::binary);
3515
3516         writeU16(os, TOCLIENT_EYE_OFFSET);
3517         writeV3F1000(os, first);
3518         writeV3F1000(os, third);
3519
3520         // Make data buffer
3521         std::string s = os.str();
3522         SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3523         // Send as reliable
3524         m_clients.send(peer_id, 0, data, true);
3525 }
3526 void Server::SendPlayerPrivileges(u16 peer_id)
3527 {
3528         Player *player = m_env->getPlayer(peer_id);
3529         assert(player);
3530         if(player->peer_id == PEER_ID_INEXISTENT)
3531                 return;
3532
3533         std::set<std::string> privs;
3534         m_script->getAuth(player->getName(), NULL, &privs);
3535
3536         std::ostringstream os(std::ios_base::binary);
3537         writeU16(os, TOCLIENT_PRIVILEGES);
3538         writeU16(os, privs.size());
3539         for(std::set<std::string>::const_iterator i = privs.begin();
3540                         i != privs.end(); i++){
3541                 os<<serializeString(*i);
3542         }
3543
3544         // Make data buffer
3545         std::string s = os.str();
3546         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3547         // Send as reliable
3548         m_clients.send(peer_id, 0, data, true);
3549 }
3550
3551 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3552 {
3553         Player *player = m_env->getPlayer(peer_id);
3554         assert(player);
3555         if(player->peer_id == PEER_ID_INEXISTENT)
3556                 return;
3557
3558         std::ostringstream os(std::ios_base::binary);
3559         writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3560         os<<serializeLongString(player->inventory_formspec);
3561
3562         // Make data buffer
3563         std::string s = os.str();
3564         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3565         // Send as reliable
3566         m_clients.send(peer_id, 0, data, true);
3567 }
3568
3569 s32 Server::playSound(const SimpleSoundSpec &spec,
3570                 const ServerSoundParams &params)
3571 {
3572         // Find out initial position of sound
3573         bool pos_exists = false;
3574         v3f pos = params.getPos(m_env, &pos_exists);
3575         // If position is not found while it should be, cancel sound
3576         if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3577                 return -1;
3578
3579         // Filter destination clients
3580         std::list<u16> dst_clients;
3581         if(params.to_player != "")
3582         {
3583                 Player *player = m_env->getPlayer(params.to_player.c_str());
3584                 if(!player){
3585                         infostream<<"Server::playSound: Player \""<<params.to_player
3586                                         <<"\" not found"<<std::endl;
3587                         return -1;
3588                 }
3589                 if(player->peer_id == PEER_ID_INEXISTENT){
3590                         infostream<<"Server::playSound: Player \""<<params.to_player
3591                                         <<"\" not connected"<<std::endl;
3592                         return -1;
3593                 }
3594                 dst_clients.push_back(player->peer_id);
3595         }
3596         else
3597         {
3598                 std::list<u16> clients = m_clients.getClientIDs();
3599
3600                 for(std::list<u16>::iterator
3601                                 i = clients.begin(); i != clients.end(); ++i)
3602                 {
3603                         Player *player = m_env->getPlayer(*i);
3604                         if(!player)
3605                                 continue;
3606                         if(pos_exists){
3607                                 if(player->getPosition().getDistanceFrom(pos) >
3608                                                 params.max_hear_distance)
3609                                         continue;
3610                         }
3611                         dst_clients.push_back(*i);
3612                 }
3613         }
3614         if(dst_clients.size() == 0)
3615                 return -1;
3616
3617         // Create the sound
3618         s32 id = m_next_sound_id++;
3619         // The sound will exist as a reference in m_playing_sounds
3620         m_playing_sounds[id] = ServerPlayingSound();
3621         ServerPlayingSound &psound = m_playing_sounds[id];
3622         psound.params = params;
3623         for(std::list<u16>::iterator i = dst_clients.begin();
3624                         i != dst_clients.end(); i++)
3625                 psound.clients.insert(*i);
3626         // Create packet
3627         std::ostringstream os(std::ios_base::binary);
3628         writeU16(os, TOCLIENT_PLAY_SOUND);
3629         writeS32(os, id);
3630         os<<serializeString(spec.name);
3631         writeF1000(os, spec.gain * params.gain);
3632         writeU8(os, params.type);
3633         writeV3F1000(os, pos);
3634         writeU16(os, params.object);
3635         writeU8(os, params.loop);
3636         // Make data buffer
3637         std::string s = os.str();
3638         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3639         // Send
3640         for(std::list<u16>::iterator i = dst_clients.begin();
3641                         i != dst_clients.end(); i++){
3642                 // Send as reliable
3643                 m_clients.send(*i, 0, data, true);
3644         }
3645         return id;
3646 }
3647 void Server::stopSound(s32 handle)
3648 {
3649         // Get sound reference
3650         std::map<s32, ServerPlayingSound>::iterator i =
3651                         m_playing_sounds.find(handle);
3652         if(i == m_playing_sounds.end())
3653                 return;
3654         ServerPlayingSound &psound = i->second;
3655         // Create packet
3656         std::ostringstream os(std::ios_base::binary);
3657         writeU16(os, TOCLIENT_STOP_SOUND);
3658         writeS32(os, handle);
3659         // Make data buffer
3660         std::string s = os.str();
3661         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3662         // Send
3663         for(std::set<u16>::iterator i = psound.clients.begin();
3664                         i != psound.clients.end(); i++){
3665                 // Send as reliable
3666                 m_clients.send(*i, 0, data, true);
3667         }
3668         // Remove sound reference
3669         m_playing_sounds.erase(i);
3670 }
3671
3672 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3673         std::list<u16> *far_players, float far_d_nodes)
3674 {
3675         float maxd = far_d_nodes*BS;
3676         v3f p_f = intToFloat(p, BS);
3677
3678         // Create packet
3679         u32 replysize = 8;
3680         SharedBuffer<u8> reply(replysize);
3681         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3682         writeS16(&reply[2], p.X);
3683         writeS16(&reply[4], p.Y);
3684         writeS16(&reply[6], p.Z);
3685
3686         std::list<u16> clients = m_clients.getClientIDs();
3687         for(std::list<u16>::iterator
3688                 i = clients.begin();
3689                 i != clients.end(); ++i)
3690         {
3691                 if(far_players)
3692                 {
3693                         // Get player
3694                         Player *player = m_env->getPlayer(*i);
3695                         if(player)
3696                         {
3697                                 // If player is far away, only set modified blocks not sent
3698                                 v3f player_pos = player->getPosition();
3699                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3700                                 {
3701                                         far_players->push_back(*i);
3702                                         continue;
3703                                 }
3704                         }
3705                 }
3706
3707                 // Send as reliable
3708                 m_clients.send(*i, 0, reply, true);
3709         }
3710 }
3711
3712 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3713                 std::list<u16> *far_players, float far_d_nodes,
3714                 bool remove_metadata)
3715 {
3716         float maxd = far_d_nodes*BS;
3717         v3f p_f = intToFloat(p, BS);
3718
3719         std::list<u16> clients = m_clients.getClientIDs();
3720                 for(std::list<u16>::iterator
3721                         i = clients.begin();
3722                         i != clients.end(); ++i)
3723                 {
3724
3725                 if(far_players)
3726                 {
3727                         // Get player
3728                         Player *player = m_env->getPlayer(*i);
3729                         if(player)
3730                         {
3731                                 // If player is far away, only set modified blocks not sent
3732                                 v3f player_pos = player->getPosition();
3733                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3734                                 {
3735                                         far_players->push_back(*i);
3736                                         continue;
3737                                 }
3738                         }
3739                 }
3740                 SharedBuffer<u8> reply(0);
3741                 m_clients.Lock();
3742                 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3743                 if (client != 0)
3744                 {
3745                         // Create packet
3746                         u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3747                         reply = SharedBuffer<u8>(replysize);
3748                         writeU16(&reply[0], TOCLIENT_ADDNODE);
3749                         writeS16(&reply[2], p.X);
3750                         writeS16(&reply[4], p.Y);
3751                         writeS16(&reply[6], p.Z);
3752                         n.serialize(&reply[8], client->serialization_version);
3753                         u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3754                         writeU8(&reply[index], remove_metadata ? 0 : 1);
3755
3756                         if (!remove_metadata) {
3757                                 if (client->net_proto_version <= 21) {
3758                                         // Old clients always clear metadata; fix it
3759                                         // by sending the full block again.
3760                                         client->SetBlockNotSent(p);
3761                                 }
3762                         }
3763                 }
3764                 m_clients.Unlock();
3765
3766                 // Send as reliable
3767                 if (reply.getSize() > 0)
3768                         m_clients.send(*i, 0, reply, true);
3769         }
3770 }
3771
3772 void Server::setBlockNotSent(v3s16 p)
3773 {
3774         std::list<u16> clients = m_clients.getClientIDs();
3775         m_clients.Lock();
3776         for(std::list<u16>::iterator
3777                 i = clients.begin();
3778                 i != clients.end(); ++i)
3779         {
3780                 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3781                 client->SetBlockNotSent(p);
3782         }
3783         m_clients.Unlock();
3784 }
3785
3786 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3787 {
3788         DSTACK(__FUNCTION_NAME);
3789
3790         v3s16 p = block->getPos();
3791
3792 #if 0
3793         // Analyze it a bit
3794         bool completely_air = true;
3795         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3796         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3797         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3798         {
3799                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3800                 {
3801                         completely_air = false;
3802                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3803                 }
3804         }
3805
3806         // Print result
3807         infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3808         if(completely_air)
3809                 infostream<<"[completely air] ";
3810         infostream<<std::endl;
3811 #endif
3812
3813         /*
3814                 Create a packet with the block in the right format
3815         */
3816
3817         std::ostringstream os(std::ios_base::binary);
3818         block->serialize(os, ver, false);
3819         block->serializeNetworkSpecific(os, net_proto_version);
3820         std::string s = os.str();
3821         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3822
3823         u32 replysize = 8 + blockdata.getSize();
3824         SharedBuffer<u8> reply(replysize);
3825         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3826         writeS16(&reply[2], p.X);
3827         writeS16(&reply[4], p.Y);
3828         writeS16(&reply[6], p.Z);
3829         memcpy(&reply[8], *blockdata, blockdata.getSize());
3830
3831         /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3832                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3833
3834         /*
3835                 Send packet
3836         */
3837         m_clients.send(peer_id, 2, reply, true);
3838 }
3839
3840 void Server::SendBlocks(float dtime)
3841 {
3842         DSTACK(__FUNCTION_NAME);
3843
3844         JMutexAutoLock envlock(m_env_mutex);
3845         //TODO check if one big lock could be faster then multiple small ones
3846
3847         ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3848
3849         std::vector<PrioritySortedBlockTransfer> queue;
3850
3851         s32 total_sending = 0;
3852
3853         {
3854                 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3855
3856                 std::list<u16> clients = m_clients.getClientIDs();
3857
3858                 m_clients.Lock();
3859                 for(std::list<u16>::iterator
3860                         i = clients.begin();
3861                         i != clients.end(); ++i)
3862                 {
3863                         RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3864
3865                         if (client == NULL)
3866                                 return;
3867
3868                         total_sending += client->SendingCount();
3869                         client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3870                 }
3871                 m_clients.Unlock();
3872         }
3873
3874         // Sort.
3875         // Lowest priority number comes first.
3876         // Lowest is most important.
3877         std::sort(queue.begin(), queue.end());
3878
3879         m_clients.Lock();
3880         for(u32 i=0; i<queue.size(); i++)
3881         {
3882                 //TODO: Calculate limit dynamically
3883                 if(total_sending >= g_settings->getS32
3884                                 ("max_simultaneous_block_sends_server_total"))
3885                         break;
3886
3887                 PrioritySortedBlockTransfer q = queue[i];
3888
3889                 MapBlock *block = NULL;
3890                 try
3891                 {
3892                         block = m_env->getMap().getBlockNoCreate(q.pos);
3893                 }
3894                 catch(InvalidPositionException &e)
3895                 {
3896                         continue;
3897                 }
3898
3899                 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3900
3901                 if(!client)
3902                         continue;
3903
3904                 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3905
3906                 client->SentBlock(q.pos);
3907                 total_sending++;
3908         }
3909         m_clients.Unlock();
3910 }
3911
3912 void Server::fillMediaCache()
3913 {
3914         DSTACK(__FUNCTION_NAME);
3915
3916         infostream<<"Server: Calculating media file checksums"<<std::endl;
3917
3918         // Collect all media file paths
3919         std::list<std::string> paths;
3920         for(std::vector<ModSpec>::iterator i = m_mods.begin();
3921                         i != m_mods.end(); i++){
3922                 const ModSpec &mod = *i;
3923                 paths.push_back(mod.path + DIR_DELIM + "textures");
3924                 paths.push_back(mod.path + DIR_DELIM + "sounds");
3925                 paths.push_back(mod.path + DIR_DELIM + "media");
3926                 paths.push_back(mod.path + DIR_DELIM + "models");
3927         }
3928         paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3929
3930         // Collect media file information from paths into cache
3931         for(std::list<std::string>::iterator i = paths.begin();
3932                         i != paths.end(); i++)
3933         {
3934                 std::string mediapath = *i;
3935                 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3936                 for(u32 j=0; j<dirlist.size(); j++){
3937                         if(dirlist[j].dir) // Ignode dirs
3938                                 continue;
3939                         std::string filename = dirlist[j].name;
3940                         // If name contains illegal characters, ignore the file
3941                         if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3942                                 infostream<<"Server: ignoring illegal file name: \""
3943                                                 <<filename<<"\""<<std::endl;
3944                                 continue;
3945                         }
3946                         // If name is not in a supported format, ignore it
3947                         const char *supported_ext[] = {
3948                                 ".png", ".jpg", ".bmp", ".tga",
3949                                 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3950                                 ".ogg",
3951                                 ".x", ".b3d", ".md2", ".obj",
3952                                 NULL
3953                         };
3954                         if(removeStringEnd(filename, supported_ext) == ""){
3955                                 infostream<<"Server: ignoring unsupported file extension: \""
3956                                                 <<filename<<"\""<<std::endl;
3957                                 continue;
3958                         }
3959                         // Ok, attempt to load the file and add to cache
3960                         std::string filepath = mediapath + DIR_DELIM + filename;
3961                         // Read data
3962                         std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3963                         if(fis.good() == false){
3964                                 errorstream<<"Server::fillMediaCache(): Could not open \""
3965                                                 <<filename<<"\" for reading"<<std::endl;
3966                                 continue;
3967                         }
3968                         std::ostringstream tmp_os(std::ios_base::binary);
3969                         bool bad = false;
3970                         for(;;){
3971                                 char buf[1024];
3972                                 fis.read(buf, 1024);
3973                                 std::streamsize len = fis.gcount();
3974                                 tmp_os.write(buf, len);
3975                                 if(fis.eof())
3976                                         break;
3977                                 if(!fis.good()){
3978                                         bad = true;
3979                                         break;
3980                                 }
3981                         }
3982                         if(bad){
3983                                 errorstream<<"Server::fillMediaCache(): Failed to read \""
3984                                                 <<filename<<"\""<<std::endl;
3985                                 continue;
3986                         }
3987                         if(tmp_os.str().length() == 0){
3988                                 errorstream<<"Server::fillMediaCache(): Empty file \""
3989                                                 <<filepath<<"\""<<std::endl;
3990                                 continue;
3991                         }
3992
3993                         SHA1 sha1;
3994                         sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3995
3996                         unsigned char *digest = sha1.getDigest();
3997                         std::string sha1_base64 = base64_encode(digest, 20);
3998                         std::string sha1_hex = hex_encode((char*)digest, 20);
3999                         free(digest);
4000
4001                         // Put in list
4002                         this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4003                         verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4004                 }
4005         }
4006 }
4007
4008 struct SendableMediaAnnouncement
4009 {
4010         std::string name;
4011         std::string sha1_digest;
4012
4013         SendableMediaAnnouncement(const std::string &name_="",
4014                                   const std::string &sha1_digest_=""):
4015                 name(name_),
4016                 sha1_digest(sha1_digest_)
4017         {}
4018 };
4019
4020 void Server::sendMediaAnnouncement(u16 peer_id)
4021 {
4022         DSTACK(__FUNCTION_NAME);
4023
4024         verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4025                         <<std::endl;
4026
4027         std::list<SendableMediaAnnouncement> file_announcements;
4028
4029         for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4030                         i != m_media.end(); i++){
4031                 // Put in list
4032                 file_announcements.push_back(
4033                                 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4034         }
4035
4036         // Make packet
4037         std::ostringstream os(std::ios_base::binary);
4038
4039         /*
4040                 u16 command
4041                 u32 number of files
4042                 for each texture {
4043                         u16 length of name
4044                         string name
4045                         u16 length of sha1_digest
4046                         string sha1_digest
4047                 }
4048         */
4049
4050         writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4051         writeU16(os, file_announcements.size());
4052
4053         for(std::list<SendableMediaAnnouncement>::iterator
4054                         j = file_announcements.begin();
4055                         j != file_announcements.end(); ++j){
4056                 os<<serializeString(j->name);
4057                 os<<serializeString(j->sha1_digest);
4058         }
4059         os<<serializeString(g_settings->get("remote_media"));
4060
4061         // Make data buffer
4062         std::string s = os.str();
4063         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4064
4065         // Send as reliable
4066         m_clients.send(peer_id, 0, data, true);
4067 }
4068
4069 struct SendableMedia
4070 {
4071         std::string name;
4072         std::string path;
4073         std::string data;
4074
4075         SendableMedia(const std::string &name_="", const std::string &path_="",
4076                       const std::string &data_=""):
4077                 name(name_),
4078                 path(path_),
4079                 data(data_)
4080         {}
4081 };
4082
4083 void Server::sendRequestedMedia(u16 peer_id,
4084                 const std::list<std::string> &tosend)
4085 {
4086         DSTACK(__FUNCTION_NAME);
4087
4088         verbosestream<<"Server::sendRequestedMedia(): "
4089                         <<"Sending files to client"<<std::endl;
4090
4091         /* Read files */
4092
4093         // Put 5kB in one bunch (this is not accurate)
4094         u32 bytes_per_bunch = 5000;
4095
4096         std::vector< std::list<SendableMedia> > file_bunches;
4097         file_bunches.push_back(std::list<SendableMedia>());
4098
4099         u32 file_size_bunch_total = 0;
4100
4101         for(std::list<std::string>::const_iterator i = tosend.begin();
4102                         i != tosend.end(); ++i)
4103         {
4104                 const std::string &name = *i;
4105
4106                 if(m_media.find(name) == m_media.end()){
4107                         errorstream<<"Server::sendRequestedMedia(): Client asked for "
4108                                         <<"unknown file \""<<(name)<<"\""<<std::endl;
4109                         continue;
4110                 }
4111
4112                 //TODO get path + name
4113                 std::string tpath = m_media[name].path;
4114
4115                 // Read data
4116                 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4117                 if(fis.good() == false){
4118                         errorstream<<"Server::sendRequestedMedia(): Could not open \""
4119                                         <<tpath<<"\" for reading"<<std::endl;
4120                         continue;
4121                 }
4122                 std::ostringstream tmp_os(std::ios_base::binary);
4123                 bool bad = false;
4124                 for(;;){
4125                         char buf[1024];
4126                         fis.read(buf, 1024);
4127                         std::streamsize len = fis.gcount();
4128                         tmp_os.write(buf, len);
4129                         file_size_bunch_total += len;
4130                         if(fis.eof())
4131                                 break;
4132                         if(!fis.good()){
4133                                 bad = true;
4134                                 break;
4135                         }
4136                 }
4137                 if(bad){
4138                         errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4139                                         <<name<<"\""<<std::endl;
4140                         continue;
4141                 }
4142                 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4143                                 <<tname<<"\""<<std::endl;*/
4144                 // Put in list
4145                 file_bunches[file_bunches.size()-1].push_back(
4146                                 SendableMedia(name, tpath, tmp_os.str()));
4147
4148                 // Start next bunch if got enough data
4149                 if(file_size_bunch_total >= bytes_per_bunch){
4150                         file_bunches.push_back(std::list<SendableMedia>());
4151                         file_size_bunch_total = 0;
4152                 }
4153
4154         }
4155
4156         /* Create and send packets */
4157
4158         u32 num_bunches = file_bunches.size();
4159         for(u32 i=0; i<num_bunches; i++)
4160         {
4161                 std::ostringstream os(std::ios_base::binary);
4162
4163                 /*
4164                         u16 command
4165                         u16 total number of texture bunches
4166                         u16 index of this bunch
4167                         u32 number of files in this bunch
4168                         for each file {
4169                                 u16 length of name
4170                                 string name
4171                                 u32 length of data
4172                                 data
4173                         }
4174                 */
4175
4176                 writeU16(os, TOCLIENT_MEDIA);
4177                 writeU16(os, num_bunches);
4178                 writeU16(os, i);
4179                 writeU32(os, file_bunches[i].size());
4180
4181                 for(std::list<SendableMedia>::iterator
4182                                 j = file_bunches[i].begin();
4183                                 j != file_bunches[i].end(); ++j){
4184                         os<<serializeString(j->name);
4185                         os<<serializeLongString(j->data);
4186                 }
4187
4188                 // Make data buffer
4189                 std::string s = os.str();
4190                 verbosestream<<"Server::sendRequestedMedia(): bunch "
4191                                 <<i<<"/"<<num_bunches
4192                                 <<" files="<<file_bunches[i].size()
4193                                 <<" size=" <<s.size()<<std::endl;
4194                 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4195                 // Send as reliable
4196                 m_clients.send(peer_id, 2, data, true);
4197         }
4198 }
4199
4200 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4201 {
4202         if(m_detached_inventories.count(name) == 0){
4203                 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4204                 return;
4205         }
4206         Inventory *inv = m_detached_inventories[name];
4207
4208         std::ostringstream os(std::ios_base::binary);
4209         writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4210         os<<serializeString(name);
4211         inv->serialize(os);
4212
4213         // Make data buffer
4214         std::string s = os.str();
4215         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4216
4217         if (peer_id != PEER_ID_INEXISTENT)
4218         {
4219                 // Send as reliable
4220                 m_clients.send(peer_id, 0, data, true);
4221         }
4222         else
4223         {
4224                 m_clients.sendToAll(0,data,true);
4225         }
4226 }
4227
4228 void Server::sendDetachedInventories(u16 peer_id)
4229 {
4230         DSTACK(__FUNCTION_NAME);
4231
4232         for(std::map<std::string, Inventory*>::iterator
4233                         i = m_detached_inventories.begin();
4234                         i != m_detached_inventories.end(); i++){
4235                 const std::string &name = i->first;
4236                 //Inventory *inv = i->second;
4237                 sendDetachedInventory(name, peer_id);
4238         }
4239 }
4240
4241 /*
4242         Something random
4243 */
4244
4245 void Server::DiePlayer(u16 peer_id)
4246 {
4247         DSTACK(__FUNCTION_NAME);
4248
4249         PlayerSAO *playersao = getPlayerSAO(peer_id);
4250         assert(playersao);
4251
4252         infostream<<"Server::DiePlayer(): Player "
4253                         <<playersao->getPlayer()->getName()
4254                         <<" dies"<<std::endl;
4255
4256         playersao->setHP(0);
4257
4258         // Trigger scripted stuff
4259         m_script->on_dieplayer(playersao);
4260
4261         SendPlayerHP(peer_id);
4262         SendDeathscreen(peer_id, false, v3f(0,0,0));
4263 }
4264
4265 void Server::RespawnPlayer(u16 peer_id)
4266 {
4267         DSTACK(__FUNCTION_NAME);
4268
4269         PlayerSAO *playersao = getPlayerSAO(peer_id);
4270         assert(playersao);
4271
4272         infostream<<"Server::RespawnPlayer(): Player "
4273                         <<playersao->getPlayer()->getName()
4274                         <<" respawns"<<std::endl;
4275
4276         playersao->setHP(PLAYER_MAX_HP);
4277
4278         bool repositioned = m_script->on_respawnplayer(playersao);
4279         if(!repositioned){
4280                 v3f pos = findSpawnPos(m_env->getServerMap());
4281                 playersao->setPos(pos);
4282         }
4283 }
4284
4285 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4286 {
4287         DSTACK(__FUNCTION_NAME);
4288
4289         SendAccessDenied(peer_id, reason);
4290         m_clients.event(peer_id,SetDenied);
4291         m_con.DisconnectPeer(peer_id);
4292 }
4293
4294 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4295 {
4296         DSTACK(__FUNCTION_NAME);
4297         std::wstring message;
4298         {
4299                 /*
4300                         Clear references to playing sounds
4301                 */
4302                 for(std::map<s32, ServerPlayingSound>::iterator
4303                                 i = m_playing_sounds.begin();
4304                                 i != m_playing_sounds.end();)
4305                 {
4306                         ServerPlayingSound &psound = i->second;
4307                         psound.clients.erase(peer_id);
4308                         if(psound.clients.size() == 0)
4309                                 m_playing_sounds.erase(i++);
4310                         else
4311                                 i++;
4312                 }
4313
4314                 Player *player = m_env->getPlayer(peer_id);
4315
4316                 // Collect information about leaving in chat
4317                 {
4318                         if(player != NULL && reason != CDR_DENY)
4319                         {
4320                                 std::wstring name = narrow_to_wide(player->getName());
4321                                 message += L"*** ";
4322                                 message += name;
4323                                 message += L" left the game.";
4324                                 if(reason == CDR_TIMEOUT)
4325                                         message += L" (timed out)";
4326                         }
4327                 }
4328
4329                 /* Run scripts and remove from environment */
4330                 {
4331                         if(player != NULL)
4332                         {
4333                                 PlayerSAO *playersao = player->getPlayerSAO();
4334                                 assert(playersao);
4335
4336                                 m_script->on_leaveplayer(playersao);
4337
4338                                 playersao->disconnected();
4339                         }
4340                 }
4341
4342                 /*
4343                         Print out action
4344                 */
4345                 {
4346                         if(player != NULL && reason != CDR_DENY)
4347                         {
4348                                 std::ostringstream os(std::ios_base::binary);
4349                                 std::list<u16> clients = m_clients.getClientIDs();
4350
4351                                 for(std::list<u16>::iterator
4352                                         i = clients.begin();
4353                                         i != clients.end(); ++i)
4354                                 {
4355                                         // Get player
4356                                         Player *player = m_env->getPlayer(*i);
4357                                         if(!player)
4358                                                 continue;
4359                                         // Get name of player
4360                                         os<<player->getName()<<" ";
4361                                 }
4362
4363                                 actionstream<<player->getName()<<" "
4364                                                 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4365                                                 <<" List of players: "<<os.str()<<std::endl;
4366                         }
4367                 }
4368                 {
4369                         JMutexAutoLock env_lock(m_env_mutex);
4370                         m_clients.DeleteClient(peer_id);
4371                 }
4372         }
4373
4374         // Send leave chat message to all remaining clients
4375         if(message.length() != 0)
4376                 SendChatMessage(PEER_ID_INEXISTENT,message);
4377 }
4378
4379 void Server::UpdateCrafting(u16 peer_id)
4380 {
4381         DSTACK(__FUNCTION_NAME);
4382
4383         Player* player = m_env->getPlayer(peer_id);
4384         assert(player);
4385
4386         // Get a preview for crafting
4387         ItemStack preview;
4388         InventoryLocation loc;
4389         loc.setPlayer(player->getName());
4390         getCraftingResult(&player->inventory, preview, false, this);
4391         m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4392
4393         // Put the new preview in
4394         InventoryList *plist = player->inventory.getList("craftpreview");
4395         assert(plist);
4396         assert(plist->getSize() >= 1);
4397         plist->changeItem(0, preview);
4398 }
4399
4400 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4401 {
4402         RemoteClient *client = getClientNoEx(peer_id,state_min);
4403         if(!client)
4404                 throw ClientNotFoundException("Client not found");
4405
4406         return client;
4407 }
4408 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4409 {
4410         return m_clients.getClientNoEx(peer_id, state_min);
4411 }
4412
4413 std::string Server::getPlayerName(u16 peer_id)
4414 {
4415         Player *player = m_env->getPlayer(peer_id);
4416         if(player == NULL)
4417                 return "[id="+itos(peer_id)+"]";
4418         return player->getName();
4419 }
4420
4421 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4422 {
4423         Player *player = m_env->getPlayer(peer_id);
4424         if(player == NULL)
4425                 return NULL;
4426         return player->getPlayerSAO();
4427 }
4428
4429 std::wstring Server::getStatusString()
4430 {
4431         std::wostringstream os(std::ios_base::binary);
4432         os<<L"# Server: ";
4433         // Version
4434         os<<L"version="<<narrow_to_wide(minetest_version_simple);
4435         // Uptime
4436         os<<L", uptime="<<m_uptime.get();
4437         // Max lag estimate
4438         os<<L", max_lag="<<m_env->getMaxLagEstimate();
4439         // Information about clients
4440         bool first = true;
4441         os<<L", clients={";
4442         std::list<u16> clients = m_clients.getClientIDs();
4443         for(std::list<u16>::iterator i = clients.begin();
4444                 i != clients.end(); ++i)
4445         {
4446                 // Get player
4447                 Player *player = m_env->getPlayer(*i);
4448                 // Get name of player
4449                 std::wstring name = L"unknown";
4450                 if(player != NULL)
4451                         name = narrow_to_wide(player->getName());
4452                 // Add name to information string
4453                 if(!first)
4454                         os<<L",";
4455                 else
4456                         first = false;
4457                 os<<name;
4458         }
4459         os<<L"}";
4460         if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4461                 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4462         if(g_settings->get("motd") != "")
4463                 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4464         return os.str();
4465 }
4466
4467 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4468 {
4469         std::set<std::string> privs;
4470         m_script->getAuth(name, NULL, &privs);
4471         return privs;
4472 }
4473
4474 bool Server::checkPriv(const std::string &name, const std::string &priv)
4475 {
4476         std::set<std::string> privs = getPlayerEffectivePrivs(name);
4477         return (privs.count(priv) != 0);
4478 }
4479
4480 void Server::reportPrivsModified(const std::string &name)
4481 {
4482         if(name == ""){
4483                 std::list<u16> clients = m_clients.getClientIDs();
4484                 for(std::list<u16>::iterator
4485                                 i = clients.begin();
4486                                 i != clients.end(); ++i){
4487                         Player *player = m_env->getPlayer(*i);
4488                         reportPrivsModified(player->getName());
4489                 }
4490         } else {
4491                 Player *player = m_env->getPlayer(name.c_str());
4492                 if(!player)
4493                         return;
4494                 SendPlayerPrivileges(player->peer_id);
4495                 PlayerSAO *sao = player->getPlayerSAO();
4496                 if(!sao)
4497                         return;
4498                 sao->updatePrivileges(
4499                                 getPlayerEffectivePrivs(name),
4500                                 isSingleplayer());
4501         }
4502 }
4503
4504 void Server::reportInventoryFormspecModified(const std::string &name)
4505 {
4506         Player *player = m_env->getPlayer(name.c_str());
4507         if(!player)
4508                 return;
4509         SendPlayerInventoryFormspec(player->peer_id);
4510 }
4511
4512 void Server::setIpBanned(const std::string &ip, const std::string &name)
4513 {
4514         m_banmanager->add(ip, name);
4515 }
4516
4517 void Server::unsetIpBanned(const std::string &ip_or_name)
4518 {
4519         m_banmanager->remove(ip_or_name);
4520 }
4521
4522 std::string Server::getBanDescription(const std::string &ip_or_name)
4523 {
4524         return m_banmanager->getBanDescription(ip_or_name);
4525 }
4526
4527 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4528 {
4529         Player *player = m_env->getPlayer(name);
4530         if(!player)
4531                 return;
4532
4533         if (player->peer_id == PEER_ID_INEXISTENT)
4534                 return;
4535
4536         SendChatMessage(player->peer_id, msg);
4537 }
4538
4539 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4540 {
4541         Player *player = m_env->getPlayer(playername);
4542
4543         if(!player)
4544         {
4545                 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4546                 return false;
4547         }
4548
4549         SendShowFormspecMessage(player->peer_id, formspec, formname);
4550         return true;
4551 }
4552
4553 u32 Server::hudAdd(Player *player, HudElement *form) {
4554         if (!player)
4555                 return -1;
4556
4557         u32 id = player->getFreeHudID();
4558         if (id < player->hud.size())
4559                 player->hud[id] = form;
4560         else
4561                 player->hud.push_back(form);
4562         
4563         SendHUDAdd(player->peer_id, id, form);
4564         return id;
4565 }
4566
4567 bool Server::hudRemove(Player *player, u32 id) {
4568         if (!player || id >= player->hud.size() || !player->hud[id])
4569                 return false;
4570
4571         delete player->hud[id];
4572         player->hud[id] = NULL;
4573         
4574         SendHUDRemove(player->peer_id, id);
4575         return true;
4576 }
4577
4578 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4579         if (!player)
4580                 return false;
4581
4582         SendHUDChange(player->peer_id, id, stat, data);
4583         return true;
4584 }
4585
4586 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4587         if (!player)
4588                 return false;
4589
4590         SendHUDSetFlags(player->peer_id, flags, mask);
4591         return true;
4592 }
4593
4594 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4595         if (!player)
4596                 return false;
4597         if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4598                 return false;
4599
4600         std::ostringstream os(std::ios::binary);
4601         writeS32(os, hotbar_itemcount);
4602         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4603         return true;
4604 }
4605
4606 void Server::hudSetHotbarImage(Player *player, std::string name) {
4607         if (!player)
4608                 return;
4609
4610         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4611 }
4612
4613 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4614         if (!player)
4615                 return;
4616
4617         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4618 }
4619
4620 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4621 {
4622         if (!player)
4623                 return false;
4624
4625         SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4626         return true;
4627 }
4628
4629 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4630 {
4631         if (!player)
4632                 return false;
4633
4634         SendEyeOffset(player->peer_id, first, third);
4635         return true;
4636 }
4637
4638 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4639                 const std::string &type, const std::vector<std::string> &params)
4640 {
4641         if (!player)
4642                 return false;
4643
4644         SendSetSky(player->peer_id, bgcolor, type, params);
4645         return true;
4646 }
4647
4648 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4649                 float ratio)
4650 {
4651         if (!player)
4652                 return false;
4653
4654         SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4655         return true;
4656 }
4657
4658 void Server::notifyPlayers(const std::wstring &msg)
4659 {
4660         SendChatMessage(PEER_ID_INEXISTENT,msg);
4661 }
4662
4663 void Server::spawnParticle(const char *playername, v3f pos,
4664                 v3f velocity, v3f acceleration,
4665                 float expirationtime, float size, bool
4666                 collisiondetection, bool vertical, std::string texture)
4667 {
4668         Player *player = m_env->getPlayer(playername);
4669         if(!player)
4670                 return;
4671         SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4672                         expirationtime, size, collisiondetection, vertical, texture);
4673 }
4674
4675 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4676                 float expirationtime, float size,
4677                 bool collisiondetection, bool vertical, std::string texture)
4678 {
4679         SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4680                         expirationtime, size, collisiondetection, vertical, texture);
4681 }
4682
4683 u32 Server::addParticleSpawner(const char *playername,
4684                 u16 amount, float spawntime,
4685                 v3f minpos, v3f maxpos,
4686                 v3f minvel, v3f maxvel,
4687                 v3f minacc, v3f maxacc,
4688                 float minexptime, float maxexptime,
4689                 float minsize, float maxsize,
4690                 bool collisiondetection, bool vertical, std::string texture)
4691 {
4692         Player *player = m_env->getPlayer(playername);
4693         if(!player)
4694                 return -1;
4695
4696         u32 id = 0;
4697         for(;;) // look for unused particlespawner id
4698         {
4699                 id++;
4700                 if (std::find(m_particlespawner_ids.begin(),
4701                                 m_particlespawner_ids.end(), id)
4702                                 == m_particlespawner_ids.end())
4703                 {
4704                         m_particlespawner_ids.push_back(id);
4705                         break;
4706                 }
4707         }
4708
4709         SendAddParticleSpawner(player->peer_id, amount, spawntime,
4710                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4711                 minexptime, maxexptime, minsize, maxsize,
4712                 collisiondetection, vertical, texture, id);
4713
4714         return id;
4715 }
4716
4717 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4718                 v3f minpos, v3f maxpos,
4719                 v3f minvel, v3f maxvel,
4720                 v3f minacc, v3f maxacc,
4721                 float minexptime, float maxexptime,
4722                 float minsize, float maxsize,
4723                 bool collisiondetection, bool vertical, std::string texture)
4724 {
4725         u32 id = 0;
4726         for(;;) // look for unused particlespawner id
4727         {
4728                 id++;
4729                 if (std::find(m_particlespawner_ids.begin(),
4730                                 m_particlespawner_ids.end(), id)
4731                                 == m_particlespawner_ids.end())
4732                 {
4733                         m_particlespawner_ids.push_back(id);
4734                         break;
4735                 }
4736         }
4737
4738         SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4739                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4740                 minexptime, maxexptime, minsize, maxsize,
4741                 collisiondetection, vertical, texture, id);
4742
4743         return id;
4744 }
4745
4746 void Server::deleteParticleSpawner(const char *playername, u32 id)
4747 {
4748         Player *player = m_env->getPlayer(playername);
4749         if(!player)
4750                 return;
4751
4752         m_particlespawner_ids.erase(
4753                         std::remove(m_particlespawner_ids.begin(),
4754                         m_particlespawner_ids.end(), id),
4755                         m_particlespawner_ids.end());
4756         SendDeleteParticleSpawner(player->peer_id, id);
4757 }
4758
4759 void Server::deleteParticleSpawnerAll(u32 id)
4760 {
4761         m_particlespawner_ids.erase(
4762                         std::remove(m_particlespawner_ids.begin(),
4763                         m_particlespawner_ids.end(), id),
4764                         m_particlespawner_ids.end());
4765         SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4766 }
4767
4768 Inventory* Server::createDetachedInventory(const std::string &name)
4769 {
4770         if(m_detached_inventories.count(name) > 0){
4771                 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4772                 delete m_detached_inventories[name];
4773         } else {
4774                 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4775         }
4776         Inventory *inv = new Inventory(m_itemdef);
4777         assert(inv);
4778         m_detached_inventories[name] = inv;
4779         //TODO find a better way to do this
4780         sendDetachedInventory(name,PEER_ID_INEXISTENT);
4781         return inv;
4782 }
4783
4784 class BoolScopeSet
4785 {
4786 public:
4787         BoolScopeSet(bool *dst, bool val):
4788                 m_dst(dst)
4789         {
4790                 m_orig_state = *m_dst;
4791                 *m_dst = val;
4792         }
4793         ~BoolScopeSet()
4794         {
4795                 *m_dst = m_orig_state;
4796         }
4797 private:
4798         bool *m_dst;
4799         bool m_orig_state;
4800 };
4801
4802 // actions: time-reversed list
4803 // Return value: success/failure
4804 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4805                 std::list<std::string> *log)
4806 {
4807         infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4808         ServerMap *map = (ServerMap*)(&m_env->getMap());
4809         // Disable rollback report sink while reverting
4810         BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4811
4812         // Fail if no actions to handle
4813         if(actions.empty()){
4814                 log->push_back("Nothing to do.");
4815                 return false;
4816         }
4817
4818         int num_tried = 0;
4819         int num_failed = 0;
4820
4821         for(std::list<RollbackAction>::const_iterator
4822                         i = actions.begin();
4823                         i != actions.end(); i++)
4824         {
4825                 const RollbackAction &action = *i;
4826                 num_tried++;
4827                 bool success = action.applyRevert(map, this, this);
4828                 if(!success){
4829                         num_failed++;
4830                         std::ostringstream os;
4831                         os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4832                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4833                         if(log)
4834                                 log->push_back(os.str());
4835                 }else{
4836                         std::ostringstream os;
4837                         os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4838                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4839                         if(log)
4840                                 log->push_back(os.str());
4841                 }
4842         }
4843
4844         infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4845                         <<" failed"<<std::endl;
4846
4847         // Call it done if less than half failed
4848         return num_failed <= num_tried/2;
4849 }
4850
4851 // IGameDef interface
4852 // Under envlock
4853 IItemDefManager* Server::getItemDefManager()
4854 {
4855         return m_itemdef;
4856 }
4857 INodeDefManager* Server::getNodeDefManager()
4858 {
4859         return m_nodedef;
4860 }
4861 ICraftDefManager* Server::getCraftDefManager()
4862 {
4863         return m_craftdef;
4864 }
4865 ITextureSource* Server::getTextureSource()
4866 {
4867         return NULL;
4868 }
4869 IShaderSource* Server::getShaderSource()
4870 {
4871         return NULL;
4872 }
4873 u16 Server::allocateUnknownNodeId(const std::string &name)
4874 {
4875         return m_nodedef->allocateDummy(name);
4876 }
4877 ISoundManager* Server::getSoundManager()
4878 {
4879         return &dummySoundManager;
4880 }
4881 MtEventManager* Server::getEventManager()
4882 {
4883         return m_event;
4884 }
4885 IRollbackReportSink* Server::getRollbackReportSink()
4886 {
4887         if(!m_enable_rollback_recording)
4888                 return NULL;
4889         if(!m_rollback_sink_enabled)
4890                 return NULL;
4891         return m_rollback;
4892 }
4893
4894 IWritableItemDefManager* Server::getWritableItemDefManager()
4895 {
4896         return m_itemdef;
4897 }
4898 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4899 {
4900         return m_nodedef;
4901 }
4902 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4903 {
4904         return m_craftdef;
4905 }
4906
4907 const ModSpec* Server::getModSpec(const std::string &modname)
4908 {
4909         for(std::vector<ModSpec>::iterator i = m_mods.begin();
4910                         i != m_mods.end(); i++){
4911                 const ModSpec &mod = *i;
4912                 if(mod.name == modname)
4913                         return &mod;
4914         }
4915         return NULL;
4916 }
4917 void Server::getModNames(std::list<std::string> &modlist)
4918 {
4919         for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4920         {
4921                 modlist.push_back(i->name);
4922         }
4923 }
4924 std::string Server::getBuiltinLuaPath()
4925 {
4926         return porting::path_share + DIR_DELIM + "builtin";
4927 }
4928
4929 v3f findSpawnPos(ServerMap &map)
4930 {
4931         //return v3f(50,50,50)*BS;
4932
4933         v3s16 nodepos;
4934
4935 #if 0
4936         nodepos = v2s16(0,0);
4937         groundheight = 20;
4938 #endif
4939
4940 #if 1
4941         s16 water_level = map.getWaterLevel();
4942
4943         // Try to find a good place a few times
4944         for(s32 i=0; i<1000; i++)
4945         {
4946                 s32 range = 1 + i;
4947                 // We're going to try to throw the player to this position
4948                 v2s16 nodepos2d = v2s16(
4949                                 -range + (myrand() % (range * 2)),
4950                                 -range + (myrand() % (range * 2)));
4951
4952                 // Get ground height at point
4953                 s16 groundheight = map.findGroundLevel(nodepos2d);
4954                 if (groundheight <= water_level) // Don't go underwater
4955                         continue;
4956                 if (groundheight > water_level + 6) // Don't go to high places
4957                         continue;
4958
4959                 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4960                 bool is_good = false;
4961                 s32 air_count = 0;
4962                 for (s32 i = 0; i < 10; i++) {
4963                         v3s16 blockpos = getNodeBlockPos(nodepos);
4964                         map.emergeBlock(blockpos, true);
4965                         content_t c = map.getNodeNoEx(nodepos).getContent();
4966                         if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4967                                 air_count++;
4968                                 if (air_count >= 2){
4969                                         is_good = true;
4970                                         break;
4971                                 }
4972                         }
4973                         nodepos.Y++;
4974                 }
4975                 if(is_good){
4976                         // Found a good place
4977                         //infostream<<"Searched through "<<i<<" places."<<std::endl;
4978                         break;
4979                 }
4980         }
4981 #endif
4982
4983         return intToFloat(nodepos, BS);
4984 }
4985
4986 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4987 {
4988         RemotePlayer *player = NULL;
4989         bool newplayer = false;
4990
4991         /*
4992                 Try to get an existing player
4993         */
4994         player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4995
4996         // If player is already connected, cancel
4997         if(player != NULL && player->peer_id != 0)
4998         {
4999                 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5000                 return NULL;
5001         }
5002
5003         /*
5004                 If player with the wanted peer_id already exists, cancel.
5005         */
5006         if(m_env->getPlayer(peer_id) != NULL)
5007         {
5008                 infostream<<"emergePlayer(): Player with wrong name but same"
5009                                 " peer_id already exists"<<std::endl;
5010                 return NULL;
5011         }
5012
5013         /*
5014                 Create a new player if it doesn't exist yet
5015         */
5016         if(player == NULL)
5017         {
5018                 newplayer = true;
5019                 player = new RemotePlayer(this);
5020                 player->updateName(name);
5021
5022                 /* Set player position */
5023                 infostream<<"Server: Finding spawn place for player \""
5024                                 <<name<<"\""<<std::endl;
5025                 v3f pos = findSpawnPos(m_env->getServerMap());
5026                 player->setPosition(pos);
5027
5028                 /* Add player to environment */
5029                 m_env->addPlayer(player);
5030         }
5031
5032         /*
5033                 Create a new player active object
5034         */
5035         PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5036                         getPlayerEffectivePrivs(player->getName()),
5037                         isSingleplayer());
5038
5039         /* Clean up old HUD elements from previous sessions */
5040         player->hud.clear();
5041
5042         /* Add object to environment */
5043         m_env->addActiveObject(playersao);
5044
5045         /* Run scripts */
5046         if(newplayer)
5047                 m_script->on_newplayer(playersao);
5048
5049         return playersao;
5050 }
5051
5052 void dedicated_server_loop(Server &server, bool &kill)
5053 {
5054         DSTACK(__FUNCTION_NAME);
5055
5056         verbosestream<<"dedicated_server_loop()"<<std::endl;
5057
5058         IntervalLimiter m_profiler_interval;
5059
5060         for(;;)
5061         {
5062                 float steplen = g_settings->getFloat("dedicated_server_step");
5063                 // This is kind of a hack but can be done like this
5064                 // because server.step() is very light
5065                 {
5066                         ScopeProfiler sp(g_profiler, "dedicated server sleep");
5067                         sleep_ms((int)(steplen*1000.0));
5068                 }
5069                 server.step(steplen);
5070
5071                 if(server.getShutdownRequested() || kill)
5072                 {
5073                         infostream<<"Dedicated server quitting"<<std::endl;
5074 #if USE_CURL
5075                         if(g_settings->getBool("server_announce") == true)
5076                                 ServerList::sendAnnounce("delete");
5077 #endif
5078                         break;
5079                 }
5080
5081                 /*
5082                         Profiler
5083                 */
5084                 float profiler_print_interval =
5085                                 g_settings->getFloat("profiler_print_interval");
5086                 if(profiler_print_interval != 0)
5087                 {
5088                         if(m_profiler_interval.step(steplen, profiler_print_interval))
5089                         {
5090                                 infostream<<"Profiler:"<<std::endl;
5091                                 g_profiler->print(infostream);
5092                                 g_profiler->clear();
5093                         }
5094                 }
5095         }
5096 }
5097
5098