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