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