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