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