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