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