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