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