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