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