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