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