]> git.lizzy.rs Git - dragonfireclient.git/blob - src/server.cpp
Server::AsyncRunStep: buffered_messages now uses std::vector instead of std::list...
[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 "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
26 #include "ban.h"
27 #include "environment.h"
28 #include "map.h"
29 #include "jthread/jmutexautolock.h"
30 #include "main.h"
31 #include "constants.h"
32 #include "voxel.h"
33 #include "config.h"
34 #include "version.h"
35 #include "filesys.h"
36 #include "mapblock.h"
37 #include "serverobject.h"
38 #include "genericobject.h"
39 #include "settings.h"
40 #include "profiler.h"
41 #include "log.h"
42 #include "scripting_game.h"
43 #include "nodedef.h"
44 #include "itemdef.h"
45 #include "craftdef.h"
46 #include "emerge.h"
47 #include "mapgen.h"
48 #include "mg_biome.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_abm.h"
52 #include "content_sao.h"
53 #include "mods.h"
54 #include "sound.h" // dummySoundManager
55 #include "event_manager.h"
56 #include "serverlist.h"
57 #include "util/string.h"
58 #include "util/mathconstants.h"
59 #include "rollback.h"
60 #include "util/serialize.h"
61 #include "util/thread.h"
62 #include "defaultsettings.h"
63 #include "util/base64.h"
64 #include "util/sha1.h"
65 #include "util/hex.h"
66
67 class ClientNotFoundException : public BaseException
68 {
69 public:
70         ClientNotFoundException(const char *s):
71                 BaseException(s)
72         {}
73 };
74
75 class ServerThread : public JThread
76 {
77         Server *m_server;
78
79 public:
80
81         ServerThread(Server *server):
82                 JThread(),
83                 m_server(server)
84         {
85         }
86
87         void * Thread();
88 };
89
90 void * ServerThread::Thread()
91 {
92         log_register_thread("ServerThread");
93
94         DSTACK(__FUNCTION_NAME);
95         BEGIN_DEBUG_EXCEPTION_HANDLER
96
97         m_server->AsyncRunStep(true);
98
99         ThreadStarted();
100
101         porting::setThreadName("ServerThread");
102
103         while(!StopRequested())
104         {
105                 try{
106                         //TimeTaker timer("AsyncRunStep() + Receive()");
107
108                         m_server->AsyncRunStep();
109
110                         m_server->Receive();
111
112                 }
113                 catch(con::NoIncomingDataException &e)
114                 {
115                 }
116                 catch(con::PeerNotFoundException &e)
117                 {
118                         infostream<<"Server: PeerNotFoundException"<<std::endl;
119                 }
120                 catch(ClientNotFoundException &e)
121                 {
122                 }
123                 catch(con::ConnectionBindFailed &e)
124                 {
125                         m_server->setAsyncFatalError(e.what());
126                 }
127                 catch(LuaError &e)
128                 {
129                         m_server->setAsyncFatalError(e.what());
130                 }
131         }
132
133         END_DEBUG_EXCEPTION_HANDLER(errorstream)
134
135         return NULL;
136 }
137
138 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
139 {
140         if(pos_exists) *pos_exists = false;
141         switch(type){
142         case SSP_LOCAL:
143                 return v3f(0,0,0);
144         case SSP_POSITIONAL:
145                 if(pos_exists) *pos_exists = true;
146                 return pos;
147         case SSP_OBJECT: {
148                 if(object == 0)
149                         return v3f(0,0,0);
150                 ServerActiveObject *sao = env->getActiveObject(object);
151                 if(!sao)
152                         return v3f(0,0,0);
153                 if(pos_exists) *pos_exists = true;
154                 return sao->getBasePosition(); }
155         }
156         return v3f(0,0,0);
157 }
158
159
160
161 /*
162         Server
163 */
164
165 Server::Server(
166                 const std::string &path_world,
167                 const SubgameSpec &gamespec,
168                 bool simple_singleplayer_mode,
169                 bool ipv6
170         ):
171         m_path_world(path_world),
172         m_gamespec(gamespec),
173         m_simple_singleplayer_mode(simple_singleplayer_mode),
174         m_async_fatal_error(""),
175         m_env(NULL),
176         m_con(PROTOCOL_ID,
177                         512,
178                         CONNECTION_TIMEOUT,
179                         ipv6,
180                         this),
181         m_banmanager(NULL),
182         m_rollback(NULL),
183         m_enable_rollback_recording(false),
184         m_emerge(NULL),
185         m_script(NULL),
186         m_itemdef(createItemDefManager()),
187         m_nodedef(createNodeDefManager()),
188         m_craftdef(createCraftDefManager()),
189         m_event(new EventManager()),
190         m_thread(NULL),
191         m_time_of_day_send_timer(0),
192         m_uptime(0),
193         m_clients(&m_con),
194         m_shutdown_requested(false),
195         m_ignore_map_edit_events(false),
196         m_ignore_map_edit_events_peer_id(0),
197         m_next_sound_id(0)
198
199 {
200         m_liquid_transform_timer = 0.0;
201         m_liquid_transform_every = 1.0;
202         m_print_info_timer = 0.0;
203         m_masterserver_timer = 0.0;
204         m_objectdata_timer = 0.0;
205         m_emergethread_trigger_timer = 0.0;
206         m_savemap_timer = 0.0;
207
208         m_step_dtime = 0.0;
209         m_lag = g_settings->getFloat("dedicated_server_step");
210
211         if(path_world == "")
212                 throw ServerError("Supplied empty world path");
213
214         if(!gamespec.isValid())
215                 throw ServerError("Supplied invalid gamespec");
216
217         infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
218         if(m_simple_singleplayer_mode)
219                 infostream<<" in simple singleplayer mode"<<std::endl;
220         else
221                 infostream<<std::endl;
222         infostream<<"- world:  "<<m_path_world<<std::endl;
223         infostream<<"- game:   "<<m_gamespec.path<<std::endl;
224
225         // Initialize default settings and override defaults with those provided
226         // by the game
227         set_default_settings(g_settings);
228         Settings gamedefaults;
229         getGameMinetestConfig(gamespec.path, gamedefaults);
230         override_default_settings(g_settings, &gamedefaults);
231
232         // Create server thread
233         m_thread = new ServerThread(this);
234
235         // Create emerge manager
236         m_emerge = new EmergeManager(this);
237
238         // Create world if it doesn't exist
239         if(!initializeWorld(m_path_world, m_gamespec.id))
240                 throw ServerError("Failed to initialize world");
241
242         // Create ban manager
243         std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
244         m_banmanager = new BanManager(ban_path);
245
246         ModConfiguration modconf(m_path_world);
247         m_mods = modconf.getMods();
248         std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
249         // complain about mods with unsatisfied dependencies
250         if(!modconf.isConsistent())
251         {
252                 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
253                         it != unsatisfied_mods.end(); ++it)
254                 {
255                         ModSpec mod = *it;
256                         errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
257                         for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
258                                 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
259                                 errorstream << " \"" << *dep_it << "\"";
260                         errorstream << std::endl;
261                 }
262         }
263
264         Settings worldmt_settings;
265         std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
266         worldmt_settings.readConfigFile(worldmt.c_str());
267         std::vector<std::string> names = worldmt_settings.getNames();
268         std::set<std::string> load_mod_names;
269         for(std::vector<std::string>::iterator it = names.begin();
270                 it != names.end(); ++it)
271         {
272                 std::string name = *it;
273                 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
274                         load_mod_names.insert(name.substr(9));
275         }
276         // complain about mods declared to be loaded, but not found
277         for(std::vector<ModSpec>::iterator it = m_mods.begin();
278                         it != m_mods.end(); ++it)
279                 load_mod_names.erase((*it).name);
280         for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
281                         it != unsatisfied_mods.end(); ++it)
282                 load_mod_names.erase((*it).name);
283         if(!load_mod_names.empty())
284         {
285                 errorstream << "The following mods could not be found:";
286                 for(std::set<std::string>::iterator it = load_mod_names.begin();
287                         it != load_mod_names.end(); ++it)
288                         errorstream << " \"" << (*it) << "\"";
289                 errorstream << std::endl;
290         }
291
292         // Lock environment
293         JMutexAutoLock envlock(m_env_mutex);
294
295         // Load mapgen params from Settings
296         m_emerge->loadMapgenParams();
297
298         // Create the Map (loads map_meta.txt, overriding configured mapgen params)
299         ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
300
301         // Initialize scripting
302         infostream<<"Server: Initializing Lua"<<std::endl;
303
304         m_script = new GameScripting(this);
305
306         std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
307
308         if (!m_script->loadScript(scriptpath))
309                 throw ModError("Failed to load and run " + scriptpath);
310
311         // Print 'em
312         infostream<<"Server: Loading mods: ";
313         for(std::vector<ModSpec>::iterator i = m_mods.begin();
314                         i != m_mods.end(); i++){
315                 const ModSpec &mod = *i;
316                 infostream<<mod.name<<" ";
317         }
318         infostream<<std::endl;
319         // Load and run "mod" scripts
320         for(std::vector<ModSpec>::iterator i = m_mods.begin();
321                         i != m_mods.end(); i++){
322                 const ModSpec &mod = *i;
323                 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
324                 infostream<<"  ["<<padStringRight(mod.name, 12)<<"] [\""
325                                 <<scriptpath<<"\"]"<<std::endl;
326                 bool success = m_script->loadMod(scriptpath, mod.name);
327                 if(!success){
328                         errorstream<<"Server: Failed to load and run "
329                                         <<scriptpath<<std::endl;
330                         throw ModError("Failed to load and run "+scriptpath);
331                 }
332         }
333
334         // Read Textures and calculate sha1 sums
335         fillMediaCache();
336
337         // Apply item aliases in the node definition manager
338         m_nodedef->updateAliases(m_itemdef);
339
340         m_nodedef->setNodeRegistrationStatus(true);
341
342         // Perform pending node name resolutions
343         m_nodedef->runNodeResolverCallbacks();
344
345         // Initialize Environment
346         m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
347
348         m_clients.setEnv(m_env);
349
350         // Initialize mapgens
351         m_emerge->initMapgens();
352
353         m_enable_rollback_recording = g_settings->getBool("enable_rollback_recording");
354         if (m_enable_rollback_recording) {
355                 // Create rollback manager
356                 m_rollback = new RollbackManager(m_path_world, this);
357         }
358
359         // Give environment reference to scripting api
360         m_script->initializeEnvironment(m_env);
361
362         // Register us to receive map edit events
363         servermap->addEventReceiver(this);
364
365         // If file exists, load environment metadata
366         if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
367         {
368                 infostream<<"Server: Loading environment metadata"<<std::endl;
369                 m_env->loadMeta();
370         }
371
372         // Add some test ActiveBlockModifiers to environment
373         add_legacy_abms(m_env, m_nodedef);
374
375         m_liquid_transform_every = g_settings->getFloat("liquid_update");
376 }
377
378 Server::~Server()
379 {
380         infostream<<"Server destructing"<<std::endl;
381
382         // Send shutdown message
383         SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
384
385         {
386                 JMutexAutoLock envlock(m_env_mutex);
387
388                 // Execute script shutdown hooks
389                 m_script->on_shutdown();
390
391                 infostream<<"Server: Saving players"<<std::endl;
392                 m_env->saveLoadedPlayers();
393
394                 infostream<<"Server: Saving environment metadata"<<std::endl;
395                 m_env->saveMeta();
396         }
397
398         // Stop threads
399         stop();
400         delete m_thread;
401
402         // stop all emerge threads before deleting players that may have
403         // requested blocks to be emerged
404         m_emerge->stopThreads();
405
406         // Delete things in the reverse order of creation
407         delete m_env;
408
409         // N.B. the EmergeManager should be deleted after the Environment since Map
410         // depends on EmergeManager to write its current params to the map meta
411         delete m_emerge;
412         delete m_rollback;
413         delete m_banmanager;
414         delete m_event;
415         delete m_itemdef;
416         delete m_nodedef;
417         delete m_craftdef;
418
419         // Deinitialize scripting
420         infostream<<"Server: Deinitializing scripting"<<std::endl;
421         delete m_script;
422
423         // Delete detached inventories
424         for (std::map<std::string, Inventory*>::iterator
425                         i = m_detached_inventories.begin();
426                         i != m_detached_inventories.end(); i++) {
427                 delete i->second;
428         }
429 }
430
431 void Server::start(Address bind_addr)
432 {
433         DSTACK(__FUNCTION_NAME);
434
435         m_bind_addr = bind_addr;
436
437         infostream<<"Starting server on "
438                         << bind_addr.serializeString() <<"..."<<std::endl;
439
440         // Stop thread if already running
441         m_thread->Stop();
442
443         // Initialize connection
444         m_con.SetTimeoutMs(30);
445         m_con.Serve(bind_addr);
446
447         // Start thread
448         m_thread->Start();
449
450         // ASCII art for the win!
451         actionstream
452         <<"        .__               __                   __   "<<std::endl
453         <<"  _____ |__| ____   _____/  |_  ____   _______/  |_ "<<std::endl
454         <<" /     \\|  |/    \\_/ __ \\   __\\/ __ \\ /  ___/\\   __\\"<<std::endl
455         <<"|  Y Y  \\  |   |  \\  ___/|  | \\  ___/ \\___ \\  |  |  "<<std::endl
456         <<"|__|_|  /__|___|  /\\___  >__|  \\___  >____  > |__|  "<<std::endl
457         <<"      \\/        \\/     \\/          \\/     \\/        "<<std::endl;
458         actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
459         actionstream<<"Server for gameid=\""<<m_gamespec.id
460                         <<"\" listening on "<<bind_addr.serializeString()<<":"
461                         <<bind_addr.getPort() << "."<<std::endl;
462 }
463
464 void Server::stop()
465 {
466         DSTACK(__FUNCTION_NAME);
467
468         infostream<<"Server: Stopping and waiting threads"<<std::endl;
469
470         // Stop threads (set run=false first so both start stopping)
471         m_thread->Stop();
472         //m_emergethread.setRun(false);
473         m_thread->Wait();
474         //m_emergethread.stop();
475
476         infostream<<"Server: Threads stopped"<<std::endl;
477 }
478
479 void Server::step(float dtime)
480 {
481         DSTACK(__FUNCTION_NAME);
482         // Limit a bit
483         if(dtime > 2.0)
484                 dtime = 2.0;
485         {
486                 JMutexAutoLock lock(m_step_dtime_mutex);
487                 m_step_dtime += dtime;
488         }
489         // Throw if fatal error occurred in thread
490         std::string async_err = m_async_fatal_error.get();
491         if(async_err != ""){
492                 throw ServerError(async_err);
493         }
494 }
495
496 void Server::AsyncRunStep(bool initial_step)
497 {
498         DSTACK(__FUNCTION_NAME);
499
500         g_profiler->add("Server::AsyncRunStep (num)", 1);
501
502         float dtime;
503         {
504                 JMutexAutoLock lock1(m_step_dtime_mutex);
505                 dtime = m_step_dtime;
506         }
507
508         {
509                 // Send blocks to clients
510                 SendBlocks(dtime);
511         }
512
513         if((dtime < 0.001) && (initial_step == false))
514                 return;
515
516         g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
517
518         //infostream<<"Server steps "<<dtime<<std::endl;
519         //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
520
521         {
522                 JMutexAutoLock lock1(m_step_dtime_mutex);
523                 m_step_dtime -= dtime;
524         }
525
526         /*
527                 Update uptime
528         */
529         {
530                 m_uptime.set(m_uptime.get() + dtime);
531         }
532
533         handlePeerChanges();
534
535         /*
536                 Update time of day and overall game time
537         */
538         m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
539
540         /*
541                 Send to clients at constant intervals
542         */
543
544         m_time_of_day_send_timer -= dtime;
545         if(m_time_of_day_send_timer < 0.0) {
546                 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
547                 u16 time = m_env->getTimeOfDay();
548                 float time_speed = g_settings->getFloat("time_speed");
549                 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
550         }
551
552         {
553                 JMutexAutoLock lock(m_env_mutex);
554                 // Figure out and report maximum lag to environment
555                 float max_lag = m_env->getMaxLagEstimate();
556                 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
557                 if(dtime > max_lag){
558                         if(dtime > 0.1 && dtime > max_lag * 2.0)
559                                 infostream<<"Server: Maximum lag peaked to "<<dtime
560                                                 <<" s"<<std::endl;
561                         max_lag = dtime;
562                 }
563                 m_env->reportMaxLagEstimate(max_lag);
564                 // Step environment
565                 ScopeProfiler sp(g_profiler, "SEnv step");
566                 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
567                 m_env->step(dtime);
568         }
569
570         static const float map_timer_and_unload_dtime = 2.92;
571         if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
572         {
573                 JMutexAutoLock lock(m_env_mutex);
574                 // Run Map's timers and unload unused data
575                 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
576                 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
577                                 g_settings->getFloat("server_unload_unused_data_timeout"));
578         }
579
580         /*
581                 Do background stuff
582         */
583
584         /* Transform liquids */
585         m_liquid_transform_timer += dtime;
586         if(m_liquid_transform_timer >= m_liquid_transform_every)
587         {
588                 m_liquid_transform_timer -= m_liquid_transform_every;
589
590                 JMutexAutoLock lock(m_env_mutex);
591
592                 ScopeProfiler sp(g_profiler, "Server: liquid transform");
593
594                 std::map<v3s16, MapBlock*> modified_blocks;
595                 m_env->getMap().transformLiquids(modified_blocks);
596 #if 0
597                 /*
598                         Update lighting
599                 */
600                 core::map<v3s16, MapBlock*> lighting_modified_blocks;
601                 ServerMap &map = ((ServerMap&)m_env->getMap());
602                 map.updateLighting(modified_blocks, lighting_modified_blocks);
603
604                 // Add blocks modified by lighting to modified_blocks
605                 for(core::map<v3s16, MapBlock*>::Iterator
606                                 i = lighting_modified_blocks.getIterator();
607                                 i.atEnd() == false; i++)
608                 {
609                         MapBlock *block = i.getNode()->getValue();
610                         modified_blocks.insert(block->getPos(), block);
611                 }
612 #endif
613                 /*
614                         Set the modified blocks unsent for all the clients
615                 */
616                 if(!modified_blocks.empty())
617                 {
618                         SetBlocksNotSent(modified_blocks);
619                 }
620         }
621         m_clients.step(dtime);
622
623         m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
624 #if USE_CURL
625         // send masterserver announce
626         {
627                 float &counter = m_masterserver_timer;
628                 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
629                                 g_settings->getBool("server_announce"))
630                 {
631                         ServerList::sendAnnounce(counter ? "update" : "start",
632                                         m_bind_addr.getPort(),
633                                         m_clients.getPlayerNames(),
634                                         m_uptime.get(),
635                                         m_env->getGameTime(),
636                                         m_lag,
637                                         m_gamespec.id,
638                                         m_emerge->params.mg_name,
639                                         m_mods);
640                         counter = 0.01;
641                 }
642                 counter += dtime;
643         }
644 #endif
645
646         /*
647                 Check added and deleted active objects
648         */
649         {
650                 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
651                 JMutexAutoLock envlock(m_env_mutex);
652
653                 m_clients.Lock();
654                 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
655                 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
656
657                 // Radius inside which objects are active
658                 s16 radius = g_settings->getS16("active_object_send_range_blocks");
659                 s16 player_radius = g_settings->getS16("player_transfer_distance");
660
661                 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
662                                 !g_settings->getBool("unlimited_player_transfer_distance"))
663                         player_radius = radius;
664
665                 radius *= MAP_BLOCKSIZE;
666                 player_radius *= MAP_BLOCKSIZE;
667
668                 for(std::map<u16, RemoteClient*>::iterator
669                         i = clients.begin();
670                         i != clients.end(); ++i)
671                 {
672                         RemoteClient *client = i->second;
673
674                         // If definitions and textures have not been sent, don't
675                         // send objects either
676                         if (client->getState() < CS_DefinitionsSent)
677                                 continue;
678
679                         Player *player = m_env->getPlayer(client->peer_id);
680                         if(player==NULL)
681                         {
682                                 // This can happen if the client timeouts somehow
683                                 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
684                                                 <<client->peer_id
685                                                 <<" has no associated player"<<std::endl;*/
686                                 continue;
687                         }
688                         v3s16 pos = floatToInt(player->getPosition(), BS);
689
690                         std::set<u16> removed_objects;
691                         std::set<u16> added_objects;
692                         m_env->getRemovedActiveObjects(pos, radius, player_radius,
693                                         client->m_known_objects, removed_objects);
694                         m_env->getAddedActiveObjects(pos, radius, player_radius,
695                                         client->m_known_objects, added_objects);
696
697                         // Ignore if nothing happened
698                         if(removed_objects.empty() && added_objects.empty())
699                         {
700                                 //infostream<<"active objects: none changed"<<std::endl;
701                                 continue;
702                         }
703
704                         std::string data_buffer;
705
706                         char buf[4];
707
708                         // Handle removed objects
709                         writeU16((u8*)buf, removed_objects.size());
710                         data_buffer.append(buf, 2);
711                         for(std::set<u16>::iterator
712                                         i = removed_objects.begin();
713                                         i != removed_objects.end(); ++i)
714                         {
715                                 // Get object
716                                 u16 id = *i;
717                                 ServerActiveObject* obj = m_env->getActiveObject(id);
718
719                                 // Add to data buffer for sending
720                                 writeU16((u8*)buf, id);
721                                 data_buffer.append(buf, 2);
722
723                                 // Remove from known objects
724                                 client->m_known_objects.erase(id);
725
726                                 if(obj && obj->m_known_by_count > 0)
727                                         obj->m_known_by_count--;
728                         }
729
730                         // Handle added objects
731                         writeU16((u8*)buf, added_objects.size());
732                         data_buffer.append(buf, 2);
733                         for(std::set<u16>::iterator
734                                         i = added_objects.begin();
735                                         i != added_objects.end(); ++i)
736                         {
737                                 // Get object
738                                 u16 id = *i;
739                                 ServerActiveObject* obj = m_env->getActiveObject(id);
740
741                                 // Get object type
742                                 u8 type = ACTIVEOBJECT_TYPE_INVALID;
743                                 if(obj == NULL)
744                                         infostream<<"WARNING: "<<__FUNCTION_NAME
745                                                         <<": NULL object"<<std::endl;
746                                 else
747                                         type = obj->getSendType();
748
749                                 // Add to data buffer for sending
750                                 writeU16((u8*)buf, id);
751                                 data_buffer.append(buf, 2);
752                                 writeU8((u8*)buf, type);
753                                 data_buffer.append(buf, 1);
754
755                                 if(obj)
756                                         data_buffer.append(serializeLongString(
757                                                         obj->getClientInitializationData(client->net_proto_version)));
758                                 else
759                                         data_buffer.append(serializeLongString(""));
760
761                                 // Add to known objects
762                                 client->m_known_objects.insert(id);
763
764                                 if(obj)
765                                         obj->m_known_by_count++;
766                         }
767
768                         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 0, client->peer_id);
769                         pkt->putRawString(data_buffer.c_str(), data_buffer.size());
770
771
772                         verbosestream << "Server: Sent object remove/add: "
773                                         << removed_objects.size() << " removed, "
774                                         << added_objects.size() << " added, "
775                                         << "packet size is " << pkt->getSize() << std::endl;
776
777                         Send(pkt);
778                 }
779                 m_clients.Unlock();
780         }
781
782         /*
783                 Send object messages
784         */
785         {
786                 JMutexAutoLock envlock(m_env_mutex);
787                 ScopeProfiler sp(g_profiler, "Server: sending object messages");
788
789                 // Key = object id
790                 // Value = data sent by object
791                 std::map<u16, std::vector<ActiveObjectMessage>* > buffered_messages;
792
793                 // Get active object messages from environment
794                 for(;;) {
795                         ActiveObjectMessage aom = m_env->getActiveObjectMessage();
796                         if (aom.id == 0)
797                                 break;
798
799                         std::vector<ActiveObjectMessage>* message_list = NULL;
800                         std::map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
801                         n = buffered_messages.find(aom.id);
802                         if (n == buffered_messages.end()) {
803                                 message_list = new std::vector<ActiveObjectMessage>;
804                                 buffered_messages[aom.id] = message_list;
805                         }
806                         else {
807                                 message_list = n->second;
808                         }
809                         message_list->push_back(aom);
810                 }
811
812                 m_clients.Lock();
813                 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
814                 // Route data to every client
815                 for (std::map<u16, RemoteClient*>::iterator
816                         i = clients.begin();
817                         i != clients.end(); ++i) {
818                         RemoteClient *client = i->second;
819                         std::string reliable_data;
820                         std::string unreliable_data;
821                         // Go through all objects in message buffer
822                         for (std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
823                                         j = buffered_messages.begin();
824                                         j != buffered_messages.end(); ++j) {
825                                 // If object is not known by client, skip it
826                                 u16 id = j->first;
827                                 if (client->m_known_objects.find(id) == client->m_known_objects.end())
828                                         continue;
829
830                                 // Get message list of object
831                                 std::vector<ActiveObjectMessage>* list = j->second;
832                                 // Go through every message
833                                 for (std::vector<ActiveObjectMessage>::iterator
834                                                 k = list->begin(); k != list->end(); ++k) {
835                                         // Compose the full new data with header
836                                         ActiveObjectMessage aom = *k;
837                                         std::string new_data;
838                                         // Add object id
839                                         char buf[2];
840                                         writeU16((u8*)&buf[0], aom.id);
841                                         new_data.append(buf, 2);
842                                         // Add data
843                                         new_data += serializeString(aom.datastring);
844                                         // Add data to buffer
845                                         if(aom.reliable)
846                                                 reliable_data += new_data;
847                                         else
848                                                 unreliable_data += new_data;
849                                 }
850                         }
851                         /*
852                                 reliable_data and unreliable_data are now ready.
853                                 Send them.
854                         */
855                         if(reliable_data.size() > 0) {
856                                 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
857                                                 0, client->peer_id);
858
859                                 pkt->putRawString(reliable_data.c_str(), reliable_data.size());
860                                 Send(pkt);
861                         }
862
863                         if(unreliable_data.size() > 0) {
864                                 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
865                                                 0, client->peer_id);
866
867                                 pkt->putRawString(unreliable_data.c_str(), unreliable_data.size());
868                                 Send(pkt);
869                         }
870                 }
871                 m_clients.Unlock();
872
873                 // Clear buffered_messages
874                 for(std::map<u16, std::vector<ActiveObjectMessage>* >::iterator
875                                 i = buffered_messages.begin();
876                                 i != buffered_messages.end(); ++i) {
877                         delete i->second;
878                 }
879         }
880
881         /*
882                 Send queued-for-sending map edit events.
883         */
884         {
885                 // We will be accessing the environment
886                 JMutexAutoLock lock(m_env_mutex);
887
888                 // Don't send too many at a time
889                 //u32 count = 0;
890
891                 // Single change sending is disabled if queue size is not small
892                 bool disable_single_change_sending = false;
893                 if(m_unsent_map_edit_queue.size() >= 4)
894                         disable_single_change_sending = true;
895
896                 int event_count = m_unsent_map_edit_queue.size();
897
898                 // We'll log the amount of each
899                 Profiler prof;
900
901                 while(m_unsent_map_edit_queue.size() != 0)
902                 {
903                         MapEditEvent* event = m_unsent_map_edit_queue.front();
904                         m_unsent_map_edit_queue.pop();
905
906                         // Players far away from the change are stored here.
907                         // Instead of sending the changes, MapBlocks are set not sent
908                         // for them.
909                         std::vector<u16> far_players;
910
911                         switch (event->type) {
912                         case MEET_ADDNODE:
913                         case MEET_SWAPNODE:
914                                 prof.add("MEET_ADDNODE", 1);
915                                 sendAddNode(event->p, event->n, event->already_known_by_peer,
916                                                 &far_players, disable_single_change_sending ? 5 : 30,
917                                                 event->type == MEET_ADDNODE);
918                                 break;
919                         case MEET_REMOVENODE:
920                                 prof.add("MEET_REMOVENODE", 1);
921                                 sendRemoveNode(event->p, event->already_known_by_peer,
922                                                 &far_players, disable_single_change_sending ? 5 : 30);
923                                 break;
924                         case MEET_BLOCK_NODE_METADATA_CHANGED:
925                                 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
926                                                 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
927                                                 setBlockNotSent(event->p);
928                                 break;
929                         case MEET_OTHER:
930                                 infostream << "Server: MEET_OTHER" << std::endl;
931                                 prof.add("MEET_OTHER", 1);
932                                 for(std::set<v3s16>::iterator
933                                                 i = event->modified_blocks.begin();
934                                                 i != event->modified_blocks.end(); ++i) {
935                                         setBlockNotSent(*i);
936                                 }
937                                 break;
938                         default:
939                                 prof.add("unknown", 1);
940                                 infostream << "WARNING: Server: Unknown MapEditEvent "
941                                                 << ((u32)event->type) << std::endl;
942                                 break;
943                         }
944
945                         /*
946                                 Set blocks not sent to far players
947                         */
948                         if(!far_players.empty()) {
949                                 // Convert list format to that wanted by SetBlocksNotSent
950                                 std::map<v3s16, MapBlock*> modified_blocks2;
951                                 for(std::set<v3s16>::iterator
952                                                 i = event->modified_blocks.begin();
953                                                 i != event->modified_blocks.end(); ++i) {
954                                         modified_blocks2[*i] =
955                                                         m_env->getMap().getBlockNoCreateNoEx(*i);
956                                 }
957
958                                 // Set blocks not sent
959                                 for(std::vector<u16>::iterator
960                                                 i = far_players.begin();
961                                                 i != far_players.end(); ++i) {
962                                         if(RemoteClient *client = getClient(*i))
963                                                 client->SetBlocksNotSent(modified_blocks2);
964                                 }
965                         }
966
967                         delete event;
968
969                         /*// Don't send too many at a time
970                         count++;
971                         if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
972                                 break;*/
973                 }
974
975                 if(event_count >= 5){
976                         infostream<<"Server: MapEditEvents:"<<std::endl;
977                         prof.print(infostream);
978                 } else if(event_count != 0){
979                         verbosestream<<"Server: MapEditEvents:"<<std::endl;
980                         prof.print(verbosestream);
981                 }
982
983         }
984
985         /*
986                 Trigger emergethread (it somehow gets to a non-triggered but
987                 bysy state sometimes)
988         */
989         {
990                 float &counter = m_emergethread_trigger_timer;
991                 counter += dtime;
992                 if(counter >= 2.0)
993                 {
994                         counter = 0.0;
995
996                         m_emerge->startThreads();
997                 }
998         }
999
1000         // Save map, players and auth stuff
1001         {
1002                 float &counter = m_savemap_timer;
1003                 counter += dtime;
1004                 if(counter >= g_settings->getFloat("server_map_save_interval"))
1005                 {
1006                         counter = 0.0;
1007                         JMutexAutoLock lock(m_env_mutex);
1008
1009                         ScopeProfiler sp(g_profiler, "Server: saving stuff");
1010
1011                         // Save ban file
1012                         if (m_banmanager->isModified()) {
1013                                 m_banmanager->save();
1014                         }
1015
1016                         // Save changed parts of map
1017                         m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1018
1019                         // Save players
1020                         m_env->saveLoadedPlayers();
1021
1022                         // Save environment metadata
1023                         m_env->saveMeta();
1024                 }
1025         }
1026 }
1027
1028 void Server::Receive()
1029 {
1030         DSTACK(__FUNCTION_NAME);
1031         SharedBuffer<u8> data;
1032         u16 peer_id;
1033         u32 datasize;
1034         try {
1035                 datasize = m_con.Receive(peer_id,data);
1036                 ProcessData(*data, datasize, peer_id);
1037         }
1038         catch(con::InvalidIncomingDataException &e) {
1039                 infostream<<"Server::Receive(): "
1040                                 "InvalidIncomingDataException: what()="
1041                                 <<e.what()<<std::endl;
1042         }
1043         catch(SerializationError &e) {
1044                 infostream<<"Server::Receive(): "
1045                                 "SerializationError: what()="
1046                                 <<e.what()<<std::endl;
1047         }
1048         catch(ClientStateError &e) {
1049                 errorstream << "ProcessData: peer=" << peer_id  << e.what() << std::endl;
1050                 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1051                                 L"Try reconnecting or updating your client");
1052         }
1053         catch(con::PeerNotFoundException &e) {
1054                 // Do nothing
1055         }
1056 }
1057
1058 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1059 {
1060         std::string playername = "";
1061         PlayerSAO *playersao = NULL;
1062         m_clients.Lock();
1063         try {
1064                 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1065                 if (client != NULL) {
1066                         playername = client->getName();
1067                         playersao = emergePlayer(playername.c_str(), peer_id);
1068                 }
1069         } catch (std::exception &e) {
1070                 m_clients.Unlock();
1071                 throw;
1072         }
1073         m_clients.Unlock();
1074
1075         RemotePlayer *player =
1076                 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1077
1078         // If failed, cancel
1079         if((playersao == NULL) || (player == NULL)) {
1080                 if(player && player->peer_id != 0) {
1081                         errorstream<<"Server: "<<playername<<": Failed to emerge player"
1082                                         <<" (player allocated to an another client)"<<std::endl;
1083                         DenyAccess(peer_id, L"Another client is connected with this "
1084                                         L"name. If your client closed unexpectedly, try again in "
1085                                         L"a minute.");
1086                 } else {
1087                         errorstream<<"Server: "<<playername<<": Failed to emerge player"
1088                                         <<std::endl;
1089                         DenyAccess(peer_id, L"Could not allocate player.");
1090                 }
1091                 return NULL;
1092         }
1093
1094         /*
1095                 Send complete position information
1096         */
1097         SendMovePlayer(peer_id);
1098
1099         // Send privileges
1100         SendPlayerPrivileges(peer_id);
1101
1102         // Send inventory formspec
1103         SendPlayerInventoryFormspec(peer_id);
1104
1105         // Send inventory
1106         SendInventory(playersao);
1107
1108         // Send HP
1109         if(g_settings->getBool("enable_damage"))
1110                 SendPlayerHP(peer_id);
1111
1112         // Send Breath
1113         SendPlayerBreath(peer_id);
1114
1115         // Show death screen if necessary
1116         if(player->hp == 0)
1117                 SendDeathscreen(peer_id, false, v3f(0,0,0));
1118
1119         // Note things in chat if not in simple singleplayer mode
1120         if(!m_simple_singleplayer_mode) {
1121                 // Send information about server to player in chat
1122                 SendChatMessage(peer_id, getStatusString());
1123
1124                 // Send information about joining in chat
1125                 {
1126                         std::wstring name = L"unknown";
1127                         Player *player = m_env->getPlayer(peer_id);
1128                         if(player != NULL)
1129                                 name = narrow_to_wide(player->getName());
1130
1131                         std::wstring message;
1132                         message += L"*** ";
1133                         message += name;
1134                         message += L" joined the game.";
1135                         SendChatMessage(PEER_ID_INEXISTENT,message);
1136                 }
1137         }
1138         Address addr = getPeerAddress(player->peer_id);
1139         std::string ip_str = addr.serializeString();
1140         actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1141         /*
1142                 Print out action
1143         */
1144         {
1145                 std::vector<std::string> names = m_clients.getPlayerNames();
1146
1147                 actionstream<<player->getName() <<" joins game. List of players: ";
1148
1149                 for (std::vector<std::string>::iterator i = names.begin();
1150                                 i != names.end(); i++) {
1151                         actionstream << *i << " ";
1152                 }
1153
1154                 actionstream << player->getName() <<std::endl;
1155         }
1156         return playersao;
1157 }
1158
1159 inline void Server::handleCommand(NetworkPacket* pkt)
1160 {
1161         const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1162         (this->*opHandle.handler)(pkt);
1163 }
1164
1165 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1166 {
1167         DSTACK(__FUNCTION_NAME);
1168         // Environment is locked first.
1169         JMutexAutoLock envlock(m_env_mutex);
1170
1171         ScopeProfiler sp(g_profiler, "Server::ProcessData");
1172
1173         try {
1174                 Address address = getPeerAddress(peer_id);
1175                 std::string addr_s = address.serializeString();
1176
1177                 if(m_banmanager->isIpBanned(addr_s)) {
1178                         std::string ban_name = m_banmanager->getBanName(addr_s);
1179                         infostream << "Server: A banned client tried to connect from "
1180                                         << addr_s << "; banned name was "
1181                                         << ban_name << std::endl;
1182                         // This actually doesn't seem to transfer to the client
1183                         DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1184                                         + narrow_to_wide(ban_name));
1185                         return;
1186                 }
1187         }
1188         catch(con::PeerNotFoundException &e) {
1189                 /*
1190                  * no peer for this packet found
1191                  * most common reason is peer timeout, e.g. peer didn't
1192                  * respond for some time, your server was overloaded or
1193                  * things like that.
1194                  */
1195                 infostream << "Server::ProcessData(): Cancelling: peer "
1196                                 << peer_id << " not found" << std::endl;
1197                 return;
1198         }
1199
1200         try {
1201                 if(datasize < 2)
1202                         return;
1203
1204                 NetworkPacket* pkt = new NetworkPacket(data, datasize, peer_id);
1205
1206                 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1207
1208                 // Command must be handled into ToServerCommandHandler
1209                 if (command >= TOSERVER_NUM_MSG_TYPES) {
1210                         infostream << "Server: Ignoring unknown command "
1211                                          << command << std::endl;
1212                 }
1213
1214                 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1215                         handleCommand(pkt);
1216                         delete pkt;
1217                         return;
1218                 }
1219
1220                 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1221
1222                 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1223                         errorstream << "Server::ProcessData(): Cancelling: Peer"
1224                                         " serialization format invalid or not initialized."
1225                                         " Skipping incoming command=" << command << std::endl;
1226
1227                         delete pkt;
1228                         return;
1229                 }
1230
1231                 /* Handle commands related to client startup */
1232                 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1233                         handleCommand(pkt);
1234                         delete pkt;
1235                         return;
1236                 }
1237
1238                 if (m_clients.getClientState(peer_id) < CS_Active) {
1239                         if (command == TOSERVER_PLAYERPOS) return;
1240
1241                         errorstream << "Got packet command: " << command << " for peer id "
1242                                         << peer_id << " but client isn't active yet. Dropping packet "
1243                                         << std::endl;
1244
1245                         delete pkt;
1246                         return;
1247                 }
1248
1249                 handleCommand(pkt);
1250                 delete pkt;
1251
1252         }
1253         catch(SendFailedException &e) {
1254                 errorstream << "Server::ProcessData(): SendFailedException: "
1255                                 << "what=" << e.what()
1256                                 << std::endl;
1257         }
1258 }
1259
1260 void Server::setTimeOfDay(u32 time)
1261 {
1262         m_env->setTimeOfDay(time);
1263         m_time_of_day_send_timer = 0;
1264 }
1265
1266 void Server::onMapEditEvent(MapEditEvent *event)
1267 {
1268         if(m_ignore_map_edit_events)
1269                 return;
1270         if(m_ignore_map_edit_events_area.contains(event->getArea()))
1271                 return;
1272         MapEditEvent *e = event->clone();
1273         m_unsent_map_edit_queue.push(e);
1274 }
1275
1276 Inventory* Server::getInventory(const InventoryLocation &loc)
1277 {
1278         switch (loc.type) {
1279         case InventoryLocation::UNDEFINED:
1280         case InventoryLocation::CURRENT_PLAYER:
1281                 break;
1282         case InventoryLocation::PLAYER:
1283         {
1284                 Player *player = m_env->getPlayer(loc.name.c_str());
1285                 if(!player)
1286                         return NULL;
1287                 PlayerSAO *playersao = player->getPlayerSAO();
1288                 if(!playersao)
1289                         return NULL;
1290                 return playersao->getInventory();
1291         }
1292                 break;
1293         case InventoryLocation::NODEMETA:
1294         {
1295                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1296                 if(!meta)
1297                         return NULL;
1298                 return meta->getInventory();
1299         }
1300                 break;
1301         case InventoryLocation::DETACHED:
1302         {
1303                 if(m_detached_inventories.count(loc.name) == 0)
1304                         return NULL;
1305                 return m_detached_inventories[loc.name];
1306         }
1307                 break;
1308         default:
1309                 assert(0);
1310                 break;
1311         }
1312         return NULL;
1313 }
1314 void Server::setInventoryModified(const InventoryLocation &loc)
1315 {
1316         switch(loc.type){
1317         case InventoryLocation::UNDEFINED:
1318                 break;
1319         case InventoryLocation::PLAYER:
1320         {
1321                 Player *player = m_env->getPlayer(loc.name.c_str());
1322                 if(!player)
1323                         return;
1324                 PlayerSAO *playersao = player->getPlayerSAO();
1325                 if(!playersao)
1326                         return;
1327
1328                 SendInventory(playersao);
1329         }
1330                 break;
1331         case InventoryLocation::NODEMETA:
1332         {
1333                 v3s16 blockpos = getNodeBlockPos(loc.p);
1334
1335                 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1336                 if(block)
1337                         block->raiseModified(MOD_STATE_WRITE_NEEDED);
1338
1339                 setBlockNotSent(blockpos);
1340         }
1341                 break;
1342         case InventoryLocation::DETACHED:
1343         {
1344                 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1345         }
1346                 break;
1347         default:
1348                 assert(0);
1349                 break;
1350         }
1351 }
1352
1353 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1354 {
1355         std::vector<u16> clients = m_clients.getClientIDs();
1356         m_clients.Lock();
1357         // Set the modified blocks unsent for all the clients
1358         for (std::vector<u16>::iterator i = clients.begin();
1359                  i != clients.end(); ++i) {
1360                         if (RemoteClient *client = m_clients.lockedGetClientNoEx(*i))
1361                                 client->SetBlocksNotSent(block);
1362         }
1363         m_clients.Unlock();
1364 }
1365
1366 void Server::peerAdded(con::Peer *peer)
1367 {
1368         DSTACK(__FUNCTION_NAME);
1369         verbosestream<<"Server::peerAdded(): peer->id="
1370                         <<peer->id<<std::endl;
1371
1372         con::PeerChange c;
1373         c.type = con::PEER_ADDED;
1374         c.peer_id = peer->id;
1375         c.timeout = false;
1376         m_peer_change_queue.push(c);
1377 }
1378
1379 void Server::deletingPeer(con::Peer *peer, bool timeout)
1380 {
1381         DSTACK(__FUNCTION_NAME);
1382         verbosestream<<"Server::deletingPeer(): peer->id="
1383                         <<peer->id<<", timeout="<<timeout<<std::endl;
1384
1385         m_clients.event(peer->id, CSE_Disconnect);
1386         con::PeerChange c;
1387         c.type = con::PEER_REMOVED;
1388         c.peer_id = peer->id;
1389         c.timeout = timeout;
1390         m_peer_change_queue.push(c);
1391 }
1392
1393 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
1394 {
1395         *retval = m_con.getPeerStat(peer_id,type);
1396         if (*retval == -1) return false;
1397         return true;
1398 }
1399
1400 bool Server::getClientInfo(
1401                 u16          peer_id,
1402                 ClientState* state,
1403                 u32*         uptime,
1404                 u8*          ser_vers,
1405                 u16*         prot_vers,
1406                 u8*          major,
1407                 u8*          minor,
1408                 u8*          patch,
1409                 std::string* vers_string
1410         )
1411 {
1412         *state = m_clients.getClientState(peer_id);
1413         m_clients.Lock();
1414         RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1415
1416         if (client == NULL) {
1417                 m_clients.Unlock();
1418                 return false;
1419         }
1420
1421         *uptime = client->uptime();
1422         *ser_vers = client->serialization_version;
1423         *prot_vers = client->net_proto_version;
1424
1425         *major = client->getMajor();
1426         *minor = client->getMinor();
1427         *patch = client->getPatch();
1428         *vers_string = client->getPatch();
1429
1430         m_clients.Unlock();
1431
1432         return true;
1433 }
1434
1435 void Server::handlePeerChanges()
1436 {
1437         while(m_peer_change_queue.size() > 0)
1438         {
1439                 con::PeerChange c = m_peer_change_queue.front();
1440                 m_peer_change_queue.pop();
1441
1442                 verbosestream<<"Server: Handling peer change: "
1443                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1444                                 <<std::endl;
1445
1446                 switch(c.type)
1447                 {
1448                 case con::PEER_ADDED:
1449                         m_clients.CreateClient(c.peer_id);
1450                         break;
1451
1452                 case con::PEER_REMOVED:
1453                         DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1454                         break;
1455
1456                 default:
1457                         assert("Invalid peer change event received!" == 0);
1458                         break;
1459                 }
1460         }
1461 }
1462
1463 void Server::Send(NetworkPacket* pkt)
1464 {
1465         m_clients.send(pkt->getPeerId(),
1466                 clientCommandFactoryTable[pkt->getCommand()].channel,
1467                 pkt,
1468                 clientCommandFactoryTable[pkt->getCommand()].reliable);
1469 }
1470
1471 void Server::SendMovement(u16 peer_id)
1472 {
1473         DSTACK(__FUNCTION_NAME);
1474         std::ostringstream os(std::ios_base::binary);
1475
1476         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1477
1478         *pkt << g_settings->getFloat("movement_acceleration_default");
1479         *pkt << g_settings->getFloat("movement_acceleration_air");
1480         *pkt << g_settings->getFloat("movement_acceleration_fast");
1481         *pkt << g_settings->getFloat("movement_speed_walk");
1482         *pkt << g_settings->getFloat("movement_speed_crouch");
1483         *pkt << g_settings->getFloat("movement_speed_fast");
1484         *pkt << g_settings->getFloat("movement_speed_climb");
1485         *pkt << g_settings->getFloat("movement_speed_jump");
1486         *pkt << g_settings->getFloat("movement_liquid_fluidity");
1487         *pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1488         *pkt << g_settings->getFloat("movement_liquid_sink");
1489         *pkt << g_settings->getFloat("movement_gravity");
1490
1491         Send(pkt);
1492 }
1493
1494 void Server::SendHP(u16 peer_id, u8 hp)
1495 {
1496         DSTACK(__FUNCTION_NAME);
1497
1498         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HP, 1, peer_id);
1499         *pkt << hp;
1500         Send(pkt);
1501 }
1502
1503 void Server::SendBreath(u16 peer_id, u16 breath)
1504 {
1505         DSTACK(__FUNCTION_NAME);
1506
1507         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BREATH, 2, peer_id);
1508         *pkt << (u16) breath;
1509         Send(pkt);
1510 }
1511
1512 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
1513 {
1514         DSTACK(__FUNCTION_NAME);
1515
1516         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ACCESS_DENIED, 0, peer_id);
1517         *pkt << reason;
1518         Send(pkt);
1519 }
1520
1521 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
1522                 v3f camera_point_target)
1523 {
1524         DSTACK(__FUNCTION_NAME);
1525
1526         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1527         *pkt << set_camera_point_target << camera_point_target;
1528         Send(pkt);
1529 }
1530
1531 void Server::SendItemDef(u16 peer_id,
1532                 IItemDefManager *itemdef, u16 protocol_version)
1533 {
1534         DSTACK(__FUNCTION_NAME);
1535
1536         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ITEMDEF, 0, peer_id);
1537
1538         /*
1539                 u16 command
1540                 u32 length of the next item
1541                 zlib-compressed serialized ItemDefManager
1542         */
1543         std::ostringstream tmp_os(std::ios::binary);
1544         itemdef->serialize(tmp_os, protocol_version);
1545         std::ostringstream tmp_os2(std::ios::binary);
1546         compressZlib(tmp_os.str(), tmp_os2);
1547         pkt->putLongString(tmp_os2.str());
1548
1549         // Make data buffer
1550         verbosestream << "Server: Sending item definitions to id(" << peer_id
1551                         << "): size=" << pkt->getSize() << std::endl;
1552
1553         Send(pkt);
1554 }
1555
1556 void Server::SendNodeDef(u16 peer_id,
1557                 INodeDefManager *nodedef, u16 protocol_version)
1558 {
1559         DSTACK(__FUNCTION_NAME);
1560
1561         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_NODEDEF, 0, peer_id);
1562
1563         /*
1564                 u16 command
1565                 u32 length of the next item
1566                 zlib-compressed serialized NodeDefManager
1567         */
1568         std::ostringstream tmp_os(std::ios::binary);
1569         nodedef->serialize(tmp_os, protocol_version);
1570         std::ostringstream tmp_os2(std::ios::binary);
1571         compressZlib(tmp_os.str(), tmp_os2);
1572
1573         pkt->putLongString(tmp_os2.str());
1574
1575         // Make data buffer
1576         verbosestream << "Server: Sending node definitions to id(" << peer_id
1577                         << "): size=" << pkt->getSize() << std::endl;
1578
1579         Send(pkt);
1580 }
1581
1582 /*
1583         Non-static send methods
1584 */
1585
1586 void Server::SendInventory(PlayerSAO* playerSAO)
1587 {
1588         DSTACK(__FUNCTION_NAME);
1589
1590         UpdateCrafting(playerSAO->getPlayer());
1591
1592         /*
1593                 Serialize it
1594         */
1595
1596         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY, 0,
1597                         playerSAO->getPeerID());
1598
1599         std::ostringstream os;
1600         playerSAO->getInventory()->serialize(os);
1601
1602         std::string s = os.str();
1603
1604         pkt->putRawString(s.c_str(), s.size());
1605         Send(pkt);
1606 }
1607
1608 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
1609 {
1610         DSTACK(__FUNCTION_NAME);
1611
1612         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1613         *pkt << message;
1614
1615         if (peer_id != PEER_ID_INEXISTENT) {
1616                 Send(pkt);
1617         }
1618         else {
1619                 m_clients.sendToAll(0,pkt,true);
1620         }
1621 }
1622
1623 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
1624                                      const std::string &formname)
1625 {
1626         DSTACK(__FUNCTION_NAME);
1627
1628         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1629
1630         pkt->putLongString(FORMSPEC_VERSION_STRING + formspec);
1631         *pkt << formname;
1632
1633         Send(pkt);
1634 }
1635
1636 // Spawns a particle on peer with peer_id
1637 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
1638                                 float expirationtime, float size, bool collisiondetection,
1639                                 bool vertical, std::string texture)
1640 {
1641         DSTACK(__FUNCTION_NAME);
1642
1643         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1644
1645         *pkt << pos << velocity << acceleration << expirationtime
1646                         << size << collisiondetection;
1647         pkt->putLongString(texture);
1648         *pkt << vertical;
1649
1650         if (peer_id != PEER_ID_INEXISTENT) {
1651                 Send(pkt);
1652         }
1653         else {
1654                 m_clients.sendToAll(0,pkt,true);
1655         }
1656 }
1657
1658 // Adds a ParticleSpawner on peer with peer_id
1659 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
1660         v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1661         float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
1662 {
1663         DSTACK(__FUNCTION_NAME);
1664
1665         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1666
1667         *pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1668                         << minacc << maxacc << minexptime << maxexptime << minsize
1669                         << maxsize << collisiondetection;
1670
1671         pkt->putLongString(texture);
1672
1673         *pkt << id << vertical;
1674
1675         if (peer_id != PEER_ID_INEXISTENT) {
1676                 Send(pkt);
1677         }
1678         else {
1679                 m_clients.sendToAll(0, pkt, true);
1680         }
1681 }
1682
1683 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
1684 {
1685         DSTACK(__FUNCTION_NAME);
1686
1687         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DELETE_PARTICLESPAWNER, 2, peer_id);
1688
1689         // Ugly error in this packet
1690         *pkt << (u16) id;
1691
1692         if (peer_id != PEER_ID_INEXISTENT) {
1693                 Send(pkt);
1694         }
1695         else {
1696                 m_clients.sendToAll(0, pkt, true);
1697         }
1698
1699 }
1700
1701 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
1702 {
1703         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDADD, 0 , peer_id);
1704
1705         *pkt << id << (u8) form->type << form->pos << form->name << form->scale
1706                         << form->text << form->number << form->item << form->dir
1707                         << form->align << form->offset << form->world_pos << form->size;
1708
1709         Send(pkt);
1710 }
1711
1712 void Server::SendHUDRemove(u16 peer_id, u32 id)
1713 {
1714         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDRM, 4, peer_id);
1715         *pkt << id;
1716         Send(pkt);
1717 }
1718
1719 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
1720 {
1721         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUDCHANGE, 0, peer_id);
1722         *pkt << id << (u8) stat;
1723
1724         switch (stat) {
1725                 case HUD_STAT_POS:
1726                 case HUD_STAT_SCALE:
1727                 case HUD_STAT_ALIGN:
1728                 case HUD_STAT_OFFSET:
1729                         *pkt << *(v2f *) value;
1730                         break;
1731                 case HUD_STAT_NAME:
1732                 case HUD_STAT_TEXT:
1733                         *pkt << *(std::string *) value;
1734                         break;
1735                 case HUD_STAT_WORLD_POS:
1736                         *pkt << *(v3f *) value;
1737                         break;
1738                 case HUD_STAT_SIZE:
1739                         *pkt << *(v2s32 *) value;
1740                         break;
1741                 case HUD_STAT_NUMBER:
1742                 case HUD_STAT_ITEM:
1743                 case HUD_STAT_DIR:
1744                 default:
1745                         *pkt << *(u32 *) value;
1746                         break;
1747         }
1748
1749         Send(pkt);
1750 }
1751
1752 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
1753 {
1754         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1755
1756         flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1757
1758         *pkt << flags << mask;
1759
1760         Send(pkt);
1761 }
1762
1763 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
1764 {
1765         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1766         *pkt << param << value;
1767         Send(pkt);
1768 }
1769
1770 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
1771                 const std::string &type, const std::vector<std::string> &params)
1772 {
1773         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_SET_SKY, 0, peer_id);
1774         *pkt << bgcolor << type << (u16) params.size();
1775
1776         for(size_t i=0; i<params.size(); i++)
1777                 *pkt << params[i];
1778
1779         Send(pkt);
1780 }
1781
1782 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
1783                 float ratio)
1784 {
1785         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1786                         1 + 2, peer_id);
1787
1788         *pkt << do_override << (u16) (ratio * 65535);
1789
1790         Send (pkt);
1791 }
1792
1793 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
1794 {
1795         DSTACK(__FUNCTION_NAME);
1796
1797         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1798         *pkt << time << time_speed;
1799
1800         if (peer_id == PEER_ID_INEXISTENT) {
1801                 m_clients.sendToAll(0, pkt, true);
1802         }
1803         else {
1804                 Send(pkt);
1805         }
1806 }
1807
1808 void Server::SendPlayerHP(u16 peer_id)
1809 {
1810         DSTACK(__FUNCTION_NAME);
1811         PlayerSAO *playersao = getPlayerSAO(peer_id);
1812         assert(playersao);
1813         SendHP(peer_id, playersao->getHP());
1814         m_script->player_event(playersao,"health_changed");
1815
1816         // Send to other clients
1817         std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1818         ActiveObjectMessage aom(playersao->getId(), true, str);
1819         playersao->m_messages_out.push(aom);
1820 }
1821
1822 void Server::SendPlayerBreath(u16 peer_id)
1823 {
1824         DSTACK(__FUNCTION_NAME);
1825         PlayerSAO *playersao = getPlayerSAO(peer_id);
1826         assert(playersao);
1827
1828         m_script->player_event(playersao, "breath_changed");
1829         SendBreath(peer_id, playersao->getBreath());
1830 }
1831
1832 void Server::SendMovePlayer(u16 peer_id)
1833 {
1834         DSTACK(__FUNCTION_NAME);
1835         Player *player = m_env->getPlayer(peer_id);
1836         assert(player);
1837
1838         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MOVE_PLAYER, 0, peer_id);
1839         *pkt << player->getPosition() << player->getPitch() << player->getYaw();
1840
1841         {
1842                 v3f pos = player->getPosition();
1843                 f32 pitch = player->getPitch();
1844                 f32 yaw = player->getYaw();
1845                 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
1846                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1847                                 <<" pitch="<<pitch
1848                                 <<" yaw="<<yaw
1849                                 <<std::endl;
1850         }
1851
1852         Send(pkt);
1853 }
1854
1855 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
1856 {
1857         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1858                 peer_id);
1859
1860         *pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1861                         << animation_frames[3] << animation_speed;
1862
1863         Send(pkt);
1864 }
1865
1866 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
1867 {
1868         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_EYE_OFFSET, 0, peer_id);
1869         *pkt << first << third;
1870         Send(pkt);
1871 }
1872 void Server::SendPlayerPrivileges(u16 peer_id)
1873 {
1874         Player *player = m_env->getPlayer(peer_id);
1875         assert(player);
1876         if(player->peer_id == PEER_ID_INEXISTENT)
1877                 return;
1878
1879         std::set<std::string> privs;
1880         m_script->getAuth(player->getName(), NULL, &privs);
1881
1882         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PRIVILEGES, 0, peer_id);
1883         *pkt << (u16) privs.size();
1884
1885         for(std::set<std::string>::const_iterator i = privs.begin();
1886                         i != privs.end(); i++) {
1887                 *pkt << (*i);
1888         }
1889
1890         Send(pkt);
1891 }
1892
1893 void Server::SendPlayerInventoryFormspec(u16 peer_id)
1894 {
1895         Player *player = m_env->getPlayer(peer_id);
1896         assert(player);
1897         if(player->peer_id == PEER_ID_INEXISTENT)
1898                 return;
1899
1900         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1901         pkt->putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1902         Send(pkt);
1903 }
1904
1905 s32 Server::playSound(const SimpleSoundSpec &spec,
1906                 const ServerSoundParams &params)
1907 {
1908         // Find out initial position of sound
1909         bool pos_exists = false;
1910         v3f pos = params.getPos(m_env, &pos_exists);
1911         // If position is not found while it should be, cancel sound
1912         if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1913                 return -1;
1914
1915         // Filter destination clients
1916         std::list<u16> dst_clients;
1917         if(params.to_player != "")
1918         {
1919                 Player *player = m_env->getPlayer(params.to_player.c_str());
1920                 if(!player){
1921                         infostream<<"Server::playSound: Player \""<<params.to_player
1922                                         <<"\" not found"<<std::endl;
1923                         return -1;
1924                 }
1925                 if(player->peer_id == PEER_ID_INEXISTENT){
1926                         infostream<<"Server::playSound: Player \""<<params.to_player
1927                                         <<"\" not connected"<<std::endl;
1928                         return -1;
1929                 }
1930                 dst_clients.push_back(player->peer_id);
1931         }
1932         else
1933         {
1934                 std::vector<u16> clients = m_clients.getClientIDs();
1935
1936                 for(std::vector<u16>::iterator
1937                                 i = clients.begin(); i != clients.end(); ++i) {
1938                         Player *player = m_env->getPlayer(*i);
1939                         if(!player)
1940                                 continue;
1941
1942                         if(pos_exists) {
1943                                 if(player->getPosition().getDistanceFrom(pos) >
1944                                                 params.max_hear_distance)
1945                                         continue;
1946                         }
1947                         dst_clients.push_back(*i);
1948                 }
1949         }
1950
1951         if(dst_clients.empty())
1952                 return -1;
1953
1954         // Create the sound
1955         s32 id = m_next_sound_id++;
1956         // The sound will exist as a reference in m_playing_sounds
1957         m_playing_sounds[id] = ServerPlayingSound();
1958         ServerPlayingSound &psound = m_playing_sounds[id];
1959         psound.params = params;
1960         for(std::list<u16>::iterator i = dst_clients.begin();
1961                         i != dst_clients.end(); i++)
1962                 psound.clients.insert(*i);
1963
1964         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_PLAY_SOUND, 0);
1965         *pkt << id << spec.name << (float) (spec.gain * params.gain)
1966                         << (u8) params.type << pos << params.object << params.loop;
1967         for(std::list<u16>::iterator i = dst_clients.begin();
1968                         i != dst_clients.end(); i++) {
1969                 // Send as reliable
1970                 m_clients.send(*i, 0, pkt, true, false);
1971         }
1972         delete pkt;
1973         return id;
1974 }
1975 void Server::stopSound(s32 handle)
1976 {
1977         // Get sound reference
1978         std::map<s32, ServerPlayingSound>::iterator i =
1979                         m_playing_sounds.find(handle);
1980         if(i == m_playing_sounds.end())
1981                 return;
1982         ServerPlayingSound &psound = i->second;
1983
1984         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_STOP_SOUND, 4);
1985         *pkt << handle;
1986
1987         for(std::set<u16>::iterator i = psound.clients.begin();
1988                         i != psound.clients.end(); i++) {
1989                 // Send as reliable
1990                 m_clients.send(*i, 0, pkt, true, false);
1991         }
1992         delete pkt;
1993         // Remove sound reference
1994         m_playing_sounds.erase(i);
1995 }
1996
1997 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
1998         std::vector<u16> *far_players, float far_d_nodes)
1999 {
2000         float maxd = far_d_nodes*BS;
2001         v3f p_f = intToFloat(p, BS);
2002
2003         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_REMOVENODE, 6);
2004         *pkt << p;
2005
2006         std::vector<u16> clients = m_clients.getClientIDs();
2007         for(std::vector<u16>::iterator i = clients.begin();
2008                 i != clients.end(); ++i) {
2009                 if (far_players) {
2010                         // Get player
2011                         if(Player *player = m_env->getPlayer(*i)) {
2012                                 // If player is far away, only set modified blocks not sent
2013                                 v3f player_pos = player->getPosition();
2014                                 if(player_pos.getDistanceFrom(p_f) > maxd) {
2015                                         far_players->push_back(*i);
2016                                         continue;
2017                                 }
2018                         }
2019                 }
2020
2021                 // Send as reliable
2022                 m_clients.send(*i, 0, pkt, true, false);
2023         }
2024         // This loop needs the deletion of the packet here
2025         delete pkt;
2026 }
2027
2028 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2029                 std::vector<u16> *far_players, float far_d_nodes,
2030                 bool remove_metadata)
2031 {
2032         float maxd = far_d_nodes*BS;
2033         v3f p_f = intToFloat(p, BS);
2034
2035         std::vector<u16> clients = m_clients.getClientIDs();
2036         for(std::vector<u16>::iterator i = clients.begin();
2037                         i != clients.end(); ++i) {
2038
2039                 if(far_players) {
2040                         // Get player
2041                         if(Player *player = m_env->getPlayer(*i)) {
2042                                 // If player is far away, only set modified blocks not sent
2043                                 v3f player_pos = player->getPosition();
2044                                 if(player_pos.getDistanceFrom(p_f) > maxd) {
2045                                         far_players->push_back(*i);
2046                                         continue;
2047                                 }
2048                         }
2049                 }
2050
2051                 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2052                 m_clients.Lock();
2053                 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
2054                 if (client != 0) {
2055                         *pkt << p << n.param0 << n.param1 << n.param2
2056                                         << (u8) (remove_metadata ? 0 : 1);
2057
2058                         if (!remove_metadata) {
2059                                 if (client->net_proto_version <= 21) {
2060                                         // Old clients always clear metadata; fix it
2061                                         // by sending the full block again.
2062                                         client->SetBlockNotSent(p);
2063                                 }
2064                         }
2065                 }
2066                 m_clients.Unlock();
2067
2068                 // Send as reliable
2069                 if (pkt->getSize() > 0)
2070                         m_clients.send(*i, 0, pkt, true);
2071         }
2072 }
2073
2074 void Server::setBlockNotSent(v3s16 p)
2075 {
2076         std::vector<u16> clients = m_clients.getClientIDs();
2077         m_clients.Lock();
2078         for(std::vector<u16>::iterator i = clients.begin();
2079                 i != clients.end(); ++i) {
2080                 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2081                 client->SetBlockNotSent(p);
2082         }
2083         m_clients.Unlock();
2084 }
2085
2086 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2087 {
2088         DSTACK(__FUNCTION_NAME);
2089
2090         v3s16 p = block->getPos();
2091
2092         /*
2093                 Create a packet with the block in the right format
2094         */
2095
2096         std::ostringstream os(std::ios_base::binary);
2097         block->serialize(os, ver, false);
2098         block->serializeNetworkSpecific(os, net_proto_version);
2099         std::string s = os.str();
2100
2101         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_BLOCKDATA,
2102                 2 + 2 + 2 + 2 + s.size(), peer_id);
2103
2104         *pkt << p;
2105         pkt->putRawString(s.c_str(), s.size());
2106         Send(pkt);
2107 }
2108
2109 void Server::SendBlocks(float dtime)
2110 {
2111         DSTACK(__FUNCTION_NAME);
2112
2113         JMutexAutoLock envlock(m_env_mutex);
2114         //TODO check if one big lock could be faster then multiple small ones
2115
2116         ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2117
2118         std::vector<PrioritySortedBlockTransfer> queue;
2119
2120         s32 total_sending = 0;
2121
2122         {
2123                 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
2124
2125                 std::vector<u16> clients = m_clients.getClientIDs();
2126
2127                 m_clients.Lock();
2128                 for(std::vector<u16>::iterator i = clients.begin();
2129                         i != clients.end(); ++i) {
2130                         RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
2131
2132                         if (client == NULL)
2133                                 continue;
2134
2135                         total_sending += client->SendingCount();
2136                         client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2137                 }
2138                 m_clients.Unlock();
2139         }
2140
2141         // Sort.
2142         // Lowest priority number comes first.
2143         // Lowest is most important.
2144         std::sort(queue.begin(), queue.end());
2145
2146         m_clients.Lock();
2147         for(u32 i=0; i<queue.size(); i++)
2148         {
2149                 //TODO: Calculate limit dynamically
2150                 if(total_sending >= g_settings->getS32
2151                                 ("max_simultaneous_block_sends_server_total"))
2152                         break;
2153
2154                 PrioritySortedBlockTransfer q = queue[i];
2155
2156                 MapBlock *block = NULL;
2157                 try
2158                 {
2159                         block = m_env->getMap().getBlockNoCreate(q.pos);
2160                 }
2161                 catch(InvalidPositionException &e)
2162                 {
2163                         continue;
2164                 }
2165
2166                 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
2167
2168                 if(!client)
2169                         continue;
2170
2171                 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
2172
2173                 client->SentBlock(q.pos);
2174                 total_sending++;
2175         }
2176         m_clients.Unlock();
2177 }
2178
2179 void Server::fillMediaCache()
2180 {
2181         DSTACK(__FUNCTION_NAME);
2182
2183         infostream<<"Server: Calculating media file checksums"<<std::endl;
2184
2185         // Collect all media file paths
2186         std::list<std::string> paths;
2187         for(std::vector<ModSpec>::iterator i = m_mods.begin();
2188                         i != m_mods.end(); i++){
2189                 const ModSpec &mod = *i;
2190                 paths.push_back(mod.path + DIR_DELIM + "textures");
2191                 paths.push_back(mod.path + DIR_DELIM + "sounds");
2192                 paths.push_back(mod.path + DIR_DELIM + "media");
2193                 paths.push_back(mod.path + DIR_DELIM + "models");
2194         }
2195         paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2196
2197         // Collect media file information from paths into cache
2198         for(std::list<std::string>::iterator i = paths.begin();
2199                         i != paths.end(); i++)
2200         {
2201                 std::string mediapath = *i;
2202                 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2203                 for(u32 j=0; j<dirlist.size(); j++){
2204                         if(dirlist[j].dir) // Ignode dirs
2205                                 continue;
2206                         std::string filename = dirlist[j].name;
2207                         // If name contains illegal characters, ignore the file
2208                         if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
2209                                 infostream<<"Server: ignoring illegal file name: \""
2210                                                 <<filename<<"\""<<std::endl;
2211                                 continue;
2212                         }
2213                         // If name is not in a supported format, ignore it
2214                         const char *supported_ext[] = {
2215                                 ".png", ".jpg", ".bmp", ".tga",
2216                                 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2217                                 ".ogg",
2218                                 ".x", ".b3d", ".md2", ".obj",
2219                                 NULL
2220                         };
2221                         if(removeStringEnd(filename, supported_ext) == ""){
2222                                 infostream<<"Server: ignoring unsupported file extension: \""
2223                                                 <<filename<<"\""<<std::endl;
2224                                 continue;
2225                         }
2226                         // Ok, attempt to load the file and add to cache
2227                         std::string filepath = mediapath + DIR_DELIM + filename;
2228                         // Read data
2229                         std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2230                         if(fis.good() == false){
2231                                 errorstream<<"Server::fillMediaCache(): Could not open \""
2232                                                 <<filename<<"\" for reading"<<std::endl;
2233                                 continue;
2234                         }
2235                         std::ostringstream tmp_os(std::ios_base::binary);
2236                         bool bad = false;
2237                         for(;;){
2238                                 char buf[1024];
2239                                 fis.read(buf, 1024);
2240                                 std::streamsize len = fis.gcount();
2241                                 tmp_os.write(buf, len);
2242                                 if(fis.eof())
2243                                         break;
2244                                 if(!fis.good()){
2245                                         bad = true;
2246                                         break;
2247                                 }
2248                         }
2249                         if(bad){
2250                                 errorstream<<"Server::fillMediaCache(): Failed to read \""
2251                                                 <<filename<<"\""<<std::endl;
2252                                 continue;
2253                         }
2254                         if(tmp_os.str().length() == 0){
2255                                 errorstream<<"Server::fillMediaCache(): Empty file \""
2256                                                 <<filepath<<"\""<<std::endl;
2257                                 continue;
2258                         }
2259
2260                         SHA1 sha1;
2261                         sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2262
2263                         unsigned char *digest = sha1.getDigest();
2264                         std::string sha1_base64 = base64_encode(digest, 20);
2265                         std::string sha1_hex = hex_encode((char*)digest, 20);
2266                         free(digest);
2267
2268                         // Put in list
2269                         this->m_media[filename] = MediaInfo(filepath, sha1_base64);
2270                         verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
2271                 }
2272         }
2273 }
2274
2275 struct SendableMediaAnnouncement
2276 {
2277         std::string name;
2278         std::string sha1_digest;
2279
2280         SendableMediaAnnouncement(const std::string &name_="",
2281                                   const std::string &sha1_digest_=""):
2282                 name(name_),
2283                 sha1_digest(sha1_digest_)
2284         {}
2285 };
2286
2287 void Server::sendMediaAnnouncement(u16 peer_id)
2288 {
2289         DSTACK(__FUNCTION_NAME);
2290
2291         verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
2292                         <<std::endl;
2293
2294         std::list<SendableMediaAnnouncement> file_announcements;
2295
2296         for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
2297                         i != m_media.end(); i++){
2298                 // Put in list
2299                 file_announcements.push_back(
2300                                 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
2301         }
2302
2303         // Make packet
2304         std::ostringstream os(std::ios_base::binary);
2305
2306         /*
2307                 u32 number of files
2308                 for each texture {
2309                         u16 length of name
2310                         string name
2311                         u16 length of sha1_digest
2312                         string sha1_digest
2313                 }
2314         */
2315
2316         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2317         *pkt << (u16) file_announcements.size();
2318
2319         for(std::list<SendableMediaAnnouncement>::iterator
2320                         j = file_announcements.begin();
2321                         j != file_announcements.end(); ++j) {
2322                 *pkt << j->name << j->sha1_digest;
2323         }
2324
2325         *pkt << g_settings->get("remote_media");
2326         Send(pkt);
2327 }
2328
2329 struct SendableMedia
2330 {
2331         std::string name;
2332         std::string path;
2333         std::string data;
2334
2335         SendableMedia(const std::string &name_="", const std::string &path_="",
2336                       const std::string &data_=""):
2337                 name(name_),
2338                 path(path_),
2339                 data(data_)
2340         {}
2341 };
2342
2343 void Server::sendRequestedMedia(u16 peer_id,
2344                 const std::list<std::string> &tosend)
2345 {
2346         DSTACK(__FUNCTION_NAME);
2347
2348         verbosestream<<"Server::sendRequestedMedia(): "
2349                         <<"Sending files to client"<<std::endl;
2350
2351         /* Read files */
2352
2353         // Put 5kB in one bunch (this is not accurate)
2354         u32 bytes_per_bunch = 5000;
2355
2356         std::vector< std::list<SendableMedia> > file_bunches;
2357         file_bunches.push_back(std::list<SendableMedia>());
2358
2359         u32 file_size_bunch_total = 0;
2360
2361         for(std::list<std::string>::const_iterator i = tosend.begin();
2362                         i != tosend.end(); ++i)
2363         {
2364                 const std::string &name = *i;
2365
2366                 if(m_media.find(name) == m_media.end()) {
2367                         errorstream<<"Server::sendRequestedMedia(): Client asked for "
2368                                         <<"unknown file \""<<(name)<<"\""<<std::endl;
2369                         continue;
2370                 }
2371
2372                 //TODO get path + name
2373                 std::string tpath = m_media[name].path;
2374
2375                 // Read data
2376                 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2377                 if(fis.good() == false){
2378                         errorstream<<"Server::sendRequestedMedia(): Could not open \""
2379                                         <<tpath<<"\" for reading"<<std::endl;
2380                         continue;
2381                 }
2382                 std::ostringstream tmp_os(std::ios_base::binary);
2383                 bool bad = false;
2384                 for(;;) {
2385                         char buf[1024];
2386                         fis.read(buf, 1024);
2387                         std::streamsize len = fis.gcount();
2388                         tmp_os.write(buf, len);
2389                         file_size_bunch_total += len;
2390                         if(fis.eof())
2391                                 break;
2392                         if(!fis.good()) {
2393                                 bad = true;
2394                                 break;
2395                         }
2396                 }
2397                 if(bad) {
2398                         errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2399                                         <<name<<"\""<<std::endl;
2400                         continue;
2401                 }
2402                 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2403                                 <<tname<<"\""<<std::endl;*/
2404                 // Put in list
2405                 file_bunches[file_bunches.size()-1].push_back(
2406                                 SendableMedia(name, tpath, tmp_os.str()));
2407
2408                 // Start next bunch if got enough data
2409                 if(file_size_bunch_total >= bytes_per_bunch) {
2410                         file_bunches.push_back(std::list<SendableMedia>());
2411                         file_size_bunch_total = 0;
2412                 }
2413
2414         }
2415
2416         /* Create and send packets */
2417
2418         u16 num_bunches = file_bunches.size();
2419         for(u16 i = 0; i < num_bunches; i++) {
2420                 /*
2421                         u16 command
2422                         u16 total number of texture bunches
2423                         u16 index of this bunch
2424                         u32 number of files in this bunch
2425                         for each file {
2426                                 u16 length of name
2427                                 string name
2428                                 u32 length of data
2429                                 data
2430                         }
2431                 */
2432
2433                 NetworkPacket* pkt = new NetworkPacket(TOCLIENT_MEDIA, 0, peer_id);
2434                 *pkt << num_bunches << i << (u32) file_bunches[i].size();
2435
2436                 for(std::list<SendableMedia>::iterator
2437                                 j = file_bunches[i].begin();
2438                                 j != file_bunches[i].end(); ++j) {
2439                         *pkt << j->name;
2440                         pkt->putLongString(j->data);
2441                 }
2442
2443                 verbosestream << "Server::sendRequestedMedia(): bunch "
2444                                 << i << "/" << num_bunches
2445                                 << " files=" << file_bunches[i].size()
2446                                 << " size="  << pkt->getSize() << std::endl;
2447                 Send(pkt);
2448         }
2449 }
2450
2451 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
2452 {
2453         if(m_detached_inventories.count(name) == 0) {
2454                 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2455                 return;
2456         }
2457         Inventory *inv = m_detached_inventories[name];
2458         std::ostringstream os(std::ios_base::binary);
2459
2460         os << serializeString(name);
2461         inv->serialize(os);
2462
2463         // Make data buffer
2464         std::string s = os.str();
2465
2466         NetworkPacket* pkt = new NetworkPacket(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2467         pkt->putRawString(s.c_str(), s.size());
2468
2469         if (peer_id != PEER_ID_INEXISTENT) {
2470                 Send(pkt);
2471         }
2472         else {
2473                 m_clients.sendToAll(0, pkt, true);
2474         }
2475 }
2476
2477 void Server::sendDetachedInventories(u16 peer_id)
2478 {
2479         DSTACK(__FUNCTION_NAME);
2480
2481         for(std::map<std::string, Inventory*>::iterator
2482                         i = m_detached_inventories.begin();
2483                         i != m_detached_inventories.end(); i++) {
2484                 const std::string &name = i->first;
2485                 //Inventory *inv = i->second;
2486                 sendDetachedInventory(name, peer_id);
2487         }
2488 }
2489
2490 /*
2491         Something random
2492 */
2493
2494 void Server::DiePlayer(u16 peer_id)
2495 {
2496         DSTACK(__FUNCTION_NAME);
2497
2498         PlayerSAO *playersao = getPlayerSAO(peer_id);
2499         assert(playersao);
2500
2501         infostream << "Server::DiePlayer(): Player "
2502                         << playersao->getPlayer()->getName()
2503                         << " dies" << std::endl;
2504
2505         playersao->setHP(0);
2506
2507         // Trigger scripted stuff
2508         m_script->on_dieplayer(playersao);
2509
2510         SendPlayerHP(peer_id);
2511         SendDeathscreen(peer_id, false, v3f(0,0,0));
2512 }
2513
2514 void Server::RespawnPlayer(u16 peer_id)
2515 {
2516         DSTACK(__FUNCTION_NAME);
2517
2518         PlayerSAO *playersao = getPlayerSAO(peer_id);
2519         assert(playersao);
2520
2521         infostream << "Server::RespawnPlayer(): Player "
2522                         << playersao->getPlayer()->getName()
2523                         << " respawns" << std::endl;
2524
2525         playersao->setHP(PLAYER_MAX_HP);
2526         playersao->setBreath(PLAYER_MAX_BREATH);
2527
2528         SendPlayerHP(peer_id);
2529         SendPlayerBreath(peer_id);
2530
2531         bool repositioned = m_script->on_respawnplayer(playersao);
2532         if(!repositioned){
2533                 v3f pos = findSpawnPos(m_env->getServerMap());
2534                 // setPos will send the new position to client
2535                 playersao->setPos(pos);
2536         }
2537 }
2538
2539 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
2540 {
2541         DSTACK(__FUNCTION_NAME);
2542
2543         SendAccessDenied(peer_id, reason);
2544         m_clients.event(peer_id, CSE_SetDenied);
2545         m_con.DisconnectPeer(peer_id);
2546 }
2547
2548 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
2549 {
2550         DSTACK(__FUNCTION_NAME);
2551         std::wstring message;
2552         {
2553                 /*
2554                         Clear references to playing sounds
2555                 */
2556                 for(std::map<s32, ServerPlayingSound>::iterator
2557                                 i = m_playing_sounds.begin();
2558                                 i != m_playing_sounds.end();)
2559                 {
2560                         ServerPlayingSound &psound = i->second;
2561                         psound.clients.erase(peer_id);
2562                         if(psound.clients.empty())
2563                                 m_playing_sounds.erase(i++);
2564                         else
2565                                 i++;
2566                 }
2567
2568                 Player *player = m_env->getPlayer(peer_id);
2569
2570                 // Collect information about leaving in chat
2571                 {
2572                         if(player != NULL && reason != CDR_DENY)
2573                         {
2574                                 std::wstring name = narrow_to_wide(player->getName());
2575                                 message += L"*** ";
2576                                 message += name;
2577                                 message += L" left the game.";
2578                                 if(reason == CDR_TIMEOUT)
2579                                         message += L" (timed out)";
2580                         }
2581                 }
2582
2583                 /* Run scripts and remove from environment */
2584                 {
2585                         if(player != NULL)
2586                         {
2587                                 PlayerSAO *playersao = player->getPlayerSAO();
2588                                 assert(playersao);
2589
2590                                 m_script->on_leaveplayer(playersao);
2591
2592                                 playersao->disconnected();
2593                         }
2594                 }
2595
2596                 /*
2597                         Print out action
2598                 */
2599                 {
2600                         if(player != NULL && reason != CDR_DENY) {
2601                                 std::ostringstream os(std::ios_base::binary);
2602                                 std::vector<u16> clients = m_clients.getClientIDs();
2603
2604                                 for(std::vector<u16>::iterator i = clients.begin();
2605                                         i != clients.end(); ++i) {
2606                                         // Get player
2607                                         Player *player = m_env->getPlayer(*i);
2608                                         if(!player)
2609                                                 continue;
2610
2611                                         // Get name of player
2612                                         os << player->getName() << " ";
2613                                 }
2614
2615                                 actionstream << player->getName() << " "
2616                                                 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2617                                                 << " List of players: " << os.str() << std::endl;
2618                         }
2619                 }
2620                 {
2621                         JMutexAutoLock env_lock(m_env_mutex);
2622                         m_clients.DeleteClient(peer_id);
2623                 }
2624         }
2625
2626         // Send leave chat message to all remaining clients
2627         if(message.length() != 0)
2628                 SendChatMessage(PEER_ID_INEXISTENT,message);
2629 }
2630
2631 void Server::UpdateCrafting(Player* player)
2632 {
2633         DSTACK(__FUNCTION_NAME);
2634
2635         // Get a preview for crafting
2636         ItemStack preview;
2637         InventoryLocation loc;
2638         loc.setPlayer(player->getName());
2639         getCraftingResult(&player->inventory, preview, false, this);
2640         m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
2641
2642         // Put the new preview in
2643         InventoryList *plist = player->inventory.getList("craftpreview");
2644         assert(plist);
2645         assert(plist->getSize() >= 1);
2646         plist->changeItem(0, preview);
2647 }
2648
2649 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
2650 {
2651         RemoteClient *client = getClientNoEx(peer_id,state_min);
2652         if(!client)
2653                 throw ClientNotFoundException("Client not found");
2654
2655         return client;
2656 }
2657 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
2658 {
2659         return m_clients.getClientNoEx(peer_id, state_min);
2660 }
2661
2662 std::string Server::getPlayerName(u16 peer_id)
2663 {
2664         Player *player = m_env->getPlayer(peer_id);
2665         if(player == NULL)
2666                 return "[id="+itos(peer_id)+"]";
2667         return player->getName();
2668 }
2669
2670 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
2671 {
2672         Player *player = m_env->getPlayer(peer_id);
2673         if(player == NULL)
2674                 return NULL;
2675         return player->getPlayerSAO();
2676 }
2677
2678 std::wstring Server::getStatusString()
2679 {
2680         std::wostringstream os(std::ios_base::binary);
2681         os<<L"# Server: ";
2682         // Version
2683         os<<L"version="<<narrow_to_wide(minetest_version_simple);
2684         // Uptime
2685         os<<L", uptime="<<m_uptime.get();
2686         // Max lag estimate
2687         os<<L", max_lag="<<m_env->getMaxLagEstimate();
2688         // Information about clients
2689         bool first = true;
2690         os<<L", clients={";
2691         std::vector<u16> clients = m_clients.getClientIDs();
2692         for(std::vector<u16>::iterator i = clients.begin();
2693                 i != clients.end(); ++i) {
2694                 // Get player
2695                 Player *player = m_env->getPlayer(*i);
2696                 // Get name of player
2697                 std::wstring name = L"unknown";
2698                 if(player != NULL)
2699                         name = narrow_to_wide(player->getName());
2700                 // Add name to information string
2701                 if(!first)
2702                         os << L", ";
2703                 else
2704                         first = false;
2705                 os << name;
2706         }
2707         os << L"}";
2708         if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
2709                 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2710         if(g_settings->get("motd") != "")
2711                 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2712         return os.str();
2713 }
2714
2715 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2716 {
2717         std::set<std::string> privs;
2718         m_script->getAuth(name, NULL, &privs);
2719         return privs;
2720 }
2721
2722 bool Server::checkPriv(const std::string &name, const std::string &priv)
2723 {
2724         std::set<std::string> privs = getPlayerEffectivePrivs(name);
2725         return (privs.count(priv) != 0);
2726 }
2727
2728 void Server::reportPrivsModified(const std::string &name)
2729 {
2730         if(name == "") {
2731                 std::vector<u16> clients = m_clients.getClientIDs();
2732                 for(std::vector<u16>::iterator i = clients.begin();
2733                                 i != clients.end(); ++i) {
2734                         Player *player = m_env->getPlayer(*i);
2735                         reportPrivsModified(player->getName());
2736                 }
2737         } else {
2738                 Player *player = m_env->getPlayer(name.c_str());
2739                 if(!player)
2740                         return;
2741                 SendPlayerPrivileges(player->peer_id);
2742                 PlayerSAO *sao = player->getPlayerSAO();
2743                 if(!sao)
2744                         return;
2745                 sao->updatePrivileges(
2746                                 getPlayerEffectivePrivs(name),
2747                                 isSingleplayer());
2748         }
2749 }
2750
2751 void Server::reportInventoryFormspecModified(const std::string &name)
2752 {
2753         Player *player = m_env->getPlayer(name.c_str());
2754         if(!player)
2755                 return;
2756         SendPlayerInventoryFormspec(player->peer_id);
2757 }
2758
2759 void Server::setIpBanned(const std::string &ip, const std::string &name)
2760 {
2761         m_banmanager->add(ip, name);
2762 }
2763
2764 void Server::unsetIpBanned(const std::string &ip_or_name)
2765 {
2766         m_banmanager->remove(ip_or_name);
2767 }
2768
2769 std::string Server::getBanDescription(const std::string &ip_or_name)
2770 {
2771         return m_banmanager->getBanDescription(ip_or_name);
2772 }
2773
2774 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2775 {
2776         Player *player = m_env->getPlayer(name);
2777         if(!player)
2778                 return;
2779
2780         if (player->peer_id == PEER_ID_INEXISTENT)
2781                 return;
2782
2783         SendChatMessage(player->peer_id, msg);
2784 }
2785
2786 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
2787 {
2788         Player *player = m_env->getPlayer(playername);
2789
2790         if(!player)
2791         {
2792                 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
2793                 return false;
2794         }
2795
2796         SendShowFormspecMessage(player->peer_id, formspec, formname);
2797         return true;
2798 }
2799
2800 u32 Server::hudAdd(Player *player, HudElement *form) {
2801         if (!player)
2802                 return -1;
2803
2804         u32 id = player->addHud(form);
2805
2806         SendHUDAdd(player->peer_id, id, form);
2807
2808         return id;
2809 }
2810
2811 bool Server::hudRemove(Player *player, u32 id) {
2812         if (!player)
2813                 return false;
2814
2815         HudElement* todel = player->removeHud(id);
2816
2817         if (!todel)
2818                 return false;
2819
2820         delete todel;
2821
2822         SendHUDRemove(player->peer_id, id);
2823         return true;
2824 }
2825
2826 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
2827         if (!player)
2828                 return false;
2829
2830         SendHUDChange(player->peer_id, id, stat, data);
2831         return true;
2832 }
2833
2834 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
2835         if (!player)
2836                 return false;
2837
2838         SendHUDSetFlags(player->peer_id, flags, mask);
2839         player->hud_flags = flags;
2840
2841         PlayerSAO* playersao = player->getPlayerSAO();
2842
2843         if (playersao == NULL)
2844                 return false;
2845
2846         m_script->player_event(playersao, "hud_changed");
2847         return true;
2848 }
2849
2850 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
2851         if (!player)
2852                 return false;
2853         if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
2854                 return false;
2855
2856         std::ostringstream os(std::ios::binary);
2857         writeS32(os, hotbar_itemcount);
2858         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
2859         return true;
2860 }
2861
2862 void Server::hudSetHotbarImage(Player *player, std::string name) {
2863         if (!player)
2864                 return;
2865
2866         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
2867 }
2868
2869 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
2870         if (!player)
2871                 return;
2872
2873         SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
2874 }
2875
2876 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
2877 {
2878         if (!player)
2879                 return false;
2880
2881         SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
2882         return true;
2883 }
2884
2885 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
2886 {
2887         if (!player)
2888                 return false;
2889
2890         SendEyeOffset(player->peer_id, first, third);
2891         return true;
2892 }
2893
2894 bool Server::setSky(Player *player, const video::SColor &bgcolor,
2895                 const std::string &type, const std::vector<std::string> &params)
2896 {
2897         if (!player)
2898                 return false;
2899
2900         SendSetSky(player->peer_id, bgcolor, type, params);
2901         return true;
2902 }
2903
2904 bool Server::overrideDayNightRatio(Player *player, bool do_override,
2905                 float ratio)
2906 {
2907         if (!player)
2908                 return false;
2909
2910         SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
2911         return true;
2912 }
2913
2914 void Server::notifyPlayers(const std::wstring &msg)
2915 {
2916         SendChatMessage(PEER_ID_INEXISTENT,msg);
2917 }
2918
2919 void Server::spawnParticle(const char *playername, v3f pos,
2920                 v3f velocity, v3f acceleration,
2921                 float expirationtime, float size, bool
2922                 collisiondetection, bool vertical, std::string texture)
2923 {
2924         Player *player = m_env->getPlayer(playername);
2925         if(!player)
2926                 return;
2927         SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
2928                         expirationtime, size, collisiondetection, vertical, texture);
2929 }
2930
2931 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
2932                 float expirationtime, float size,
2933                 bool collisiondetection, bool vertical, std::string texture)
2934 {
2935         SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
2936                         expirationtime, size, collisiondetection, vertical, texture);
2937 }
2938
2939 u32 Server::addParticleSpawner(const char *playername,
2940                 u16 amount, float spawntime,
2941                 v3f minpos, v3f maxpos,
2942                 v3f minvel, v3f maxvel,
2943                 v3f minacc, v3f maxacc,
2944                 float minexptime, float maxexptime,
2945                 float minsize, float maxsize,
2946                 bool collisiondetection, bool vertical, std::string texture)
2947 {
2948         Player *player = m_env->getPlayer(playername);
2949         if(!player)
2950                 return -1;
2951
2952         u32 id = 0;
2953         for(;;) // look for unused particlespawner id
2954         {
2955                 id++;
2956                 if (std::find(m_particlespawner_ids.begin(),
2957                                 m_particlespawner_ids.end(), id)
2958                                 == m_particlespawner_ids.end())
2959                 {
2960                         m_particlespawner_ids.push_back(id);
2961                         break;
2962                 }
2963         }
2964
2965         SendAddParticleSpawner(player->peer_id, amount, spawntime,
2966                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2967                 minexptime, maxexptime, minsize, maxsize,
2968                 collisiondetection, vertical, texture, id);
2969
2970         return id;
2971 }
2972
2973 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
2974                 v3f minpos, v3f maxpos,
2975                 v3f minvel, v3f maxvel,
2976                 v3f minacc, v3f maxacc,
2977                 float minexptime, float maxexptime,
2978                 float minsize, float maxsize,
2979                 bool collisiondetection, bool vertical, std::string texture)
2980 {
2981         u32 id = 0;
2982         for(;;) // look for unused particlespawner id
2983         {
2984                 id++;
2985                 if (std::find(m_particlespawner_ids.begin(),
2986                                 m_particlespawner_ids.end(), id)
2987                                 == m_particlespawner_ids.end())
2988                 {
2989                         m_particlespawner_ids.push_back(id);
2990                         break;
2991                 }
2992         }
2993
2994         SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
2995                 minpos, maxpos, minvel, maxvel, minacc, maxacc,
2996                 minexptime, maxexptime, minsize, maxsize,
2997                 collisiondetection, vertical, texture, id);
2998
2999         return id;
3000 }
3001
3002 void Server::deleteParticleSpawner(const char *playername, u32 id)
3003 {
3004         Player *player = m_env->getPlayer(playername);
3005         if(!player)
3006                 return;
3007
3008         m_particlespawner_ids.erase(
3009                         std::remove(m_particlespawner_ids.begin(),
3010                         m_particlespawner_ids.end(), id),
3011                         m_particlespawner_ids.end());
3012         SendDeleteParticleSpawner(player->peer_id, id);
3013 }
3014
3015 void Server::deleteParticleSpawnerAll(u32 id)
3016 {
3017         m_particlespawner_ids.erase(
3018                         std::remove(m_particlespawner_ids.begin(),
3019                         m_particlespawner_ids.end(), id),
3020                         m_particlespawner_ids.end());
3021         SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
3022 }
3023
3024 Inventory* Server::createDetachedInventory(const std::string &name)
3025 {
3026         if(m_detached_inventories.count(name) > 0){
3027                 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3028                 delete m_detached_inventories[name];
3029         } else {
3030                 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3031         }
3032         Inventory *inv = new Inventory(m_itemdef);
3033         assert(inv);
3034         m_detached_inventories[name] = inv;
3035         //TODO find a better way to do this
3036         sendDetachedInventory(name,PEER_ID_INEXISTENT);
3037         return inv;
3038 }
3039
3040 class BoolScopeSet
3041 {
3042 public:
3043         BoolScopeSet(bool *dst, bool val):
3044                 m_dst(dst)
3045         {
3046                 m_orig_state = *m_dst;
3047                 *m_dst = val;
3048         }
3049         ~BoolScopeSet()
3050         {
3051                 *m_dst = m_orig_state;
3052         }
3053 private:
3054         bool *m_dst;
3055         bool m_orig_state;
3056 };
3057
3058 // actions: time-reversed list
3059 // Return value: success/failure
3060 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3061                 std::list<std::string> *log)
3062 {
3063         infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3064         ServerMap *map = (ServerMap*)(&m_env->getMap());
3065
3066         // Fail if no actions to handle
3067         if(actions.empty()){
3068                 log->push_back("Nothing to do.");
3069                 return false;
3070         }
3071
3072         int num_tried = 0;
3073         int num_failed = 0;
3074
3075         for(std::list<RollbackAction>::const_iterator
3076                         i = actions.begin();
3077                         i != actions.end(); i++)
3078         {
3079                 const RollbackAction &action = *i;
3080                 num_tried++;
3081                 bool success = action.applyRevert(map, this, this);
3082                 if(!success){
3083                         num_failed++;
3084                         std::ostringstream os;
3085                         os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3086                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3087                         if(log)
3088                                 log->push_back(os.str());
3089                 }else{
3090                         std::ostringstream os;
3091                         os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3092                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3093                         if(log)
3094                                 log->push_back(os.str());
3095                 }
3096         }
3097
3098         infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3099                         <<" failed"<<std::endl;
3100
3101         // Call it done if less than half failed
3102         return num_failed <= num_tried/2;
3103 }
3104
3105 // IGameDef interface
3106 // Under envlock
3107 IItemDefManager* Server::getItemDefManager()
3108 {
3109         return m_itemdef;
3110 }
3111 INodeDefManager* Server::getNodeDefManager()
3112 {
3113         return m_nodedef;
3114 }
3115 ICraftDefManager* Server::getCraftDefManager()
3116 {
3117         return m_craftdef;
3118 }
3119 ITextureSource* Server::getTextureSource()
3120 {
3121         return NULL;
3122 }
3123 IShaderSource* Server::getShaderSource()
3124 {
3125         return NULL;
3126 }
3127 scene::ISceneManager* Server::getSceneManager()
3128 {
3129         return NULL;
3130 }
3131
3132 u16 Server::allocateUnknownNodeId(const std::string &name)
3133 {
3134         return m_nodedef->allocateDummy(name);
3135 }
3136 ISoundManager* Server::getSoundManager()
3137 {
3138         return &dummySoundManager;
3139 }
3140 MtEventManager* Server::getEventManager()
3141 {
3142         return m_event;
3143 }
3144
3145 IWritableItemDefManager* Server::getWritableItemDefManager()
3146 {
3147         return m_itemdef;
3148 }
3149 IWritableNodeDefManager* Server::getWritableNodeDefManager()
3150 {
3151         return m_nodedef;
3152 }
3153 IWritableCraftDefManager* Server::getWritableCraftDefManager()
3154 {
3155         return m_craftdef;
3156 }
3157
3158 const ModSpec* Server::getModSpec(const std::string &modname)
3159 {
3160         for(std::vector<ModSpec>::iterator i = m_mods.begin();
3161                         i != m_mods.end(); i++){
3162                 const ModSpec &mod = *i;
3163                 if(mod.name == modname)
3164                         return &mod;
3165         }
3166         return NULL;
3167 }
3168 void Server::getModNames(std::vector<std::string> &modlist)
3169 {
3170         for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++) {
3171                 modlist.push_back(i->name);
3172         }
3173 }
3174 std::string Server::getBuiltinLuaPath()
3175 {
3176         return porting::path_share + DIR_DELIM + "builtin";
3177 }
3178
3179 v3f findSpawnPos(ServerMap &map)
3180 {
3181         //return v3f(50,50,50)*BS;
3182
3183         v3s16 nodepos;
3184
3185 #if 0
3186         nodepos = v2s16(0,0);
3187         groundheight = 20;
3188 #endif
3189
3190 #if 1
3191         s16 water_level = map.getWaterLevel();
3192
3193         // Try to find a good place a few times
3194         for(s32 i=0; i<1000; i++)
3195         {
3196                 s32 range = 1 + i;
3197                 // We're going to try to throw the player to this position
3198                 v2s16 nodepos2d = v2s16(
3199                                 -range + (myrand() % (range * 2)),
3200                                 -range + (myrand() % (range * 2)));
3201
3202                 // Get ground height at point
3203                 s16 groundheight = map.findGroundLevel(nodepos2d);
3204                 if (groundheight <= water_level) // Don't go underwater
3205                         continue;
3206                 if (groundheight > water_level + 6) // Don't go to high places
3207                         continue;
3208
3209                 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
3210                 bool is_good = false;
3211                 s32 air_count = 0;
3212                 for (s32 i = 0; i < 10; i++) {
3213                         v3s16 blockpos = getNodeBlockPos(nodepos);
3214                         map.emergeBlock(blockpos, true);
3215                         content_t c = map.getNodeNoEx(nodepos).getContent();
3216                         if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3217                                 air_count++;
3218                                 if (air_count >= 2){
3219                                         is_good = true;
3220                                         break;
3221                                 }
3222                         }
3223                         nodepos.Y++;
3224                 }
3225                 if(is_good){
3226                         // Found a good place
3227                         //infostream<<"Searched through "<<i<<" places."<<std::endl;
3228                         break;
3229                 }
3230         }
3231 #endif
3232
3233         return intToFloat(nodepos, BS);
3234 }
3235
3236 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
3237 {
3238         bool newplayer = false;
3239
3240         /*
3241                 Try to get an existing player
3242         */
3243         RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
3244
3245         // If player is already connected, cancel
3246         if(player != NULL && player->peer_id != 0)
3247         {
3248                 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3249                 return NULL;
3250         }
3251
3252         /*
3253                 If player with the wanted peer_id already exists, cancel.
3254         */
3255         if(m_env->getPlayer(peer_id) != NULL)
3256         {
3257                 infostream<<"emergePlayer(): Player with wrong name but same"
3258                                 " peer_id already exists"<<std::endl;
3259                 return NULL;
3260         }
3261
3262         // Load player if it isn't already loaded
3263         if (!player) {
3264                 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
3265         }
3266
3267         // Create player if it doesn't exist
3268         if (!player) {
3269                 newplayer = true;
3270                 player = new RemotePlayer(this, name);
3271                 // Set player position
3272                 infostream<<"Server: Finding spawn place for player \""
3273                                 <<name<<"\""<<std::endl;
3274                 v3f pos = findSpawnPos(m_env->getServerMap());
3275                 player->setPosition(pos);
3276
3277                 // Make sure the player is saved
3278                 player->setModified(true);
3279
3280                 // Add player to environment
3281                 m_env->addPlayer(player);
3282         }
3283
3284         // Create a new player active object
3285         PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
3286                         getPlayerEffectivePrivs(player->getName()),
3287                         isSingleplayer());
3288
3289         /* Clean up old HUD elements from previous sessions */
3290         player->clearHud();
3291
3292         /* Add object to environment */
3293         m_env->addActiveObject(playersao);
3294
3295         /* Run scripts */
3296         if (newplayer) {
3297                 m_script->on_newplayer(playersao);
3298         }
3299
3300         return playersao;
3301 }
3302
3303 void dedicated_server_loop(Server &server, bool &kill)
3304 {
3305         DSTACK(__FUNCTION_NAME);
3306
3307         verbosestream<<"dedicated_server_loop()"<<std::endl;
3308
3309         IntervalLimiter m_profiler_interval;
3310
3311         for(;;)
3312         {
3313                 float steplen = g_settings->getFloat("dedicated_server_step");
3314                 // This is kind of a hack but can be done like this
3315                 // because server.step() is very light
3316                 {
3317                         ScopeProfiler sp(g_profiler, "dedicated server sleep");
3318                         sleep_ms((int)(steplen*1000.0));
3319                 }
3320                 server.step(steplen);
3321
3322                 if(server.getShutdownRequested() || kill)
3323                 {
3324                         infostream<<"Dedicated server quitting"<<std::endl;
3325 #if USE_CURL
3326                         if(g_settings->getBool("server_announce"))
3327                                 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
3328 #endif
3329                         break;
3330                 }
3331
3332                 /*
3333                         Profiler
3334                 */
3335                 float profiler_print_interval =
3336                                 g_settings->getFloat("profiler_print_interval");
3337                 if(profiler_print_interval != 0)
3338                 {
3339                         if(m_profiler_interval.step(steplen, profiler_print_interval))
3340                         {
3341                                 infostream<<"Profiler:"<<std::endl;
3342                                 g_profiler->print(infostream);
3343                                 g_profiler->clear();
3344                         }
3345                 }
3346         }
3347 }
3348
3349