]> git.lizzy.rs Git - dragonfireclient.git/blob - src/server.cpp
Cache serialized mapblocks during sending
[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, SerializedBlockCache *cache)
2330 {
2331         thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
2332         std::string s, *sptr = nullptr;
2333
2334         if (cache) {
2335                 auto it = cache->find({block->getPos(), ver});
2336                 if (it != cache->end())
2337                         sptr = &it->second;
2338         }
2339
2340         // Serialize the block in the right format
2341         if (!sptr) {
2342                 std::ostringstream os(std::ios_base::binary);
2343                 block->serialize(os, ver, false, net_compression_level);
2344                 block->serializeNetworkSpecific(os);
2345                 s = os.str();
2346                 sptr = &s;
2347         }
2348
2349         NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + sptr->size(), peer_id);
2350         pkt << block->getPos();
2351         pkt.putRawString(*sptr);
2352         Send(&pkt);
2353
2354         // Store away in cache
2355         if (cache && sptr == &s)
2356                 (*cache)[{block->getPos(), ver}] = std::move(s);
2357 }
2358
2359 void Server::SendBlocks(float dtime)
2360 {
2361         MutexAutoLock envlock(m_env_mutex);
2362         //TODO check if one big lock could be faster then multiple small ones
2363
2364         std::vector<PrioritySortedBlockTransfer> queue;
2365
2366         u32 total_sending = 0, unique_clients = 0;
2367
2368         {
2369                 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2370
2371                 std::vector<session_t> clients = m_clients.getClientIDs();
2372
2373                 ClientInterface::AutoLock clientlock(m_clients);
2374                 for (const session_t client_id : clients) {
2375                         RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2376
2377                         if (!client)
2378                                 continue;
2379
2380                         total_sending += client->getSendingCount();
2381                         const auto old_count = queue.size();
2382                         client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2383                         unique_clients += queue.size() > old_count ? 1 : 0;
2384                 }
2385         }
2386
2387         // Sort.
2388         // Lowest priority number comes first.
2389         // Lowest is most important.
2390         std::sort(queue.begin(), queue.end());
2391
2392         ClientInterface::AutoLock clientlock(m_clients);
2393
2394         // Maximal total count calculation
2395         // The per-client block sends is halved with the maximal online users
2396         u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2397                 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2398
2399         ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2400         Map &map = m_env->getMap();
2401
2402         SerializedBlockCache cache, *cache_ptr = nullptr;
2403         if (unique_clients > 1) {
2404                 // caching is pointless with a single client
2405                 cache_ptr = &cache;
2406         }
2407
2408         for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2409                 if (total_sending >= max_blocks_to_send)
2410                         break;
2411
2412                 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2413                 if (!block)
2414                         continue;
2415
2416                 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2417                                 CS_Active);
2418                 if (!client)
2419                         continue;
2420
2421                 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2422                                 client->net_proto_version, cache_ptr);
2423
2424                 client->SentBlock(block_to_send.pos);
2425                 total_sending++;
2426         }
2427 }
2428
2429 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2430 {
2431         MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2432         if (!block)
2433                 return false;
2434
2435         ClientInterface::AutoLock clientlock(m_clients);
2436         RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2437         if (!client || client->isBlockSent(blockpos))
2438                 return false;
2439         SendBlockNoLock(peer_id, block, client->serialization_version,
2440                         client->net_proto_version);
2441
2442         return true;
2443 }
2444
2445 bool Server::addMediaFile(const std::string &filename,
2446         const std::string &filepath, std::string *filedata_to,
2447         std::string *digest_to)
2448 {
2449         // If name contains illegal characters, ignore the file
2450         if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2451                 infostream << "Server: ignoring illegal file name: \""
2452                                 << filename << "\"" << std::endl;
2453                 return false;
2454         }
2455         // If name is not in a supported format, ignore it
2456         const char *supported_ext[] = {
2457                 ".png", ".jpg", ".bmp", ".tga",
2458                 ".ogg",
2459                 ".x", ".b3d", ".obj",
2460                 // Custom translation file format
2461                 ".tr",
2462                 NULL
2463         };
2464         if (removeStringEnd(filename, supported_ext).empty()) {
2465                 infostream << "Server: ignoring unsupported file extension: \""
2466                                 << filename << "\"" << std::endl;
2467                 return false;
2468         }
2469         // Ok, attempt to load the file and add to cache
2470
2471         // Read data
2472         std::string filedata;
2473         if (!fs::ReadFile(filepath, filedata)) {
2474                 errorstream << "Server::addMediaFile(): Failed to open \""
2475                                         << filename << "\" for reading" << std::endl;
2476                 return false;
2477         }
2478
2479         if (filedata.empty()) {
2480                 errorstream << "Server::addMediaFile(): Empty file \""
2481                                 << filepath << "\"" << std::endl;
2482                 return false;
2483         }
2484
2485         SHA1 sha1;
2486         sha1.addBytes(filedata.c_str(), filedata.length());
2487
2488         unsigned char *digest = sha1.getDigest();
2489         std::string sha1_base64 = base64_encode(digest, 20);
2490         std::string sha1_hex = hex_encode((char*) digest, 20);
2491         if (digest_to)
2492                 *digest_to = std::string((char*) digest, 20);
2493         free(digest);
2494
2495         // Put in list
2496         m_media[filename] = MediaInfo(filepath, sha1_base64);
2497         verbosestream << "Server: " << sha1_hex << " is " << filename
2498                         << std::endl;
2499
2500         if (filedata_to)
2501                 *filedata_to = std::move(filedata);
2502         return true;
2503 }
2504
2505 void Server::fillMediaCache()
2506 {
2507         infostream << "Server: Calculating media file checksums" << std::endl;
2508
2509         // Collect all media file paths
2510         std::vector<std::string> paths;
2511
2512         // ordered in descending priority
2513         paths.push_back(getBuiltinLuaPath() + DIR_DELIM + "locale");
2514         fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2515         fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2516         m_modmgr->getModsMediaPaths(paths);
2517
2518         // Collect media file information from paths into cache
2519         for (const std::string &mediapath : paths) {
2520                 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2521                 for (const fs::DirListNode &dln : dirlist) {
2522                         if (dln.dir) // Ignore dirs (already in paths)
2523                                 continue;
2524
2525                         const std::string &filename = dln.name;
2526                         if (m_media.find(filename) != m_media.end()) // Do not override
2527                                 continue;
2528
2529                         std::string filepath = mediapath;
2530                         filepath.append(DIR_DELIM).append(filename);
2531                         addMediaFile(filename, filepath);
2532                 }
2533         }
2534
2535         infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2536 }
2537
2538 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2539 {
2540         // Make packet
2541         NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2542
2543         u16 media_sent = 0;
2544         std::string lang_suffix;
2545         lang_suffix.append(".").append(lang_code).append(".tr");
2546         for (const auto &i : m_media) {
2547                 if (i.second.no_announce)
2548                         continue;
2549                 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2550                         continue;
2551                 media_sent++;
2552         }
2553
2554         pkt << media_sent;
2555
2556         for (const auto &i : m_media) {
2557                 if (i.second.no_announce)
2558                         continue;
2559                 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2560                         continue;
2561                 pkt << i.first << i.second.sha1_digest;
2562         }
2563
2564         pkt << g_settings->get("remote_media");
2565         Send(&pkt);
2566
2567         verbosestream << "Server: Announcing files to id(" << peer_id
2568                 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2569 }
2570
2571 struct SendableMedia
2572 {
2573         std::string name;
2574         std::string path;
2575         std::string data;
2576
2577         SendableMedia(const std::string &name, const std::string &path,
2578                         std::string &&data):
2579                 name(name), path(path), data(std::move(data))
2580         {}
2581 };
2582
2583 void Server::sendRequestedMedia(session_t peer_id,
2584                 const std::vector<std::string> &tosend)
2585 {
2586         verbosestream<<"Server::sendRequestedMedia(): "
2587                         <<"Sending files to client"<<std::endl;
2588
2589         /* Read files */
2590
2591         // Put 5kB in one bunch (this is not accurate)
2592         u32 bytes_per_bunch = 5000;
2593
2594         std::vector< std::vector<SendableMedia> > file_bunches;
2595         file_bunches.emplace_back();
2596
2597         u32 file_size_bunch_total = 0;
2598
2599         for (const std::string &name : tosend) {
2600                 if (m_media.find(name) == m_media.end()) {
2601                         errorstream<<"Server::sendRequestedMedia(): Client asked for "
2602                                         <<"unknown file \""<<(name)<<"\""<<std::endl;
2603                         continue;
2604                 }
2605
2606                 const auto &m = m_media[name];
2607
2608                 // Read data
2609                 std::string data;
2610                 if (!fs::ReadFile(m.path, data)) {
2611                         errorstream << "Server::sendRequestedMedia(): Failed to read \""
2612                                         << name << "\"" << std::endl;
2613                         continue;
2614                 }
2615                 file_size_bunch_total += data.size();
2616
2617                 // Put in list
2618                 file_bunches.back().emplace_back(name, m.path, std::move(data));
2619
2620                 // Start next bunch if got enough data
2621                 if(file_size_bunch_total >= bytes_per_bunch) {
2622                         file_bunches.emplace_back();
2623                         file_size_bunch_total = 0;
2624                 }
2625
2626         }
2627
2628         /* Create and send packets */
2629
2630         u16 num_bunches = file_bunches.size();
2631         for (u16 i = 0; i < num_bunches; i++) {
2632                 /*
2633                         u16 command
2634                         u16 total number of texture bunches
2635                         u16 index of this bunch
2636                         u32 number of files in this bunch
2637                         for each file {
2638                                 u16 length of name
2639                                 string name
2640                                 u32 length of data
2641                                 data
2642                         }
2643                 */
2644
2645                 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2646                 pkt << num_bunches << i << (u32) file_bunches[i].size();
2647
2648                 for (const SendableMedia &j : file_bunches[i]) {
2649                         pkt << j.name;
2650                         pkt.putLongString(j.data);
2651                 }
2652
2653                 verbosestream << "Server::sendRequestedMedia(): bunch "
2654                                 << i << "/" << num_bunches
2655                                 << " files=" << file_bunches[i].size()
2656                                 << " size="  << pkt.getSize() << std::endl;
2657                 Send(&pkt);
2658         }
2659 }
2660
2661 void Server::stepPendingDynMediaCallbacks(float dtime)
2662 {
2663         MutexAutoLock lock(m_env_mutex);
2664
2665         for (auto it = m_pending_dyn_media.begin(); it != m_pending_dyn_media.end();) {
2666                 it->second.expiry_timer -= dtime;
2667                 bool del = it->second.waiting_players.empty() || it->second.expiry_timer < 0;
2668
2669                 if (!del) {
2670                         it++;
2671                         continue;
2672                 }
2673
2674                 const auto &name = it->second.filename;
2675                 if (!name.empty()) {
2676                         assert(m_media.count(name));
2677                         // if no_announce isn't set we're definitely deleting the wrong file!
2678                         sanity_check(m_media[name].no_announce);
2679
2680                         fs::DeleteSingleFileOrEmptyDirectory(m_media[name].path);
2681                         m_media.erase(name);
2682                 }
2683                 getScriptIface()->freeDynamicMediaCallback(it->first);
2684                 it = m_pending_dyn_media.erase(it);
2685         }
2686 }
2687
2688 void Server::SendMinimapModes(session_t peer_id,
2689                 std::vector<MinimapMode> &modes, size_t wanted_mode)
2690 {
2691         RemotePlayer *player = m_env->getPlayer(peer_id);
2692         assert(player);
2693         if (player->getPeerId() == PEER_ID_INEXISTENT)
2694                 return;
2695
2696         NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2697         pkt << (u16)modes.size() << (u16)wanted_mode;
2698
2699         for (auto &mode : modes)
2700                 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2701
2702         Send(&pkt);
2703 }
2704
2705 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2706 {
2707         NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2708         pkt << name;
2709
2710         if (!inventory) {
2711                 pkt << false; // Remove inventory
2712         } else {
2713                 pkt << true; // Update inventory
2714
2715                 // Serialization & NetworkPacket isn't a love story
2716                 std::ostringstream os(std::ios_base::binary);
2717                 inventory->serialize(os);
2718                 inventory->setModified(false);
2719
2720                 const std::string &os_str = os.str();
2721                 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2722                 pkt.putRawString(os_str);
2723         }
2724
2725         if (peer_id == PEER_ID_INEXISTENT)
2726                 m_clients.sendToAll(&pkt);
2727         else
2728                 Send(&pkt);
2729 }
2730
2731 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2732 {
2733         // Lookup player name, to filter detached inventories just after
2734         std::string peer_name;
2735         if (peer_id != PEER_ID_INEXISTENT) {
2736                 peer_name = getClient(peer_id, CS_Created)->getName();
2737         }
2738
2739         auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2740                 sendDetachedInventory(inv, name, peer_id);
2741         };
2742
2743         m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2744 }
2745
2746 /*
2747         Something random
2748 */
2749
2750 void Server::HandlePlayerDeath(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
2751 {
2752         infostream << "Server::DiePlayer(): Player "
2753                         << playersao->getPlayer()->getName()
2754                         << " dies" << std::endl;
2755
2756         playersao->clearParentAttachment();
2757
2758         // Trigger scripted stuff
2759         m_script->on_dieplayer(playersao, reason);
2760
2761         SendDeathscreen(playersao->getPeerID(), false, v3f(0,0,0));
2762 }
2763
2764 void Server::RespawnPlayer(session_t peer_id)
2765 {
2766         PlayerSAO *playersao = getPlayerSAO(peer_id);
2767         assert(playersao);
2768
2769         infostream << "Server::RespawnPlayer(): Player "
2770                         << playersao->getPlayer()->getName()
2771                         << " respawns" << std::endl;
2772
2773         playersao->setHP(playersao->accessObjectProperties()->hp_max,
2774                         PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2775         playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2776
2777         bool repositioned = m_script->on_respawnplayer(playersao);
2778         if (!repositioned) {
2779                 // setPos will send the new position to client
2780                 playersao->setPos(findSpawnPos());
2781         }
2782 }
2783
2784
2785 void Server::DenySudoAccess(session_t peer_id)
2786 {
2787         NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2788         Send(&pkt);
2789 }
2790
2791
2792 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2793                 const std::string &custom_reason, bool reconnect)
2794 {
2795         SendAccessDenied(peer_id, reason, custom_reason, reconnect);
2796         m_clients.event(peer_id, CSE_SetDenied);
2797         DisconnectPeer(peer_id);
2798 }
2799
2800 void Server::DisconnectPeer(session_t peer_id)
2801 {
2802         m_modchannel_mgr->leaveAllChannels(peer_id);
2803         m_con->DisconnectPeer(peer_id);
2804 }
2805
2806 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2807 {
2808         if (!forSudoMode) {
2809                 RemoteClient* client = getClient(peer_id, CS_Invalid);
2810
2811                 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2812
2813                 // Right now, the auth mechs don't change between login and sudo mode.
2814                 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2815                 client->allowed_sudo_mechs = sudo_auth_mechs;
2816
2817                 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2818                                 << g_settings->getFloat("dedicated_server_step")
2819                                 << sudo_auth_mechs;
2820
2821                 Send(&resp_pkt);
2822                 m_clients.event(peer_id, CSE_AuthAccept);
2823         } else {
2824                 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2825
2826                 // We only support SRP right now
2827                 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2828
2829                 resp_pkt << sudo_auth_mechs;
2830                 Send(&resp_pkt);
2831                 m_clients.event(peer_id, CSE_SudoSuccess);
2832         }
2833 }
2834
2835 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2836 {
2837         std::wstring message;
2838         {
2839                 /*
2840                         Clear references to playing sounds
2841                 */
2842                 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2843                                  i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2844                         ServerPlayingSound &psound = i->second;
2845                         psound.clients.erase(peer_id);
2846                         if (psound.clients.empty())
2847                                 m_playing_sounds.erase(i++);
2848                         else
2849                                 ++i;
2850                 }
2851
2852                 // clear formspec info so the next client can't abuse the current state
2853                 m_formspec_state_data.erase(peer_id);
2854
2855                 RemotePlayer *player = m_env->getPlayer(peer_id);
2856
2857                 /* Run scripts and remove from environment */
2858                 if (player) {
2859                         PlayerSAO *playersao = player->getPlayerSAO();
2860                         assert(playersao);
2861
2862                         playersao->clearChildAttachments();
2863                         playersao->clearParentAttachment();
2864
2865                         // inform connected clients
2866                         const std::string &player_name = player->getName();
2867                         NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2868                         // (u16) 1 + std::string represents a vector serialization representation
2869                         notice << (u8) PLAYER_LIST_REMOVE  << (u16) 1 << player_name;
2870                         m_clients.sendToAll(&notice);
2871                         // run scripts
2872                         m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2873
2874                         playersao->disconnected();
2875                 }
2876
2877                 /*
2878                         Print out action
2879                 */
2880                 {
2881                         if (player && reason != CDR_DENY) {
2882                                 std::ostringstream os(std::ios_base::binary);
2883                                 std::vector<session_t> clients = m_clients.getClientIDs();
2884
2885                                 for (const session_t client_id : clients) {
2886                                         // Get player
2887                                         RemotePlayer *player = m_env->getPlayer(client_id);
2888                                         if (!player)
2889                                                 continue;
2890
2891                                         // Get name of player
2892                                         os << player->getName() << " ";
2893                                 }
2894
2895                                 std::string name = player->getName();
2896                                 actionstream << name << " "
2897                                                 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2898                                                 << " List of players: " << os.str() << std::endl;
2899                                 if (m_admin_chat)
2900                                         m_admin_chat->outgoing_queue.push_back(
2901                                                 new ChatEventNick(CET_NICK_REMOVE, name));
2902                         }
2903                 }
2904                 {
2905                         MutexAutoLock env_lock(m_env_mutex);
2906                         m_clients.DeleteClient(peer_id);
2907                 }
2908         }
2909
2910         // Send leave chat message to all remaining clients
2911         if (!message.empty()) {
2912                 SendChatMessage(PEER_ID_INEXISTENT,
2913                                 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2914         }
2915 }
2916
2917 void Server::UpdateCrafting(RemotePlayer *player)
2918 {
2919         InventoryList *clist = player->inventory.getList("craft");
2920         if (!clist || clist->getSize() == 0)
2921                 return;
2922
2923         if (!clist->checkModified())
2924                 return;
2925
2926         // Get a preview for crafting
2927         ItemStack preview;
2928         InventoryLocation loc;
2929         loc.setPlayer(player->getName());
2930         std::vector<ItemStack> output_replacements;
2931         getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2932         m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2933                         clist, loc);
2934
2935         InventoryList *plist = player->inventory.getList("craftpreview");
2936         if (plist && plist->getSize() >= 1) {
2937                 // Put the new preview in
2938                 plist->changeItem(0, preview);
2939         }
2940 }
2941
2942 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2943 {
2944         if (evt->type == CET_NICK_ADD) {
2945                 // The terminal informed us of its nick choice
2946                 m_admin_nick = ((ChatEventNick *)evt)->nick;
2947                 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2948                         errorstream << "You haven't set up an account." << std::endl
2949                                 << "Please log in using the client as '"
2950                                 << m_admin_nick << "' with a secure password." << std::endl
2951                                 << "Until then, you can't execute admin tasks via the console," << std::endl
2952                                 << "and everybody can claim the user account instead of you," << std::endl
2953                                 << "giving them full control over this server." << std::endl;
2954                 }
2955         } else {
2956                 assert(evt->type == CET_CHAT);
2957                 handleAdminChat((ChatEventChat *)evt);
2958         }
2959 }
2960
2961 std::wstring Server::handleChat(const std::string &name,
2962         std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2963 {
2964         // If something goes wrong, this player is to blame
2965         RollbackScopeActor rollback_scope(m_rollback,
2966                         std::string("player:") + name);
2967
2968         if (g_settings->getBool("strip_color_codes"))
2969                 wmessage = unescape_enriched(wmessage);
2970
2971         if (player) {
2972                 switch (player->canSendChatMessage()) {
2973                 case RPLAYER_CHATRESULT_FLOODING: {
2974                         std::wstringstream ws;
2975                         ws << L"You cannot send more messages. You are limited to "
2976                                         << g_settings->getFloat("chat_message_limit_per_10sec")
2977                                         << L" messages per 10 seconds.";
2978                         return ws.str();
2979                 }
2980                 case RPLAYER_CHATRESULT_KICK:
2981                         DenyAccess(player->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING,
2982                                 "You have been kicked due to message flooding.");
2983                         return L"";
2984                 case RPLAYER_CHATRESULT_OK:
2985                         break;
2986                 default:
2987                         FATAL_ERROR("Unhandled chat filtering result found.");
2988                 }
2989         }
2990
2991         if (m_max_chatmessage_length > 0
2992                         && wmessage.length() > m_max_chatmessage_length) {
2993                 return L"Your message exceed the maximum chat message limit set on the server. "
2994                                 L"It was refused. Send a shorter message";
2995         }
2996
2997         auto message = trim(wide_to_utf8(wmessage));
2998         if (message.empty())
2999                 return L"";
3000
3001         if (message.find_first_of("\n\r") != std::wstring::npos) {
3002                 return L"Newlines are not permitted in chat messages";
3003         }
3004
3005         // Run script hook, exit if script ate the chat message
3006         if (m_script->on_chat_message(name, message))
3007                 return L"";
3008
3009         // Line to send
3010         std::wstring line;
3011         // Whether to send line to the player that sent the message, or to all players
3012         bool broadcast_line = true;
3013
3014         if (check_shout_priv && !checkPriv(name, "shout")) {
3015                 line += L"-!- You don't have permission to shout.";
3016                 broadcast_line = false;
3017         } else {
3018                 /*
3019                         Workaround for fixing chat on Android. Lua doesn't handle
3020                         the Cyrillic alphabet and some characters on older Android devices
3021                 */
3022 #ifdef __ANDROID__
3023                 line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
3024 #else
3025                 line += utf8_to_wide(m_script->formatChatMessage(name,
3026                                 wide_to_utf8(wmessage)));
3027 #endif
3028         }
3029
3030         /*
3031                 Tell calling method to send the message to sender
3032         */
3033         if (!broadcast_line)
3034                 return line;
3035
3036         /*
3037                 Send the message to others
3038         */
3039         actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
3040
3041         ChatMessage chatmsg(line);
3042
3043         std::vector<session_t> clients = m_clients.getClientIDs();
3044         for (u16 cid : clients)
3045                 SendChatMessage(cid, chatmsg);
3046
3047         return L"";
3048 }
3049
3050 void Server::handleAdminChat(const ChatEventChat *evt)
3051 {
3052         std::string name = evt->nick;
3053         std::wstring wmessage = evt->evt_msg;
3054
3055         std::wstring answer = handleChat(name, wmessage);
3056
3057         // If asked to send answer to sender
3058         if (!answer.empty()) {
3059                 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3060         }
3061 }
3062
3063 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3064 {
3065         RemoteClient *client = getClientNoEx(peer_id,state_min);
3066         if(!client)
3067                 throw ClientNotFoundException("Client not found");
3068
3069         return client;
3070 }
3071 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3072 {
3073         return m_clients.getClientNoEx(peer_id, state_min);
3074 }
3075
3076 std::string Server::getPlayerName(session_t peer_id)
3077 {
3078         RemotePlayer *player = m_env->getPlayer(peer_id);
3079         if (!player)
3080                 return "[id="+itos(peer_id)+"]";
3081         return player->getName();
3082 }
3083
3084 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3085 {
3086         RemotePlayer *player = m_env->getPlayer(peer_id);
3087         if (!player)
3088                 return NULL;
3089         return player->getPlayerSAO();
3090 }
3091
3092 std::string Server::getStatusString()
3093 {
3094         std::ostringstream os(std::ios_base::binary);
3095         os << "# Server: ";
3096         // Version
3097         os << "version: " << g_version_string;
3098         // Game
3099         os << " | game: " << (m_gamespec.name.empty() ? m_gamespec.id : m_gamespec.name);
3100         // Uptime
3101         os << " | uptime: " << duration_to_string((int) m_uptime_counter->get());
3102         // Max lag estimate
3103         os << " | max lag: " << std::setprecision(3);
3104         os << (m_env ? m_env->getMaxLagEstimate() : 0) << "s";
3105
3106         // Information about clients
3107         bool first = true;
3108         os << " | clients: ";
3109         if (m_env) {
3110                 std::vector<session_t> clients = m_clients.getClientIDs();
3111                 for (session_t client_id : clients) {
3112                         RemotePlayer *player = m_env->getPlayer(client_id);
3113
3114                         // Get name of player
3115                         const char *name = player ? player->getName() : "<unknown>";
3116
3117                         // Add name to information string
3118                         if (!first)
3119                                 os << ", ";
3120                         else
3121                                 first = false;
3122                         os << name;
3123                 }
3124         }
3125
3126         if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3127                 os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
3128
3129         if (!g_settings->get("motd").empty())
3130                 os << std::endl << "# Server: " << g_settings->get("motd");
3131
3132         return os.str();
3133 }
3134
3135 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3136 {
3137         std::set<std::string> privs;
3138         m_script->getAuth(name, NULL, &privs);
3139         return privs;
3140 }
3141
3142 bool Server::checkPriv(const std::string &name, const std::string &priv)
3143 {
3144         std::set<std::string> privs = getPlayerEffectivePrivs(name);
3145         return (privs.count(priv) != 0);
3146 }
3147
3148 void Server::reportPrivsModified(const std::string &name)
3149 {
3150         if (name.empty()) {
3151                 std::vector<session_t> clients = m_clients.getClientIDs();
3152                 for (const session_t client_id : clients) {
3153                         RemotePlayer *player = m_env->getPlayer(client_id);
3154                         reportPrivsModified(player->getName());
3155                 }
3156         } else {
3157                 RemotePlayer *player = m_env->getPlayer(name.c_str());
3158                 if (!player)
3159                         return;
3160                 SendPlayerPrivileges(player->getPeerId());
3161                 PlayerSAO *sao = player->getPlayerSAO();
3162                 if(!sao)
3163                         return;
3164                 sao->updatePrivileges(
3165                                 getPlayerEffectivePrivs(name),
3166                                 isSingleplayer());
3167         }
3168 }
3169
3170 void Server::reportInventoryFormspecModified(const std::string &name)
3171 {
3172         RemotePlayer *player = m_env->getPlayer(name.c_str());
3173         if (!player)
3174                 return;
3175         SendPlayerInventoryFormspec(player->getPeerId());
3176 }
3177
3178 void Server::reportFormspecPrependModified(const std::string &name)
3179 {
3180         RemotePlayer *player = m_env->getPlayer(name.c_str());
3181         if (!player)
3182                 return;
3183         SendPlayerFormspecPrepend(player->getPeerId());
3184 }
3185
3186 void Server::setIpBanned(const std::string &ip, const std::string &name)
3187 {
3188         m_banmanager->add(ip, name);
3189 }
3190
3191 void Server::unsetIpBanned(const std::string &ip_or_name)
3192 {
3193         m_banmanager->remove(ip_or_name);
3194 }
3195
3196 std::string Server::getBanDescription(const std::string &ip_or_name)
3197 {
3198         return m_banmanager->getBanDescription(ip_or_name);
3199 }
3200
3201 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3202 {
3203         // m_env will be NULL if the server is initializing
3204         if (!m_env)
3205                 return;
3206
3207         if (m_admin_nick == name && !m_admin_nick.empty()) {
3208                 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3209         }
3210
3211         RemotePlayer *player = m_env->getPlayer(name);
3212         if (!player) {
3213                 return;
3214         }
3215
3216         if (player->getPeerId() == PEER_ID_INEXISTENT)
3217                 return;
3218
3219         SendChatMessage(player->getPeerId(), ChatMessage(msg));
3220 }
3221
3222 bool Server::showFormspec(const char *playername, const std::string &formspec,
3223         const std::string &formname)
3224 {
3225         // m_env will be NULL if the server is initializing
3226         if (!m_env)
3227                 return false;
3228
3229         RemotePlayer *player = m_env->getPlayer(playername);
3230         if (!player)
3231                 return false;
3232
3233         SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3234         return true;
3235 }
3236
3237 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3238 {
3239         if (!player)
3240                 return -1;
3241
3242         u32 id = player->addHud(form);
3243
3244         SendHUDAdd(player->getPeerId(), id, form);
3245
3246         return id;
3247 }
3248
3249 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3250         if (!player)
3251                 return false;
3252
3253         HudElement* todel = player->removeHud(id);
3254
3255         if (!todel)
3256                 return false;
3257
3258         delete todel;
3259
3260         SendHUDRemove(player->getPeerId(), id);
3261         return true;
3262 }
3263
3264 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3265 {
3266         if (!player)
3267                 return false;
3268
3269         SendHUDChange(player->getPeerId(), id, stat, data);
3270         return true;
3271 }
3272
3273 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3274 {
3275         if (!player)
3276                 return false;
3277
3278         u32 new_hud_flags = (player->hud_flags & ~mask) | flags;
3279         if (new_hud_flags == player->hud_flags) // no change
3280                 return true;
3281         
3282         SendHUDSetFlags(player->getPeerId(), flags, mask);
3283         player->hud_flags = new_hud_flags;
3284
3285         PlayerSAO* playersao = player->getPlayerSAO();
3286
3287         if (!playersao)
3288                 return false;
3289
3290         m_script->player_event(playersao, "hud_changed");
3291         return true;
3292 }
3293
3294 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3295 {
3296         if (!player)
3297                 return false;
3298
3299         if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3300                 return false;
3301
3302         player->setHotbarItemcount(hotbar_itemcount);
3303         std::ostringstream os(std::ios::binary);
3304         writeS32(os, hotbar_itemcount);
3305         SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3306         return true;
3307 }
3308
3309 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3310 {
3311         if (!player)
3312                 return;
3313
3314         player->setHotbarImage(name);
3315         SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3316 }
3317
3318 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3319 {
3320         if (!player)
3321                 return;
3322
3323         player->setHotbarSelectedImage(name);
3324         SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3325 }
3326
3327 Address Server::getPeerAddress(session_t peer_id)
3328 {
3329         // Note that this is only set after Init was received in Server::handleCommand_Init
3330         return getClient(peer_id, CS_Invalid)->getAddress();
3331 }
3332
3333 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3334                 v2s32 animation_frames[4], f32 frame_speed)
3335 {
3336         sanity_check(player);
3337         player->setLocalAnimations(animation_frames, frame_speed);
3338         SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3339 }
3340
3341 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3342 {
3343         sanity_check(player);
3344         player->eye_offset_first = first;
3345         player->eye_offset_third = third;
3346         SendEyeOffset(player->getPeerId(), first, third);
3347 }
3348
3349 void Server::setSky(RemotePlayer *player, const SkyboxParams &params)
3350 {
3351         sanity_check(player);
3352         player->setSky(params);
3353         SendSetSky(player->getPeerId(), params);
3354 }
3355
3356 void Server::setSun(RemotePlayer *player, const SunParams &params)
3357 {
3358         sanity_check(player);
3359         player->setSun(params);
3360         SendSetSun(player->getPeerId(), params);
3361 }
3362
3363 void Server::setMoon(RemotePlayer *player, const MoonParams &params)
3364 {
3365         sanity_check(player);
3366         player->setMoon(params);
3367         SendSetMoon(player->getPeerId(), params);
3368 }
3369
3370 void Server::setStars(RemotePlayer *player, const StarParams &params)
3371 {
3372         sanity_check(player);
3373         player->setStars(params);
3374         SendSetStars(player->getPeerId(), params);
3375 }
3376
3377 void Server::setClouds(RemotePlayer *player, const CloudParams &params)
3378 {
3379         sanity_check(player);
3380         player->setCloudParams(params);
3381         SendCloudParams(player->getPeerId(), params);
3382 }
3383
3384 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3385         float ratio)
3386 {
3387         sanity_check(player);
3388         player->overrideDayNightRatio(do_override, ratio);
3389         SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3390 }
3391
3392 void Server::setLighting(RemotePlayer *player, const Lighting &lighting)
3393 {
3394         sanity_check(player);
3395         player->setLighting(lighting);
3396         SendSetLighting(player->getPeerId(), lighting);
3397 }
3398
3399 void Server::notifyPlayers(const std::wstring &msg)
3400 {
3401         SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3402 }
3403
3404 void Server::spawnParticle(const std::string &playername,
3405         const ParticleParameters &p)
3406 {
3407         // m_env will be NULL if the server is initializing
3408         if (!m_env)
3409                 return;
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;
3417                 peer_id = player->getPeerId();
3418                 proto_ver = player->protocol_version;
3419         }
3420
3421         SendSpawnParticle(peer_id, proto_ver, p);
3422 }
3423
3424 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3425         ServerActiveObject *attached, const std::string &playername)
3426 {
3427         // m_env will be NULL if the server is initializing
3428         if (!m_env)
3429                 return -1;
3430
3431         session_t peer_id = PEER_ID_INEXISTENT;
3432         u16 proto_ver = 0;
3433         if (!playername.empty()) {
3434                 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3435                 if (!player)
3436                         return -1;
3437                 peer_id = player->getPeerId();
3438                 proto_ver = player->protocol_version;
3439         }
3440
3441         u16 attached_id = attached ? attached->getId() : 0;
3442
3443         u32 id;
3444         if (attached_id == 0)
3445                 id = m_env->addParticleSpawner(p.time);
3446         else
3447                 id = m_env->addParticleSpawner(p.time, attached_id);
3448
3449         SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3450         return id;
3451 }
3452
3453 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3454 {
3455         // m_env will be NULL if the server is initializing
3456         if (!m_env)
3457                 throw ServerError("Can't delete particle spawners during initialisation!");
3458
3459         session_t peer_id = PEER_ID_INEXISTENT;
3460         if (!playername.empty()) {
3461                 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3462                 if (!player)
3463                         return;
3464                 peer_id = player->getPeerId();
3465         }
3466
3467         m_env->deleteParticleSpawner(id);
3468         SendDeleteParticleSpawner(peer_id, id);
3469 }
3470
3471 bool Server::dynamicAddMedia(std::string filepath,
3472         const u32 token, const std::string &to_player, bool ephemeral)
3473 {
3474         std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3475         auto it = m_media.find(filename);
3476         if (it != m_media.end()) {
3477                 // Allow the same path to be "added" again in certain conditions
3478                 if (ephemeral || it->second.path != filepath) {
3479                         errorstream << "Server::dynamicAddMedia(): file \"" << filename
3480                                 << "\" already exists in media cache" << std::endl;
3481                         return false;
3482                 }
3483         }
3484
3485         // Load the file and add it to our media cache
3486         std::string filedata, raw_hash;
3487         bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3488         if (!ok)
3489                 return false;
3490
3491         if (ephemeral) {
3492                 // Create a copy of the file and swap out the path, this removes the
3493                 // requirement that mods keep the file accessible at the original path.
3494                 filepath = fs::CreateTempFile();
3495                 bool ok = ([&] () -> bool {
3496                         if (filepath.empty())
3497                                 return false;
3498                         std::ofstream os(filepath.c_str(), std::ios::binary);
3499                         if (!os.good())
3500                                 return false;
3501                         os << filedata;
3502                         os.close();
3503                         return !os.fail();
3504                 })();
3505                 if (!ok) {
3506                         errorstream << "Server: failed to create a copy of media file "
3507                                 << "\"" << filename << "\"" << std::endl;
3508                         m_media.erase(filename);
3509                         return false;
3510                 }
3511                 verbosestream << "Server: \"" << filename << "\" temporarily copied to "
3512                         << filepath << std::endl;
3513
3514                 m_media[filename].path = filepath;
3515                 m_media[filename].no_announce = true;
3516                 // stepPendingDynMediaCallbacks will clean this up later.
3517         } else if (!to_player.empty()) {
3518                 m_media[filename].no_announce = true;
3519         }
3520
3521         // Push file to existing clients
3522         NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3523         pkt << raw_hash << filename << (bool)ephemeral;
3524
3525         NetworkPacket legacy_pkt = pkt;
3526
3527         // Newer clients get asked to fetch the file (asynchronous)
3528         pkt << token;
3529         // Older clients have an awful hack that just throws the data at them
3530         legacy_pkt.putLongString(filedata);
3531
3532         std::unordered_set<session_t> delivered, waiting;
3533         {
3534                 ClientInterface::AutoLock clientlock(m_clients);
3535                 for (auto &pair : m_clients.getClientList()) {
3536                         if (pair.second->getState() == CS_DefinitionsSent && !ephemeral) {
3537                                 /*
3538                                         If a client is in the DefinitionsSent state it is too late to
3539                                         transfer the file via sendMediaAnnouncement() but at the same
3540                                         time the client cannot accept a media push yet.
3541                                         Short of artificially delaying the joining process there is no
3542                                         way for the server to resolve this so we (currently) opt not to.
3543                                 */
3544                                 warningstream << "The media \"" << filename << "\" (dynamic) could "
3545                                         "not be delivered to " << pair.second->getName()
3546                                         << " due to a race condition." << std::endl;
3547                                 continue;
3548                         }
3549                         if (pair.second->getState() < CS_Active)
3550                                 continue;
3551
3552                         const auto proto_ver = pair.second->net_proto_version;
3553                         if (proto_ver < 39)
3554                                 continue;
3555
3556                         const session_t peer_id = pair.second->peer_id;
3557                         if (!to_player.empty() && getPlayerName(peer_id) != to_player)
3558                                 continue;
3559
3560                         if (proto_ver < 40) {
3561                                 delivered.emplace(peer_id);
3562                                 /*
3563                                         The network layer only guarantees ordered delivery inside a channel.
3564                                         Since the very next packet could be one that uses the media, we have
3565                                         to push the media over ALL channels to ensure it is processed before
3566                                         it is used. In practice this means channels 1 and 0.
3567                                 */
3568                                 m_clients.send(peer_id, 1, &legacy_pkt, true);
3569                                 m_clients.send(peer_id, 0, &legacy_pkt, true);
3570                         } else {
3571                                 waiting.emplace(peer_id);
3572                                 Send(peer_id, &pkt);
3573                         }
3574                 }
3575         }
3576
3577         // Run callback for players that already had the file delivered (legacy-only)
3578         for (session_t peer_id : delivered) {
3579                 if (auto player = m_env->getPlayer(peer_id))
3580                         getScriptIface()->on_dynamic_media_added(token, player->getName());
3581         }
3582
3583         // Save all others in our pending state
3584         auto &state = m_pending_dyn_media[token];
3585         state.waiting_players = std::move(waiting);
3586         // regardless of success throw away the callback after a while
3587         state.expiry_timer = 60.0f;
3588         if (ephemeral)
3589                 state.filename = filename;
3590
3591         return true;
3592 }
3593
3594 // actions: time-reversed list
3595 // Return value: success/failure
3596 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3597                 std::list<std::string> *log)
3598 {
3599         infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3600         ServerMap *map = (ServerMap*)(&m_env->getMap());
3601
3602         // Fail if no actions to handle
3603         if (actions.empty()) {
3604                 assert(log);
3605                 log->push_back("Nothing to do.");
3606                 return false;
3607         }
3608
3609         int num_tried = 0;
3610         int num_failed = 0;
3611
3612         for (const RollbackAction &action : actions) {
3613                 num_tried++;
3614                 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3615                 if(!success){
3616                         num_failed++;
3617                         std::ostringstream os;
3618                         os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3619                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3620                         if (log)
3621                                 log->push_back(os.str());
3622                 }else{
3623                         std::ostringstream os;
3624                         os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3625                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3626                         if (log)
3627                                 log->push_back(os.str());
3628                 }
3629         }
3630
3631         infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3632                         <<" failed"<<std::endl;
3633
3634         // Call it done if less than half failed
3635         return num_failed <= num_tried/2;
3636 }
3637
3638 // IGameDef interface
3639 // Under envlock
3640 IItemDefManager *Server::getItemDefManager()
3641 {
3642         return m_itemdef;
3643 }
3644
3645 const NodeDefManager *Server::getNodeDefManager()
3646 {
3647         return m_nodedef;
3648 }
3649
3650 ICraftDefManager *Server::getCraftDefManager()
3651 {
3652         return m_craftdef;
3653 }
3654
3655 u16 Server::allocateUnknownNodeId(const std::string &name)
3656 {
3657         return m_nodedef->allocateDummy(name);
3658 }
3659
3660 IWritableItemDefManager *Server::getWritableItemDefManager()
3661 {
3662         return m_itemdef;
3663 }
3664
3665 NodeDefManager *Server::getWritableNodeDefManager()
3666 {
3667         return m_nodedef;
3668 }
3669
3670 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3671 {
3672         return m_craftdef;
3673 }
3674
3675 const std::vector<ModSpec> & Server::getMods() const
3676 {
3677         return m_modmgr->getMods();
3678 }
3679
3680 const ModSpec *Server::getModSpec(const std::string &modname) const
3681 {
3682         return m_modmgr->getModSpec(modname);
3683 }
3684
3685 std::string Server::getBuiltinLuaPath()
3686 {
3687         return porting::path_share + DIR_DELIM + "builtin";
3688 }
3689
3690 v3f Server::findSpawnPos()
3691 {
3692         ServerMap &map = m_env->getServerMap();
3693         v3f nodeposf;
3694         if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3695                 return nodeposf * BS;
3696
3697         bool is_good = false;
3698         // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3699         s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3700
3701         // Try to find a good place a few times
3702         for (s32 i = 0; i < 4000 && !is_good; i++) {
3703                 s32 range = MYMIN(1 + i, range_max);
3704                 // We're going to try to throw the player to this position
3705                 v2s16 nodepos2d = v2s16(
3706                         -range + (myrand() % (range * 2)),
3707                         -range + (myrand() % (range * 2)));
3708                 // Get spawn level at point
3709                 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3710                 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3711                 // signify an unsuitable spawn position, or if outside limits.
3712                 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3713                                 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3714                         continue;
3715
3716                 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3717                 // Consecutive empty nodes
3718                 s32 air_count = 0;
3719
3720                 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3721                 // avoid obstructions in already-generated mapblocks.
3722                 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3723                 // no obstructions, but mapgen decorations are generated after spawn so
3724                 // the player may end up inside one.
3725                 for (s32 i = 0; i < 8; i++) {
3726                         v3s16 blockpos = getNodeBlockPos(nodepos);
3727                         map.emergeBlock(blockpos, true);
3728                         content_t c = map.getNode(nodepos).getContent();
3729
3730                         // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3731                         // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3732                         if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3733                                 air_count++;
3734                                 if (air_count >= 2) {
3735                                         // Spawn in lower empty node
3736                                         nodepos.Y--;
3737                                         nodeposf = intToFloat(nodepos, BS);
3738                                         // Don't spawn the player outside map boundaries
3739                                         if (objectpos_over_limit(nodeposf))
3740                                                 // Exit this loop, positions above are probably over limit
3741                                                 break;
3742
3743                                         // Good position found, cause an exit from main loop
3744                                         is_good = true;
3745                                         break;
3746                                 }
3747                         } else {
3748                                 air_count = 0;
3749                         }
3750                         nodepos.Y++;
3751                 }
3752         }
3753
3754         if (is_good)
3755                 return nodeposf;
3756
3757         // No suitable spawn point found, return fallback 0,0,0
3758         return v3f(0.0f, 0.0f, 0.0f);
3759 }
3760
3761 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3762 {
3763         if (delay == 0.0f) {
3764         // No delay, shutdown immediately
3765                 m_shutdown_state.is_requested = true;
3766                 // only print to the infostream, a chat message saying
3767                 // "Server Shutting Down" is sent when the server destructs.
3768                 infostream << "*** Immediate Server shutdown requested." << std::endl;
3769         } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3770                 // Negative delay, cancel shutdown if requested
3771                 m_shutdown_state.reset();
3772                 std::wstringstream ws;
3773
3774                 ws << L"*** Server shutdown canceled.";
3775
3776                 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3777                 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3778                 // m_shutdown_* are already handled, skip.
3779                 return;
3780         } else if (delay > 0.0f) {
3781         // Positive delay, tell the clients when the server will shut down
3782                 std::wstringstream ws;
3783
3784                 ws << L"*** Server shutting down in "
3785                                 << duration_to_string(myround(delay)).c_str()
3786                                 << ".";
3787
3788                 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3789                 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3790         }
3791
3792         m_shutdown_state.trigger(delay, msg, reconnect);
3793 }
3794
3795 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3796 {
3797         /*
3798                 Try to get an existing player
3799         */
3800         RemotePlayer *player = m_env->getPlayer(name);
3801
3802         // If player is already connected, cancel
3803         if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3804                 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3805                 return NULL;
3806         }
3807
3808         /*
3809                 If player with the wanted peer_id already exists, cancel.
3810         */
3811         if (m_env->getPlayer(peer_id)) {
3812                 infostream<<"emergePlayer(): Player with wrong name but same"
3813                                 " peer_id already exists"<<std::endl;
3814                 return NULL;
3815         }
3816
3817         if (!player) {
3818                 player = new RemotePlayer(name, idef());
3819         }
3820
3821         bool newplayer = false;
3822
3823         // Load player
3824         PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3825
3826         // Complete init with server parts
3827         playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3828         player->protocol_version = proto_version;
3829
3830         /* Run scripts */
3831         if (newplayer) {
3832                 m_script->on_newplayer(playersao);
3833         }
3834
3835         return playersao;
3836 }
3837
3838 bool Server::registerModStorage(ModMetadata *storage)
3839 {
3840         if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3841                 errorstream << "Unable to register same mod storage twice. Storage name: "
3842                                 << storage->getModName() << std::endl;
3843                 return false;
3844         }
3845
3846         m_mod_storages[storage->getModName()] = storage;
3847         return true;
3848 }
3849
3850 void Server::unregisterModStorage(const std::string &name)
3851 {
3852         std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3853         if (it != m_mod_storages.end())
3854                 m_mod_storages.erase(name);
3855 }
3856
3857 void dedicated_server_loop(Server &server, bool &kill)
3858 {
3859         verbosestream<<"dedicated_server_loop()"<<std::endl;
3860
3861         IntervalLimiter m_profiler_interval;
3862
3863         static thread_local const float steplen =
3864                         g_settings->getFloat("dedicated_server_step");
3865         static thread_local const float profiler_print_interval =
3866                         g_settings->getFloat("profiler_print_interval");
3867
3868         /*
3869          * The dedicated server loop only does time-keeping (in Server::step) and
3870          * provides a way to main.cpp to kill the server externally (bool &kill).
3871          */
3872
3873         for(;;) {
3874                 // This is kind of a hack but can be done like this
3875                 // because server.step() is very light
3876                 sleep_ms((int)(steplen*1000.0));
3877                 server.step(steplen);
3878
3879                 if (server.isShutdownRequested() || kill)
3880                         break;
3881
3882                 /*
3883                         Profiler
3884                 */
3885                 if (profiler_print_interval != 0) {
3886                         if(m_profiler_interval.step(steplen, profiler_print_interval))
3887                         {
3888                                 infostream<<"Profiler:"<<std::endl;
3889                                 g_profiler->print(infostream);
3890                                 g_profiler->clear();
3891                         }
3892                 }
3893         }
3894
3895         infostream << "Dedicated server quitting" << std::endl;
3896 #if USE_CURL
3897         if (g_settings->getBool("server_announce"))
3898                 ServerList::sendAnnounce(ServerList::AA_DELETE,
3899                         server.m_bind_addr.getPort());
3900 #endif
3901 }
3902
3903 /*
3904  * Mod channels
3905  */
3906
3907
3908 bool Server::joinModChannel(const std::string &channel)
3909 {
3910         return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3911                         m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3912 }
3913
3914 bool Server::leaveModChannel(const std::string &channel)
3915 {
3916         return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3917 }
3918
3919 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3920 {
3921         if (!m_modchannel_mgr->canWriteOnChannel(channel))
3922                 return false;
3923
3924         broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3925         return true;
3926 }
3927
3928 ModChannel* Server::getModChannel(const std::string &channel)
3929 {
3930         return m_modchannel_mgr->getModChannel(channel);
3931 }
3932
3933 void Server::broadcastModChannelMessage(const std::string &channel,
3934                 const std::string &message, session_t from_peer)
3935 {
3936         const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3937         if (peers.empty())
3938                 return;
3939
3940         if (message.size() > STRING_MAX_LEN) {
3941                 warningstream << "ModChannel message too long, dropping before sending "
3942                                 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3943                                 << channel << ")" << std::endl;
3944                 return;
3945         }
3946
3947         std::string sender;
3948         if (from_peer != PEER_ID_SERVER) {
3949                 sender = getPlayerName(from_peer);
3950         }
3951
3952         NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3953                         2 + channel.size() + 2 + sender.size() + 2 + message.size());
3954         resp_pkt << channel << sender << message;
3955         for (session_t peer_id : peers) {
3956                 // Ignore sender
3957                 if (peer_id == from_peer)
3958                         continue;
3959
3960                 Send(peer_id, &resp_pkt);
3961         }
3962
3963         if (from_peer != PEER_ID_SERVER) {
3964                 m_script->on_modchannel_message(channel, sender, message);
3965         }
3966 }
3967
3968 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3969 {
3970         if (lang_code.empty())
3971                 return nullptr;
3972
3973         auto it = server_translations.find(lang_code);
3974         if (it != server_translations.end())
3975                 return &it->second; // Already loaded
3976
3977         // [] will create an entry
3978         auto *translations = &server_translations[lang_code];
3979
3980         std::string suffix = "." + lang_code + ".tr";
3981         for (const auto &i : m_media) {
3982                 if (str_ends_with(i.first, suffix)) {
3983                         std::string data;
3984                         if (fs::ReadFile(i.second.path, data)) {
3985                                 translations->loadTranslation(data);
3986                         }
3987                 }
3988         }
3989
3990         return translations;
3991 }
3992
3993 ModMetadataDatabase *Server::openModStorageDatabase(const std::string &world_path)
3994 {
3995         std::string world_mt_path = world_path + DIR_DELIM + "world.mt";
3996         Settings world_mt;
3997         if (!world_mt.readConfigFile(world_mt_path.c_str()))
3998                 throw BaseException("Cannot read world.mt!");
3999
4000         std::string backend = world_mt.exists("mod_storage_backend") ?
4001                 world_mt.get("mod_storage_backend") : "files";
4002         if (backend == "files")
4003                 warningstream << "/!\\ You are using the old mod storage files backend. "
4004                         << "This backend is deprecated and may be removed in a future release /!\\"
4005                         << std::endl << "Switching to SQLite3 is advised, "
4006                         << "please read http://wiki.minetest.net/Database_backends." << std::endl;
4007
4008         return openModStorageDatabase(backend, world_path, world_mt);
4009 }
4010
4011 ModMetadataDatabase *Server::openModStorageDatabase(const std::string &backend,
4012                 const std::string &world_path, const Settings &world_mt)
4013 {
4014         if (backend == "sqlite3")
4015                 return new ModMetadataDatabaseSQLite3(world_path);
4016
4017         if (backend == "files")
4018                 return new ModMetadataDatabaseFiles(world_path);
4019
4020         if (backend == "dummy")
4021                 return new Database_Dummy();
4022
4023         throw BaseException("Mod storage database backend " + backend + " not supported");
4024 }
4025
4026 bool Server::migrateModStorageDatabase(const GameParams &game_params, const Settings &cmd_args)
4027 {
4028         std::string migrate_to = cmd_args.get("migrate-mod-storage");
4029         Settings world_mt;
4030         std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt";
4031         if (!world_mt.readConfigFile(world_mt_path.c_str())) {
4032                 errorstream << "Cannot read world.mt!" << std::endl;
4033                 return false;
4034         }
4035
4036         std::string backend = world_mt.exists("mod_storage_backend") ?
4037                 world_mt.get("mod_storage_backend") : "files";
4038         if (backend == migrate_to) {
4039                 errorstream << "Cannot migrate: new backend is same"
4040                         << " as the old one" << std::endl;
4041                 return false;
4042         }
4043
4044         ModMetadataDatabase *srcdb = nullptr;
4045         ModMetadataDatabase *dstdb = nullptr;
4046
4047         bool succeeded = false;
4048
4049         try {
4050                 srcdb = Server::openModStorageDatabase(backend, game_params.world_path, world_mt);
4051                 dstdb = Server::openModStorageDatabase(migrate_to, game_params.world_path, world_mt);
4052
4053                 dstdb->beginSave();
4054
4055                 std::vector<std::string> mod_list;
4056                 srcdb->listMods(&mod_list);
4057                 for (const std::string &modname : mod_list) {
4058                         StringMap meta;
4059                         srcdb->getModEntries(modname, &meta);
4060                         for (const auto &pair : meta) {
4061                                 dstdb->setModEntry(modname, pair.first, pair.second);
4062                         }
4063                 }
4064
4065                 dstdb->endSave();
4066
4067                 succeeded = true;
4068
4069                 actionstream << "Successfully migrated the metadata of "
4070                         << mod_list.size() << " mods" << std::endl;
4071                 world_mt.set("mod_storage_backend", migrate_to);
4072                 if (!world_mt.updateConfigFile(world_mt_path.c_str()))
4073                         errorstream << "Failed to update world.mt!" << std::endl;
4074                 else
4075                         actionstream << "world.mt updated" << std::endl;
4076
4077         } catch (BaseException &e) {
4078                 errorstream << "An error occurred during migration: " << e.what() << std::endl;
4079         }
4080
4081         delete srcdb;
4082         delete dstdb;
4083
4084         if (succeeded && backend == "files") {
4085                 // Back up files
4086                 const std::string storage_path = game_params.world_path + DIR_DELIM + "mod_storage";
4087                 const std::string backup_path = game_params.world_path + DIR_DELIM + "mod_storage.bak";
4088                 if (!fs::Rename(storage_path, backup_path))
4089                         warningstream << "After migration, " << storage_path
4090                                 << " could not be renamed to " << backup_path << std::endl;
4091         }
4092
4093         return succeeded;
4094 }