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