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