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