]> git.lizzy.rs Git - minetest.git/blob - src/server.cpp
fb2e0db95b33ab8534b8383f8a6f5e5a1f79f686
[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                 /*
700                         Set the modified blocks unsent for all the clients
701                 */
702                 if (!modified_blocks.empty()) {
703                         SetBlocksNotSent(modified_blocks);
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::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1257 {
1258         std::vector<session_t> clients = m_clients.getClientIDs();
1259         ClientInterface::AutoLock clientlock(m_clients);
1260         // Set the modified blocks unsent for all the clients
1261         for (const session_t client_id : clients) {
1262                         if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1263                                 client->SetBlocksNotSent(block);
1264         }
1265 }
1266
1267 void Server::peerAdded(con::Peer *peer)
1268 {
1269         verbosestream<<"Server::peerAdded(): peer->id="
1270                         <<peer->id<<std::endl;
1271
1272         m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1273 }
1274
1275 void Server::deletingPeer(con::Peer *peer, bool timeout)
1276 {
1277         verbosestream<<"Server::deletingPeer(): peer->id="
1278                         <<peer->id<<", timeout="<<timeout<<std::endl;
1279
1280         m_clients.event(peer->id, CSE_Disconnect);
1281         m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1282 }
1283
1284 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1285 {
1286         *retval = m_con->getPeerStat(peer_id,type);
1287         return *retval != -1;
1288 }
1289
1290 bool Server::getClientInfo(session_t peer_id, ClientInfo &ret)
1291 {
1292         ClientInterface::AutoLock clientlock(m_clients);
1293         RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1294
1295         if (!client)
1296                 return false;
1297
1298         ret.state = client->getState();
1299         ret.addr = client->getAddress();
1300         ret.uptime = client->uptime();
1301         ret.ser_vers = client->serialization_version;
1302         ret.prot_vers = client->net_proto_version;
1303
1304         ret.major = client->getMajor();
1305         ret.minor = client->getMinor();
1306         ret.patch = client->getPatch();
1307         ret.vers_string = client->getFullVer();
1308
1309         ret.lang_code = client->getLangCode();
1310
1311         return true;
1312 }
1313
1314 void Server::handlePeerChanges()
1315 {
1316         while(!m_peer_change_queue.empty())
1317         {
1318                 con::PeerChange c = m_peer_change_queue.front();
1319                 m_peer_change_queue.pop();
1320
1321                 verbosestream<<"Server: Handling peer change: "
1322                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1323                                 <<std::endl;
1324
1325                 switch(c.type)
1326                 {
1327                 case con::PEER_ADDED:
1328                         m_clients.CreateClient(c.peer_id);
1329                         break;
1330
1331                 case con::PEER_REMOVED:
1332                         DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1333                         break;
1334
1335                 default:
1336                         FATAL_ERROR("Invalid peer change event received!");
1337                         break;
1338                 }
1339         }
1340 }
1341
1342 void Server::printToConsoleOnly(const std::string &text)
1343 {
1344         if (m_admin_chat) {
1345                 m_admin_chat->outgoing_queue.push_back(
1346                         new ChatEventChat("", utf8_to_wide(text)));
1347         } else {
1348                 std::cout << text << std::endl;
1349         }
1350 }
1351
1352 void Server::Send(NetworkPacket *pkt)
1353 {
1354         Send(pkt->getPeerId(), pkt);
1355 }
1356
1357 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1358 {
1359         m_clients.send(peer_id,
1360                 clientCommandFactoryTable[pkt->getCommand()].channel,
1361                 pkt,
1362                 clientCommandFactoryTable[pkt->getCommand()].reliable);
1363 }
1364
1365 void Server::SendMovement(session_t peer_id)
1366 {
1367         NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1368
1369         pkt << g_settings->getFloat("movement_acceleration_default");
1370         pkt << g_settings->getFloat("movement_acceleration_air");
1371         pkt << g_settings->getFloat("movement_acceleration_fast");
1372         pkt << g_settings->getFloat("movement_speed_walk");
1373         pkt << g_settings->getFloat("movement_speed_crouch");
1374         pkt << g_settings->getFloat("movement_speed_fast");
1375         pkt << g_settings->getFloat("movement_speed_climb");
1376         pkt << g_settings->getFloat("movement_speed_jump");
1377         pkt << g_settings->getFloat("movement_liquid_fluidity");
1378         pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1379         pkt << g_settings->getFloat("movement_liquid_sink");
1380         pkt << g_settings->getFloat("movement_gravity");
1381
1382         Send(&pkt);
1383 }
1384
1385 void Server::HandlePlayerHPChange(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1386 {
1387         m_script->player_event(playersao, "health_changed");
1388         SendPlayerHP(playersao, reason.type != PlayerHPChangeReason::SET_HP_MAX);
1389
1390         // Send to other clients
1391         playersao->sendPunchCommand();
1392
1393         if (playersao->isDead())
1394                 HandlePlayerDeath(playersao, reason);
1395 }
1396
1397 void Server::SendPlayerHP(PlayerSAO *playersao, bool effect)
1398 {
1399         SendHP(playersao->getPeerID(), playersao->getHP(), effect);
1400 }
1401
1402 void Server::SendHP(session_t peer_id, u16 hp, bool effect)
1403 {
1404         NetworkPacket pkt(TOCLIENT_HP, 3, peer_id);
1405         pkt << hp << effect;
1406         Send(&pkt);
1407 }
1408
1409 void Server::SendBreath(session_t peer_id, u16 breath)
1410 {
1411         NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1412         pkt << (u16) breath;
1413         Send(&pkt);
1414 }
1415
1416 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1417                 const std::string &custom_reason, bool reconnect)
1418 {
1419         assert(reason < SERVER_ACCESSDENIED_MAX);
1420
1421         NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1422         pkt << (u8)reason;
1423         if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1424                 pkt << custom_reason;
1425         else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1426                         reason == SERVER_ACCESSDENIED_CRASH)
1427                 pkt << custom_reason << (u8)reconnect;
1428         Send(&pkt);
1429 }
1430
1431 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1432                 v3f camera_point_target)
1433 {
1434         NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1435         pkt << set_camera_point_target << camera_point_target;
1436         Send(&pkt);
1437 }
1438
1439 void Server::SendItemDef(session_t peer_id,
1440                 IItemDefManager *itemdef, u16 protocol_version)
1441 {
1442         NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1443
1444         /*
1445                 u16 command
1446                 u32 length of the next item
1447                 zlib-compressed serialized ItemDefManager
1448         */
1449         std::ostringstream tmp_os(std::ios::binary);
1450         itemdef->serialize(tmp_os, protocol_version);
1451         std::ostringstream tmp_os2(std::ios::binary);
1452         compressZlib(tmp_os.str(), tmp_os2);
1453         pkt.putLongString(tmp_os2.str());
1454
1455         // Make data buffer
1456         verbosestream << "Server: Sending item definitions to id(" << peer_id
1457                         << "): size=" << pkt.getSize() << std::endl;
1458
1459         Send(&pkt);
1460 }
1461
1462 void Server::SendNodeDef(session_t peer_id,
1463         const NodeDefManager *nodedef, u16 protocol_version)
1464 {
1465         NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1466
1467         /*
1468                 u16 command
1469                 u32 length of the next item
1470                 zlib-compressed serialized NodeDefManager
1471         */
1472         std::ostringstream tmp_os(std::ios::binary);
1473         nodedef->serialize(tmp_os, protocol_version);
1474         std::ostringstream tmp_os2(std::ios::binary);
1475         compressZlib(tmp_os.str(), tmp_os2);
1476
1477         pkt.putLongString(tmp_os2.str());
1478
1479         // Make data buffer
1480         verbosestream << "Server: Sending node definitions to id(" << peer_id
1481                         << "): size=" << pkt.getSize() << std::endl;
1482
1483         Send(&pkt);
1484 }
1485
1486 /*
1487         Non-static send methods
1488 */
1489
1490 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1491 {
1492         RemotePlayer *player = sao->getPlayer();
1493
1494         // Do not send new format to old clients
1495         incremental &= player->protocol_version >= 38;
1496
1497         UpdateCrafting(player);
1498
1499         /*
1500                 Serialize it
1501         */
1502
1503         NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1504
1505         std::ostringstream os(std::ios::binary);
1506         sao->getInventory()->serialize(os, incremental);
1507         sao->getInventory()->setModified(false);
1508         player->setModified(true);
1509
1510         const std::string &s = os.str();
1511         pkt.putRawString(s.c_str(), s.size());
1512         Send(&pkt);
1513 }
1514
1515 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1516 {
1517         NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1518         u8 version = 1;
1519         u8 type = message.type;
1520         pkt << version << type << message.sender << message.message
1521                 << static_cast<u64>(message.timestamp);
1522
1523         if (peer_id != PEER_ID_INEXISTENT) {
1524                 RemotePlayer *player = m_env->getPlayer(peer_id);
1525                 if (!player)
1526                         return;
1527
1528                 Send(&pkt);
1529         } else {
1530                 m_clients.sendToAll(&pkt);
1531         }
1532 }
1533
1534 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1535         const std::string &formname)
1536 {
1537         NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1538         if (formspec.empty()){
1539                 //the client should close the formspec
1540                 //but make sure there wasn't another one open in meantime
1541                 const auto it = m_formspec_state_data.find(peer_id);
1542                 if (it != m_formspec_state_data.end() && it->second == formname) {
1543                         m_formspec_state_data.erase(peer_id);
1544                 }
1545                 pkt.putLongString("");
1546         } else {
1547                 m_formspec_state_data[peer_id] = formname;
1548                 pkt.putLongString(formspec);
1549         }
1550         pkt << formname;
1551
1552         Send(&pkt);
1553 }
1554
1555 // Spawns a particle on peer with peer_id
1556 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1557         const ParticleParameters &p)
1558 {
1559         static thread_local const float radius =
1560                         g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1561
1562         if (peer_id == PEER_ID_INEXISTENT) {
1563                 std::vector<session_t> clients = m_clients.getClientIDs();
1564                 const v3f pos = p.pos * BS;
1565                 const float radius_sq = radius * radius;
1566
1567                 for (const session_t client_id : clients) {
1568                         RemotePlayer *player = m_env->getPlayer(client_id);
1569                         if (!player)
1570                                 continue;
1571
1572                         PlayerSAO *sao = player->getPlayerSAO();
1573                         if (!sao)
1574                                 continue;
1575
1576                         // Do not send to distant clients
1577                         if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1578                                 continue;
1579
1580                         SendSpawnParticle(client_id, player->protocol_version, p);
1581                 }
1582                 return;
1583         }
1584         assert(protocol_version != 0);
1585
1586         NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1587
1588         {
1589                 // NetworkPacket and iostreams are incompatible...
1590                 std::ostringstream oss(std::ios_base::binary);
1591                 p.serialize(oss, protocol_version);
1592                 pkt.putRawString(oss.str());
1593         }
1594
1595         Send(&pkt);
1596 }
1597
1598 // Adds a ParticleSpawner on peer with peer_id
1599 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1600         const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1601 {
1602         static thread_local const float radius =
1603                         g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1604
1605         if (peer_id == PEER_ID_INEXISTENT) {
1606                 std::vector<session_t> clients = m_clients.getClientIDs();
1607                 const v3f pos = (
1608                         p.pos.start.min.val +
1609                         p.pos.start.max.val +
1610                         p.pos.end.min.val +
1611                         p.pos.end.max.val
1612                 ) / 4.0f * BS;
1613                 const float radius_sq = radius * radius;
1614                 /* Don't send short-lived spawners to distant players.
1615                  * This could be replaced with proper tracking at some point. */
1616                 const bool distance_check = !attached_id && p.time <= 1.0f;
1617
1618                 for (const session_t client_id : clients) {
1619                         RemotePlayer *player = m_env->getPlayer(client_id);
1620                         if (!player)
1621                                 continue;
1622
1623                         if (distance_check) {
1624                                 PlayerSAO *sao = player->getPlayerSAO();
1625                                 if (!sao)
1626                                         continue;
1627                                 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1628                                         continue;
1629                         }
1630
1631                         SendAddParticleSpawner(client_id, player->protocol_version,
1632                                 p, attached_id, id);
1633                 }
1634                 return;
1635         }
1636         assert(protocol_version != 0);
1637
1638         NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1639
1640         pkt << p.amount << p.time;
1641         { // serialize legacy fields
1642                 std::ostringstream os(std::ios_base::binary);
1643                 p.pos.start.legacySerialize(os);
1644                 p.vel.start.legacySerialize(os);
1645                 p.acc.start.legacySerialize(os);
1646                 p.exptime.start.legacySerialize(os);
1647                 p.size.start.legacySerialize(os);
1648                 pkt.putRawString(os.str());
1649         }
1650         pkt << p.collisiondetection;
1651
1652         pkt.putLongString(p.texture.string);
1653
1654         pkt << id << p.vertical << p.collision_removal << attached_id;
1655         {
1656                 std::ostringstream os(std::ios_base::binary);
1657                 p.animation.serialize(os, protocol_version);
1658                 pkt.putRawString(os.str());
1659         }
1660         pkt << p.glow << p.object_collision;
1661         pkt << p.node.param0 << p.node.param2 << p.node_tile;
1662
1663         { // serialize new fields
1664                 // initial bias for older properties
1665                 pkt << p.pos.start.bias
1666                         << p.vel.start.bias
1667                         << p.acc.start.bias
1668                         << p.exptime.start.bias
1669                         << p.size.start.bias;
1670
1671                 std::ostringstream os(std::ios_base::binary);
1672
1673                 // final tween frames of older properties
1674                 p.pos.end.serialize(os);
1675                 p.vel.end.serialize(os);
1676                 p.acc.end.serialize(os);
1677                 p.exptime.end.serialize(os);
1678                 p.size.end.serialize(os);
1679
1680                 // properties for legacy texture field
1681                 p.texture.serialize(os, protocol_version, true);
1682
1683                 // new properties
1684                 p.drag.serialize(os);
1685                 p.jitter.serialize(os);
1686                 p.bounce.serialize(os);
1687                 ParticleParamTypes::serializeParameterValue(os, p.attractor_kind);
1688                 if (p.attractor_kind != ParticleParamTypes::AttractorKind::none) {
1689                         p.attract.serialize(os);
1690                         p.attractor_origin.serialize(os);
1691                         writeU16(os, p.attractor_attachment); /* object ID */
1692                         writeU8(os, p.attractor_kill);
1693                         if (p.attractor_kind != ParticleParamTypes::AttractorKind::point) {
1694                                 p.attractor_direction.serialize(os);
1695                                 writeU16(os, p.attractor_direction_attachment);
1696                         }
1697                 }
1698                 p.radius.serialize(os);
1699
1700                 ParticleParamTypes::serializeParameterValue(os, (u16)p.texpool.size());
1701                 for (const auto& tex : p.texpool) {
1702                         tex.serialize(os, protocol_version);
1703                 }
1704
1705                 pkt.putRawString(os.str());
1706         }
1707
1708         Send(&pkt);
1709 }
1710
1711 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1712 {
1713         NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1714
1715         pkt << id;
1716
1717         if (peer_id != PEER_ID_INEXISTENT)
1718                 Send(&pkt);
1719         else
1720                 m_clients.sendToAll(&pkt);
1721
1722 }
1723
1724 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1725 {
1726         NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1727
1728         pkt << id << (u8) form->type << form->pos << form->name << form->scale
1729                         << form->text << form->number << form->item << form->dir
1730                         << form->align << form->offset << form->world_pos << form->size
1731                         << form->z_index << form->text2 << form->style;
1732
1733         Send(&pkt);
1734 }
1735
1736 void Server::SendHUDRemove(session_t peer_id, u32 id)
1737 {
1738         NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1739         pkt << id;
1740         Send(&pkt);
1741 }
1742
1743 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1744 {
1745         NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1746         pkt << id << (u8) stat;
1747
1748         switch (stat) {
1749                 case HUD_STAT_POS:
1750                 case HUD_STAT_SCALE:
1751                 case HUD_STAT_ALIGN:
1752                 case HUD_STAT_OFFSET:
1753                         pkt << *(v2f *) value;
1754                         break;
1755                 case HUD_STAT_NAME:
1756                 case HUD_STAT_TEXT:
1757                 case HUD_STAT_TEXT2:
1758                         pkt << *(std::string *) value;
1759                         break;
1760                 case HUD_STAT_WORLD_POS:
1761                         pkt << *(v3f *) value;
1762                         break;
1763                 case HUD_STAT_SIZE:
1764                         pkt << *(v2s32 *) value;
1765                         break;
1766                 default: // all other types
1767                         pkt << *(u32 *) value;
1768                         break;
1769         }
1770
1771         Send(&pkt);
1772 }
1773
1774 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1775 {
1776         NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1777
1778         flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1779
1780         pkt << flags << mask;
1781
1782         Send(&pkt);
1783 }
1784
1785 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1786 {
1787         NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1788         pkt << param << value;
1789         Send(&pkt);
1790 }
1791
1792 void Server::SendSetSky(session_t peer_id, const SkyboxParams &params)
1793 {
1794         NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1795
1796         // Handle prior clients here
1797         if (m_clients.getProtocolVersion(peer_id) < 39) {
1798                 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1799
1800                 for (const std::string& texture : params.textures)
1801                         pkt << texture;
1802
1803                 pkt << params.clouds;
1804         } else { // Handle current clients and future clients
1805                 pkt << params.bgcolor << params.type
1806                 << params.clouds << params.fog_sun_tint
1807                 << params.fog_moon_tint << params.fog_tint_type;
1808
1809                 if (params.type == "skybox") {
1810                         pkt << (u16) params.textures.size();
1811                         for (const std::string &texture : params.textures)
1812                                 pkt << texture;
1813                 } else if (params.type == "regular") {
1814                         pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1815                                 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1816                                 << params.sky_color.night_sky << params.sky_color.night_horizon
1817                                 << params.sky_color.indoors;
1818                 }
1819         }
1820
1821         Send(&pkt);
1822 }
1823
1824 void Server::SendSetSun(session_t peer_id, const SunParams &params)
1825 {
1826         NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1827         pkt << params.visible << params.texture
1828                 << params.tonemap << params.sunrise
1829                 << params.sunrise_visible << params.scale;
1830
1831         Send(&pkt);
1832 }
1833 void Server::SendSetMoon(session_t peer_id, const MoonParams &params)
1834 {
1835         NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1836
1837         pkt << params.visible << params.texture
1838                 << params.tonemap << params.scale;
1839
1840         Send(&pkt);
1841 }
1842 void Server::SendSetStars(session_t peer_id, const StarParams &params)
1843 {
1844         NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1845
1846         pkt << params.visible << params.count
1847                 << params.starcolor << params.scale
1848                 << params.day_opacity;
1849
1850         Send(&pkt);
1851 }
1852
1853 void Server::SendCloudParams(session_t peer_id, const CloudParams &params)
1854 {
1855         NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1856         pkt << params.density << params.color_bright << params.color_ambient
1857                         << params.height << params.thickness << params.speed;
1858         Send(&pkt);
1859 }
1860
1861 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1862                 float ratio)
1863 {
1864         NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1865                         1 + 2, peer_id);
1866
1867         pkt << do_override << (u16) (ratio * 65535);
1868
1869         Send(&pkt);
1870 }
1871
1872 void Server::SendSetLighting(session_t peer_id, const Lighting &lighting)
1873 {
1874         NetworkPacket pkt(TOCLIENT_SET_LIGHTING,
1875                         4, peer_id);
1876
1877         pkt << lighting.shadow_intensity;
1878
1879         Send(&pkt);
1880 }
1881
1882 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1883 {
1884         NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1885         pkt << time << time_speed;
1886
1887         if (peer_id == PEER_ID_INEXISTENT) {
1888                 m_clients.sendToAll(&pkt);
1889         }
1890         else {
1891                 Send(&pkt);
1892         }
1893 }
1894
1895 void Server::SendPlayerBreath(PlayerSAO *sao)
1896 {
1897         assert(sao);
1898
1899         m_script->player_event(sao, "breath_changed");
1900         SendBreath(sao->getPeerID(), sao->getBreath());
1901 }
1902
1903 void Server::SendMovePlayer(session_t peer_id)
1904 {
1905         RemotePlayer *player = m_env->getPlayer(peer_id);
1906         assert(player);
1907         PlayerSAO *sao = player->getPlayerSAO();
1908         assert(sao);
1909
1910         // Send attachment updates instantly to the client prior updating position
1911         sao->sendOutdatedData();
1912
1913         NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1914         pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1915
1916         {
1917                 v3f pos = sao->getBasePosition();
1918                 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1919                                 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1920                                 << " pitch=" << sao->getLookPitch()
1921                                 << " yaw=" << sao->getRotation().Y
1922                                 << std::endl;
1923         }
1924
1925         Send(&pkt);
1926 }
1927
1928 void Server::SendPlayerFov(session_t peer_id)
1929 {
1930         NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1931
1932         PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1933         pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1934
1935         Send(&pkt);
1936 }
1937
1938 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1939                 f32 animation_speed)
1940 {
1941         NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1942                 peer_id);
1943
1944         pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1945                         << animation_frames[3] << animation_speed;
1946
1947         Send(&pkt);
1948 }
1949
1950 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1951 {
1952         NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1953         pkt << first << third;
1954         Send(&pkt);
1955 }
1956
1957 void Server::SendPlayerPrivileges(session_t peer_id)
1958 {
1959         RemotePlayer *player = m_env->getPlayer(peer_id);
1960         assert(player);
1961         if(player->getPeerId() == PEER_ID_INEXISTENT)
1962                 return;
1963
1964         std::set<std::string> privs;
1965         m_script->getAuth(player->getName(), NULL, &privs);
1966
1967         NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1968         pkt << (u16) privs.size();
1969
1970         for (const std::string &priv : privs) {
1971                 pkt << priv;
1972         }
1973
1974         Send(&pkt);
1975 }
1976
1977 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1978 {
1979         RemotePlayer *player = m_env->getPlayer(peer_id);
1980         assert(player);
1981         if (player->getPeerId() == PEER_ID_INEXISTENT)
1982                 return;
1983
1984         NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1985         pkt.putLongString(player->inventory_formspec);
1986
1987         Send(&pkt);
1988 }
1989
1990 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1991 {
1992         RemotePlayer *player = m_env->getPlayer(peer_id);
1993         assert(player);
1994         if (player->getPeerId() == PEER_ID_INEXISTENT)
1995                 return;
1996
1997         NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1998         pkt << player->formspec_prepend;
1999         Send(&pkt);
2000 }
2001
2002 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
2003 {
2004         // Radius inside which objects are active
2005         static thread_local const s16 radius =
2006                 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
2007
2008         // Radius inside which players are active
2009         static thread_local const bool is_transfer_limited =
2010                 g_settings->exists("unlimited_player_transfer_distance") &&
2011                 !g_settings->getBool("unlimited_player_transfer_distance");
2012
2013         static thread_local const s16 player_transfer_dist =
2014                 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
2015
2016         s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
2017                 radius : player_transfer_dist;
2018
2019         s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
2020         if (my_radius <= 0)
2021                 my_radius = radius;
2022
2023         std::queue<u16> removed_objects, added_objects;
2024         m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
2025                 client->m_known_objects, removed_objects);
2026         m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
2027                 client->m_known_objects, added_objects);
2028
2029         int removed_count = removed_objects.size();
2030         int added_count   = added_objects.size();
2031
2032         if (removed_objects.empty() && added_objects.empty())
2033                 return;
2034
2035         char buf[4];
2036         std::string data;
2037
2038         // Handle removed objects
2039         writeU16((u8*)buf, removed_objects.size());
2040         data.append(buf, 2);
2041         while (!removed_objects.empty()) {
2042                 // Get object
2043                 u16 id = removed_objects.front();
2044                 ServerActiveObject* obj = m_env->getActiveObject(id);
2045
2046                 // Add to data buffer for sending
2047                 writeU16((u8*)buf, id);
2048                 data.append(buf, 2);
2049
2050                 // Remove from known objects
2051                 client->m_known_objects.erase(id);
2052
2053                 if (obj && obj->m_known_by_count > 0)
2054                         obj->m_known_by_count--;
2055
2056                 removed_objects.pop();
2057         }
2058
2059         // Handle added objects
2060         writeU16((u8*)buf, added_objects.size());
2061         data.append(buf, 2);
2062         while (!added_objects.empty()) {
2063                 // Get object
2064                 u16 id = added_objects.front();
2065                 ServerActiveObject *obj = m_env->getActiveObject(id);
2066                 added_objects.pop();
2067
2068                 if (!obj) {
2069                         warningstream << FUNCTION_NAME << ": NULL object id="
2070                                 << (int)id << std::endl;
2071                         continue;
2072                 }
2073
2074                 // Get object type
2075                 u8 type = obj->getSendType();
2076
2077                 // Add to data buffer for sending
2078                 writeU16((u8*)buf, id);
2079                 data.append(buf, 2);
2080                 writeU8((u8*)buf, type);
2081                 data.append(buf, 1);
2082
2083                 data.append(serializeString32(
2084                         obj->getClientInitializationData(client->net_proto_version)));
2085
2086                 // Add to known objects
2087                 client->m_known_objects.insert(id);
2088
2089                 obj->m_known_by_count++;
2090         }
2091
2092         NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2093         pkt.putRawString(data.c_str(), data.size());
2094         Send(&pkt);
2095
2096         verbosestream << "Server::SendActiveObjectRemoveAdd: "
2097                 << removed_count << " removed, " << added_count << " added, "
2098                 << "packet size is " << pkt.getSize() << std::endl;
2099 }
2100
2101 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2102                 bool reliable)
2103 {
2104         NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2105                         datas.size(), peer_id);
2106
2107         pkt.putRawString(datas.c_str(), datas.size());
2108
2109         m_clients.send(pkt.getPeerId(),
2110                         reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2111                         &pkt, reliable);
2112 }
2113
2114 void Server::SendCSMRestrictionFlags(session_t peer_id)
2115 {
2116         NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2117                 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2118         pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2119         Send(&pkt);
2120 }
2121
2122 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2123 {
2124         NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2125         pkt << added_vel;
2126         Send(&pkt);
2127 }
2128
2129 inline s32 Server::nextSoundId()
2130 {
2131         s32 ret = m_next_sound_id;
2132         if (m_next_sound_id == INT32_MAX)
2133                 m_next_sound_id = 0; // signed overflow is undefined
2134         else
2135                 m_next_sound_id++;
2136         return ret;
2137 }
2138
2139 s32 Server::playSound(ServerPlayingSound &params, bool ephemeral)
2140 {
2141         // Find out initial position of sound
2142         bool pos_exists = false;
2143         const v3f pos = params.getPos(m_env, &pos_exists);
2144         // If position is not found while it should be, cancel sound
2145         if(pos_exists != (params.type != SoundLocation::Local))
2146                 return -1;
2147
2148         // Filter destination clients
2149         std::vector<session_t> dst_clients;
2150         if (!params.to_player.empty()) {
2151                 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2152                 if(!player){
2153                         infostream<<"Server::playSound: Player \""<<params.to_player
2154                                         <<"\" not found"<<std::endl;
2155                         return -1;
2156                 }
2157                 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2158                         infostream<<"Server::playSound: Player \""<<params.to_player
2159                                         <<"\" not connected"<<std::endl;
2160                         return -1;
2161                 }
2162                 dst_clients.push_back(player->getPeerId());
2163         } else {
2164                 std::vector<session_t> clients = m_clients.getClientIDs();
2165
2166                 for (const session_t client_id : clients) {
2167                         RemotePlayer *player = m_env->getPlayer(client_id);
2168                         if (!player)
2169                                 continue;
2170                         if (!params.exclude_player.empty() &&
2171                                         params.exclude_player == player->getName())
2172                                 continue;
2173
2174                         PlayerSAO *sao = player->getPlayerSAO();
2175                         if (!sao)
2176                                 continue;
2177
2178                         if (pos_exists) {
2179                                 if(sao->getBasePosition().getDistanceFrom(pos) >
2180                                                 params.max_hear_distance)
2181                                         continue;
2182                         }
2183                         dst_clients.push_back(client_id);
2184                 }
2185         }
2186
2187         if(dst_clients.empty())
2188                 return -1;
2189
2190         // old clients will still use this, so pick a reserved ID (-1)
2191         const s32 id = ephemeral ? -1 : nextSoundId();
2192
2193         float gain = params.gain * params.spec.gain;
2194         NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2195         pkt << id << params.spec.name << gain
2196                         << (u8) params.type << pos << params.object
2197                         << params.spec.loop << params.spec.fade << params.spec.pitch
2198                         << ephemeral;
2199
2200         bool as_reliable = !ephemeral;
2201
2202         for (const session_t peer_id : dst_clients) {
2203                 if (!ephemeral)
2204                         params.clients.insert(peer_id);
2205                 m_clients.send(peer_id, 0, &pkt, as_reliable);
2206         }
2207
2208         if (!ephemeral)
2209                 m_playing_sounds[id] = std::move(params);
2210         return id;
2211 }
2212 void Server::stopSound(s32 handle)
2213 {
2214         auto it = m_playing_sounds.find(handle);
2215         if (it == m_playing_sounds.end())
2216                 return;
2217
2218         ServerPlayingSound &psound = it->second;
2219
2220         NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2221         pkt << handle;
2222
2223         for (session_t peer_id : psound.clients) {
2224                 // Send as reliable
2225                 m_clients.send(peer_id, 0, &pkt, true);
2226         }
2227
2228         // Remove sound reference
2229         m_playing_sounds.erase(it);
2230 }
2231
2232 void Server::fadeSound(s32 handle, float step, float gain)
2233 {
2234         auto it = m_playing_sounds.find(handle);
2235         if (it == m_playing_sounds.end())
2236                 return;
2237
2238         ServerPlayingSound &psound = it->second;
2239         psound.gain = gain; // destination gain
2240
2241         NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2242         pkt << handle << step << gain;
2243
2244         for (session_t peer_id : psound.clients) {
2245                 // Send as reliable
2246                 m_clients.send(peer_id, 0, &pkt, true);
2247         }
2248
2249         // Remove sound reference
2250         if (gain <= 0 || psound.clients.empty())
2251                 m_playing_sounds.erase(it);
2252 }
2253
2254 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2255                 float far_d_nodes)
2256 {
2257         v3f p_f = intToFloat(p, BS);
2258         v3s16 block_pos = getNodeBlockPos(p);
2259
2260         NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2261         pkt << p;
2262
2263         sendNodeChangePkt(pkt, block_pos, p_f, far_d_nodes, far_players);
2264 }
2265
2266 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2267                 float far_d_nodes, bool remove_metadata)
2268 {
2269         v3f p_f = intToFloat(p, BS);
2270         v3s16 block_pos = getNodeBlockPos(p);
2271
2272         NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2273         pkt << p << n.param0 << n.param1 << n.param2
2274                         << (u8) (remove_metadata ? 0 : 1);
2275         sendNodeChangePkt(pkt, block_pos, p_f, far_d_nodes, far_players);
2276 }
2277
2278 void Server::sendNodeChangePkt(NetworkPacket &pkt, v3s16 block_pos,
2279                 v3f p, float far_d_nodes, std::unordered_set<u16> *far_players)
2280 {
2281         float maxd = far_d_nodes * BS;
2282         std::vector<session_t> clients = m_clients.getClientIDs();
2283         ClientInterface::AutoLock clientlock(m_clients);
2284
2285         for (session_t client_id : clients) {
2286                 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2287                 if (!client)
2288                         continue;
2289
2290                 RemotePlayer *player = m_env->getPlayer(client_id);
2291                 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2292
2293                 // If player is far away, only set modified blocks not sent
2294                 if (!client->isBlockSent(block_pos) || (sao &&
2295                                 sao->getBasePosition().getDistanceFrom(p) > maxd)) {
2296                         if (far_players)
2297                                 far_players->emplace(client_id);
2298                         else
2299                                 client->SetBlockNotSent(block_pos);
2300                         continue;
2301                 }
2302
2303                 // Send as reliable
2304                 m_clients.send(client_id, 0, &pkt, true);
2305         }
2306 }
2307
2308 void Server::sendMetadataChanged(const std::unordered_set<v3s16> &positions, float far_d_nodes)
2309 {
2310         NodeMetadataList meta_updates_list(false);
2311         std::ostringstream os(std::ios::binary);
2312
2313         std::vector<session_t> clients = m_clients.getClientIDs();
2314         ClientInterface::AutoLock clientlock(m_clients);
2315
2316         for (session_t i : clients) {
2317                 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2318                 if (!client)
2319                         continue;
2320
2321                 ServerActiveObject *player = getPlayerSAO(i);
2322                 v3s16 player_pos;
2323                 if (player)
2324                         player_pos = floatToInt(player->getBasePosition(), BS);
2325
2326                 for (const v3s16 pos : positions) {
2327                         NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2328
2329                         if (!meta)
2330                                 continue;
2331
2332                         v3s16 block_pos = getNodeBlockPos(pos);
2333                         if (!client->isBlockSent(block_pos) ||
2334                                         player_pos.getDistanceFrom(pos) > far_d_nodes) {
2335                                 client->SetBlockNotSent(block_pos);
2336                                 continue;
2337                         }
2338
2339                         // Add the change to send list
2340                         meta_updates_list.set(pos, meta);
2341                 }
2342                 if (meta_updates_list.size() == 0)
2343                         continue;
2344
2345                 // Send the meta changes
2346                 os.str("");
2347                 meta_updates_list.serialize(os, client->serialization_version, false, true, true);
2348                 std::string raw = os.str();
2349                 os.str("");
2350                 compressZlib(raw, os);
2351
2352                 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0, i);
2353                 pkt.putLongString(os.str());
2354                 Send(&pkt);
2355
2356                 meta_updates_list.clear();
2357         }
2358 }
2359
2360 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2361                 u16 net_proto_version, SerializedBlockCache *cache)
2362 {
2363         thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
2364         std::string s, *sptr = nullptr;
2365
2366         if (cache) {
2367                 auto it = cache->find({block->getPos(), ver});
2368                 if (it != cache->end())
2369                         sptr = &it->second;
2370         }
2371
2372         // Serialize the block in the right format
2373         if (!sptr) {
2374                 std::ostringstream os(std::ios_base::binary);
2375                 block->serialize(os, ver, false, net_compression_level);
2376                 block->serializeNetworkSpecific(os);
2377                 s = os.str();
2378                 sptr = &s;
2379         }
2380
2381         NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + sptr->size(), peer_id);
2382         pkt << block->getPos();
2383         pkt.putRawString(*sptr);
2384         Send(&pkt);
2385
2386         // Store away in cache
2387         if (cache && sptr == &s)
2388                 (*cache)[{block->getPos(), ver}] = std::move(s);
2389 }
2390
2391 void Server::SendBlocks(float dtime)
2392 {
2393         MutexAutoLock envlock(m_env_mutex);
2394         //TODO check if one big lock could be faster then multiple small ones
2395
2396         std::vector<PrioritySortedBlockTransfer> queue;
2397
2398         u32 total_sending = 0, unique_clients = 0;
2399
2400         {
2401                 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2402
2403                 std::vector<session_t> clients = m_clients.getClientIDs();
2404
2405                 ClientInterface::AutoLock clientlock(m_clients);
2406                 for (const session_t client_id : clients) {
2407                         RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2408
2409                         if (!client)
2410                                 continue;
2411
2412                         total_sending += client->getSendingCount();
2413                         const auto old_count = queue.size();
2414                         client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2415                         unique_clients += queue.size() > old_count ? 1 : 0;
2416                 }
2417         }
2418
2419         // Sort.
2420         // Lowest priority number comes first.
2421         // Lowest is most important.
2422         std::sort(queue.begin(), queue.end());
2423
2424         ClientInterface::AutoLock clientlock(m_clients);
2425
2426         // Maximal total count calculation
2427         // The per-client block sends is halved with the maximal online users
2428         u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2429                 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2430
2431         ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2432         Map &map = m_env->getMap();
2433
2434         SerializedBlockCache cache, *cache_ptr = nullptr;
2435         if (unique_clients > 1) {
2436                 // caching is pointless with a single client
2437                 cache_ptr = &cache;
2438         }
2439
2440         for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2441                 if (total_sending >= max_blocks_to_send)
2442                         break;
2443
2444                 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2445                 if (!block)
2446                         continue;
2447
2448                 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2449                                 CS_Active);
2450                 if (!client)
2451                         continue;
2452
2453                 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2454                                 client->net_proto_version, cache_ptr);
2455
2456                 client->SentBlock(block_to_send.pos);
2457                 total_sending++;
2458         }
2459 }
2460
2461 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2462 {
2463         MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2464         if (!block)
2465                 return false;
2466
2467         ClientInterface::AutoLock clientlock(m_clients);
2468         RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2469         if (!client || client->isBlockSent(blockpos))
2470                 return false;
2471         SendBlockNoLock(peer_id, block, client->serialization_version,
2472                         client->net_proto_version);
2473
2474         return true;
2475 }
2476
2477 bool Server::addMediaFile(const std::string &filename,
2478         const std::string &filepath, std::string *filedata_to,
2479         std::string *digest_to)
2480 {
2481         // If name contains illegal characters, ignore the file
2482         if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2483                 infostream << "Server: ignoring illegal file name: \""
2484                                 << filename << "\"" << std::endl;
2485                 return false;
2486         }
2487         // If name is not in a supported format, ignore it
2488         const char *supported_ext[] = {
2489                 ".png", ".jpg", ".bmp", ".tga",
2490                 ".ogg",
2491                 ".x", ".b3d", ".obj",
2492                 // Custom translation file format
2493                 ".tr",
2494                 NULL
2495         };
2496         if (removeStringEnd(filename, supported_ext).empty()) {
2497                 infostream << "Server: ignoring unsupported file extension: \""
2498                                 << filename << "\"" << std::endl;
2499                 return false;
2500         }
2501         // Ok, attempt to load the file and add to cache
2502
2503         // Read data
2504         std::string filedata;
2505         if (!fs::ReadFile(filepath, filedata)) {
2506                 errorstream << "Server::addMediaFile(): Failed to open \""
2507                                         << filename << "\" for reading" << std::endl;
2508                 return false;
2509         }
2510
2511         if (filedata.empty()) {
2512                 errorstream << "Server::addMediaFile(): Empty file \""
2513                                 << filepath << "\"" << std::endl;
2514                 return false;
2515         }
2516
2517         SHA1 sha1;
2518         sha1.addBytes(filedata.c_str(), filedata.length());
2519
2520         unsigned char *digest = sha1.getDigest();
2521         std::string sha1_base64 = base64_encode(digest, 20);
2522         std::string sha1_hex = hex_encode((char*) digest, 20);
2523         if (digest_to)
2524                 *digest_to = std::string((char*) digest, 20);
2525         free(digest);
2526
2527         // Put in list
2528         m_media[filename] = MediaInfo(filepath, sha1_base64);
2529         verbosestream << "Server: " << sha1_hex << " is " << filename
2530                         << std::endl;
2531
2532         if (filedata_to)
2533                 *filedata_to = std::move(filedata);
2534         return true;
2535 }
2536
2537 void Server::fillMediaCache()
2538 {
2539         infostream << "Server: Calculating media file checksums" << std::endl;
2540
2541         // Collect all media file paths
2542         std::vector<std::string> paths;
2543
2544         // ordered in descending priority
2545         paths.push_back(getBuiltinLuaPath() + DIR_DELIM + "locale");
2546         fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2547         fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2548         m_modmgr->getModsMediaPaths(paths);
2549
2550         // Collect media file information from paths into cache
2551         for (const std::string &mediapath : paths) {
2552                 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2553                 for (const fs::DirListNode &dln : dirlist) {
2554                         if (dln.dir) // Ignore dirs (already in paths)
2555                                 continue;
2556
2557                         const std::string &filename = dln.name;
2558                         if (m_media.find(filename) != m_media.end()) // Do not override
2559                                 continue;
2560
2561                         std::string filepath = mediapath;
2562                         filepath.append(DIR_DELIM).append(filename);
2563                         addMediaFile(filename, filepath);
2564                 }
2565         }
2566
2567         infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2568 }
2569
2570 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2571 {
2572         // Make packet
2573         NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2574
2575         u16 media_sent = 0;
2576         std::string lang_suffix;
2577         lang_suffix.append(".").append(lang_code).append(".tr");
2578         for (const auto &i : m_media) {
2579                 if (i.second.no_announce)
2580                         continue;
2581                 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2582                         continue;
2583                 media_sent++;
2584         }
2585
2586         pkt << media_sent;
2587
2588         for (const auto &i : m_media) {
2589                 if (i.second.no_announce)
2590                         continue;
2591                 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2592                         continue;
2593                 pkt << i.first << i.second.sha1_digest;
2594         }
2595
2596         pkt << g_settings->get("remote_media");
2597         Send(&pkt);
2598
2599         verbosestream << "Server: Announcing files to id(" << peer_id
2600                 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2601 }
2602
2603 struct SendableMedia
2604 {
2605         std::string name;
2606         std::string path;
2607         std::string data;
2608
2609         SendableMedia(const std::string &name, const std::string &path,
2610                         std::string &&data):
2611                 name(name), path(path), data(std::move(data))
2612         {}
2613 };
2614
2615 void Server::sendRequestedMedia(session_t peer_id,
2616                 const std::vector<std::string> &tosend)
2617 {
2618         verbosestream<<"Server::sendRequestedMedia(): "
2619                         <<"Sending files to client"<<std::endl;
2620
2621         /* Read files */
2622
2623         // Put 5kB in one bunch (this is not accurate)
2624         u32 bytes_per_bunch = 5000;
2625
2626         std::vector< std::vector<SendableMedia> > file_bunches;
2627         file_bunches.emplace_back();
2628
2629         u32 file_size_bunch_total = 0;
2630
2631         for (const std::string &name : tosend) {
2632                 if (m_media.find(name) == m_media.end()) {
2633                         errorstream<<"Server::sendRequestedMedia(): Client asked for "
2634                                         <<"unknown file \""<<(name)<<"\""<<std::endl;
2635                         continue;
2636                 }
2637
2638                 const auto &m = m_media[name];
2639
2640                 // Read data
2641                 std::string data;
2642                 if (!fs::ReadFile(m.path, data)) {
2643                         errorstream << "Server::sendRequestedMedia(): Failed to read \""
2644                                         << name << "\"" << std::endl;
2645                         continue;
2646                 }
2647                 file_size_bunch_total += data.size();
2648
2649                 // Put in list
2650                 file_bunches.back().emplace_back(name, m.path, std::move(data));
2651
2652                 // Start next bunch if got enough data
2653                 if(file_size_bunch_total >= bytes_per_bunch) {
2654                         file_bunches.emplace_back();
2655                         file_size_bunch_total = 0;
2656                 }
2657
2658         }
2659
2660         /* Create and send packets */
2661
2662         u16 num_bunches = file_bunches.size();
2663         for (u16 i = 0; i < num_bunches; i++) {
2664                 /*
2665                         u16 command
2666                         u16 total number of texture bunches
2667                         u16 index of this bunch
2668                         u32 number of files in this bunch
2669                         for each file {
2670                                 u16 length of name
2671                                 string name
2672                                 u32 length of data
2673                                 data
2674                         }
2675                 */
2676
2677                 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2678                 pkt << num_bunches << i << (u32) file_bunches[i].size();
2679
2680                 for (const SendableMedia &j : file_bunches[i]) {
2681                         pkt << j.name;
2682                         pkt.putLongString(j.data);
2683                 }
2684
2685                 verbosestream << "Server::sendRequestedMedia(): bunch "
2686                                 << i << "/" << num_bunches
2687                                 << " files=" << file_bunches[i].size()
2688                                 << " size="  << pkt.getSize() << std::endl;
2689                 Send(&pkt);
2690         }
2691 }
2692
2693 void Server::stepPendingDynMediaCallbacks(float dtime)
2694 {
2695         MutexAutoLock lock(m_env_mutex);
2696
2697         for (auto it = m_pending_dyn_media.begin(); it != m_pending_dyn_media.end();) {
2698                 it->second.expiry_timer -= dtime;
2699                 bool del = it->second.waiting_players.empty() || it->second.expiry_timer < 0;
2700
2701                 if (!del) {
2702                         it++;
2703                         continue;
2704                 }
2705
2706                 const auto &name = it->second.filename;
2707                 if (!name.empty()) {
2708                         assert(m_media.count(name));
2709                         // if no_announce isn't set we're definitely deleting the wrong file!
2710                         sanity_check(m_media[name].no_announce);
2711
2712                         fs::DeleteSingleFileOrEmptyDirectory(m_media[name].path);
2713                         m_media.erase(name);
2714                 }
2715                 getScriptIface()->freeDynamicMediaCallback(it->first);
2716                 it = m_pending_dyn_media.erase(it);
2717         }
2718 }
2719
2720 void Server::SendMinimapModes(session_t peer_id,
2721                 std::vector<MinimapMode> &modes, size_t wanted_mode)
2722 {
2723         RemotePlayer *player = m_env->getPlayer(peer_id);
2724         assert(player);
2725         if (player->getPeerId() == PEER_ID_INEXISTENT)
2726                 return;
2727
2728         NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2729         pkt << (u16)modes.size() << (u16)wanted_mode;
2730
2731         for (auto &mode : modes)
2732                 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2733
2734         Send(&pkt);
2735 }
2736
2737 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2738 {
2739         NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2740         pkt << name;
2741
2742         if (!inventory) {
2743                 pkt << false; // Remove inventory
2744         } else {
2745                 pkt << true; // Update inventory
2746
2747                 // Serialization & NetworkPacket isn't a love story
2748                 std::ostringstream os(std::ios_base::binary);
2749                 inventory->serialize(os);
2750                 inventory->setModified(false);
2751
2752                 const std::string &os_str = os.str();
2753                 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2754                 pkt.putRawString(os_str);
2755         }
2756
2757         if (peer_id == PEER_ID_INEXISTENT)
2758                 m_clients.sendToAll(&pkt);
2759         else
2760                 Send(&pkt);
2761 }
2762
2763 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2764 {
2765         // Lookup player name, to filter detached inventories just after
2766         std::string peer_name;
2767         if (peer_id != PEER_ID_INEXISTENT) {
2768                 peer_name = getClient(peer_id, CS_Created)->getName();
2769         }
2770
2771         auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2772                 sendDetachedInventory(inv, name, peer_id);
2773         };
2774
2775         m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2776 }
2777
2778 /*
2779         Something random
2780 */
2781
2782 void Server::HandlePlayerDeath(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
2783 {
2784         infostream << "Server::DiePlayer(): Player "
2785                         << playersao->getPlayer()->getName()
2786                         << " dies" << std::endl;
2787
2788         playersao->clearParentAttachment();
2789
2790         // Trigger scripted stuff
2791         m_script->on_dieplayer(playersao, reason);
2792
2793         SendDeathscreen(playersao->getPeerID(), false, v3f(0,0,0));
2794 }
2795
2796 void Server::RespawnPlayer(session_t peer_id)
2797 {
2798         PlayerSAO *playersao = getPlayerSAO(peer_id);
2799         assert(playersao);
2800
2801         infostream << "Server::RespawnPlayer(): Player "
2802                         << playersao->getPlayer()->getName()
2803                         << " respawns" << std::endl;
2804
2805         const auto *prop = playersao->accessObjectProperties();
2806         playersao->setHP(prop->hp_max,
2807                         PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2808         playersao->setBreath(prop->breath_max);
2809
2810         bool repositioned = m_script->on_respawnplayer(playersao);
2811         if (!repositioned) {
2812                 // setPos will send the new position to client
2813                 playersao->setPos(findSpawnPos());
2814         }
2815 }
2816
2817
2818 void Server::DenySudoAccess(session_t peer_id)
2819 {
2820         NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2821         Send(&pkt);
2822 }
2823
2824
2825 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2826                 const std::string &custom_reason, bool reconnect)
2827 {
2828         SendAccessDenied(peer_id, reason, custom_reason, reconnect);
2829         m_clients.event(peer_id, CSE_SetDenied);
2830         DisconnectPeer(peer_id);
2831 }
2832
2833 void Server::DisconnectPeer(session_t peer_id)
2834 {
2835         m_modchannel_mgr->leaveAllChannels(peer_id);
2836         m_con->DisconnectPeer(peer_id);
2837 }
2838
2839 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2840 {
2841         if (!forSudoMode) {
2842                 RemoteClient* client = getClient(peer_id, CS_Invalid);
2843
2844                 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2845
2846                 // Right now, the auth mechs don't change between login and sudo mode.
2847                 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2848                 client->allowed_sudo_mechs = sudo_auth_mechs;
2849
2850                 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2851                                 << g_settings->getFloat("dedicated_server_step")
2852                                 << sudo_auth_mechs;
2853
2854                 Send(&resp_pkt);
2855                 m_clients.event(peer_id, CSE_AuthAccept);
2856         } else {
2857                 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2858
2859                 // We only support SRP right now
2860                 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2861
2862                 resp_pkt << sudo_auth_mechs;
2863                 Send(&resp_pkt);
2864                 m_clients.event(peer_id, CSE_SudoSuccess);
2865         }
2866 }
2867
2868 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2869 {
2870         std::wstring message;
2871         {
2872                 /*
2873                         Clear references to playing sounds
2874                 */
2875                 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2876                                  i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2877                         ServerPlayingSound &psound = i->second;
2878                         psound.clients.erase(peer_id);
2879                         if (psound.clients.empty())
2880                                 m_playing_sounds.erase(i++);
2881                         else
2882                                 ++i;
2883                 }
2884
2885                 // clear formspec info so the next client can't abuse the current state
2886                 m_formspec_state_data.erase(peer_id);
2887
2888                 RemotePlayer *player = m_env->getPlayer(peer_id);
2889
2890                 /* Run scripts and remove from environment */
2891                 if (player) {
2892                         PlayerSAO *playersao = player->getPlayerSAO();
2893                         assert(playersao);
2894
2895                         playersao->clearChildAttachments();
2896                         playersao->clearParentAttachment();
2897
2898                         // inform connected clients
2899                         const std::string &player_name = player->getName();
2900                         NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2901                         // (u16) 1 + std::string represents a vector serialization representation
2902                         notice << (u8) PLAYER_LIST_REMOVE  << (u16) 1 << player_name;
2903                         m_clients.sendToAll(&notice);
2904                         // run scripts
2905                         m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2906
2907                         playersao->disconnected();
2908                 }
2909
2910                 /*
2911                         Print out action
2912                 */
2913                 {
2914                         if (player && reason != CDR_DENY) {
2915                                 std::ostringstream os(std::ios_base::binary);
2916                                 std::vector<session_t> clients = m_clients.getClientIDs();
2917
2918                                 for (const session_t client_id : clients) {
2919                                         // Get player
2920                                         RemotePlayer *player = m_env->getPlayer(client_id);
2921                                         if (!player)
2922                                                 continue;
2923
2924                                         // Get name of player
2925                                         os << player->getName() << " ";
2926                                 }
2927
2928                                 std::string name = player->getName();
2929                                 actionstream << name << " "
2930                                                 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2931                                                 << " List of players: " << os.str() << std::endl;
2932                                 if (m_admin_chat)
2933                                         m_admin_chat->outgoing_queue.push_back(
2934                                                 new ChatEventNick(CET_NICK_REMOVE, name));
2935                         }
2936                 }
2937                 {
2938                         MutexAutoLock env_lock(m_env_mutex);
2939                         m_clients.DeleteClient(peer_id);
2940                 }
2941         }
2942
2943         // Send leave chat message to all remaining clients
2944         if (!message.empty()) {
2945                 SendChatMessage(PEER_ID_INEXISTENT,
2946                                 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2947         }
2948 }
2949
2950 void Server::UpdateCrafting(RemotePlayer *player)
2951 {
2952         InventoryList *clist = player->inventory.getList("craft");
2953         if (!clist || clist->getSize() == 0)
2954                 return;
2955
2956         if (!clist->checkModified())
2957                 return;
2958
2959         // Get a preview for crafting
2960         ItemStack preview;
2961         InventoryLocation loc;
2962         loc.setPlayer(player->getName());
2963         std::vector<ItemStack> output_replacements;
2964         getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2965         m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2966                         clist, loc);
2967
2968         InventoryList *plist = player->inventory.getList("craftpreview");
2969         if (plist && plist->getSize() >= 1) {
2970                 // Put the new preview in
2971                 plist->changeItem(0, preview);
2972         }
2973 }
2974
2975 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2976 {
2977         if (evt->type == CET_NICK_ADD) {
2978                 // The terminal informed us of its nick choice
2979                 m_admin_nick = ((ChatEventNick *)evt)->nick;
2980                 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2981                         errorstream << "You haven't set up an account." << std::endl
2982                                 << "Please log in using the client as '"
2983                                 << m_admin_nick << "' with a secure password." << std::endl
2984                                 << "Until then, you can't execute admin tasks via the console," << std::endl
2985                                 << "and everybody can claim the user account instead of you," << std::endl
2986                                 << "giving them full control over this server." << std::endl;
2987                 }
2988         } else {
2989                 assert(evt->type == CET_CHAT);
2990                 handleAdminChat((ChatEventChat *)evt);
2991         }
2992 }
2993
2994 std::wstring Server::handleChat(const std::string &name,
2995         std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2996 {
2997         // If something goes wrong, this player is to blame
2998         RollbackScopeActor rollback_scope(m_rollback,
2999                         std::string("player:") + name);
3000
3001         if (g_settings->getBool("strip_color_codes"))
3002                 wmessage = unescape_enriched(wmessage);
3003
3004         if (player) {
3005                 switch (player->canSendChatMessage()) {
3006                 case RPLAYER_CHATRESULT_FLOODING: {
3007                         std::wstringstream ws;
3008                         ws << L"You cannot send more messages. You are limited to "
3009                                         << g_settings->getFloat("chat_message_limit_per_10sec")
3010                                         << L" messages per 10 seconds.";
3011                         return ws.str();
3012                 }
3013                 case RPLAYER_CHATRESULT_KICK:
3014                         DenyAccess(player->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING,
3015                                 "You have been kicked due to message flooding.");
3016                         return L"";
3017                 case RPLAYER_CHATRESULT_OK:
3018                         break;
3019                 default:
3020                         FATAL_ERROR("Unhandled chat filtering result found.");
3021                 }
3022         }
3023
3024         if (m_max_chatmessage_length > 0
3025                         && wmessage.length() > m_max_chatmessage_length) {
3026                 return L"Your message exceed the maximum chat message limit set on the server. "
3027                                 L"It was refused. Send a shorter message";
3028         }
3029
3030         auto message = trim(wide_to_utf8(wmessage));
3031         if (message.empty())
3032                 return L"";
3033
3034         if (message.find_first_of("\n\r") != std::wstring::npos) {
3035                 return L"Newlines are not permitted in chat messages";
3036         }
3037
3038         // Run script hook, exit if script ate the chat message
3039         if (m_script->on_chat_message(name, message))
3040                 return L"";
3041
3042         // Line to send
3043         std::wstring line;
3044         // Whether to send line to the player that sent the message, or to all players
3045         bool broadcast_line = true;
3046
3047         if (check_shout_priv && !checkPriv(name, "shout")) {
3048                 line += L"-!- You don't have permission to shout.";
3049                 broadcast_line = false;
3050         } else {
3051                 /*
3052                         Workaround for fixing chat on Android. Lua doesn't handle
3053                         the Cyrillic alphabet and some characters on older Android devices
3054                 */
3055 #ifdef __ANDROID__
3056                 line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
3057 #else
3058                 line += utf8_to_wide(m_script->formatChatMessage(name,
3059                                 wide_to_utf8(wmessage)));
3060 #endif
3061         }
3062
3063         /*
3064                 Tell calling method to send the message to sender
3065         */
3066         if (!broadcast_line)
3067                 return line;
3068
3069         /*
3070                 Send the message to others
3071         */
3072         actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
3073
3074         ChatMessage chatmsg(line);
3075
3076         std::vector<session_t> clients = m_clients.getClientIDs();
3077         for (u16 cid : clients)
3078                 SendChatMessage(cid, chatmsg);
3079
3080         return L"";
3081 }
3082
3083 void Server::handleAdminChat(const ChatEventChat *evt)
3084 {
3085         std::string name = evt->nick;
3086         std::wstring wmessage = evt->evt_msg;
3087
3088         std::wstring answer = handleChat(name, wmessage);
3089
3090         // If asked to send answer to sender
3091         if (!answer.empty()) {
3092                 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3093         }
3094 }
3095
3096 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3097 {
3098         RemoteClient *client = getClientNoEx(peer_id,state_min);
3099         if(!client)
3100                 throw ClientNotFoundException("Client not found");
3101
3102         return client;
3103 }
3104 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3105 {
3106         return m_clients.getClientNoEx(peer_id, state_min);
3107 }
3108
3109 std::string Server::getPlayerName(session_t peer_id)
3110 {
3111         RemotePlayer *player = m_env->getPlayer(peer_id);
3112         if (!player)
3113                 return "[id="+itos(peer_id)+"]";
3114         return player->getName();
3115 }
3116
3117 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3118 {
3119         RemotePlayer *player = m_env->getPlayer(peer_id);
3120         if (!player)
3121                 return NULL;
3122         return player->getPlayerSAO();
3123 }
3124
3125 std::string Server::getStatusString()
3126 {
3127         std::ostringstream os(std::ios_base::binary);
3128         os << "# Server: ";
3129         // Version
3130         os << "version: " << g_version_string;
3131         // Game
3132         os << " | game: " << (m_gamespec.title.empty() ? m_gamespec.id : m_gamespec.title);
3133         // Uptime
3134         os << " | uptime: " << duration_to_string((int) m_uptime_counter->get());
3135         // Max lag estimate
3136         os << " | max lag: " << std::setprecision(3);
3137         os << (m_env ? m_env->getMaxLagEstimate() : 0) << "s";
3138
3139         // Information about clients
3140         bool first = true;
3141         os << " | clients: ";
3142         if (m_env) {
3143                 std::vector<session_t> clients = m_clients.getClientIDs();
3144                 for (session_t client_id : clients) {
3145                         RemotePlayer *player = m_env->getPlayer(client_id);
3146
3147                         // Get name of player
3148                         const char *name = player ? player->getName() : "<unknown>";
3149
3150                         // Add name to information string
3151                         if (!first)
3152                                 os << ", ";
3153                         else
3154                                 first = false;
3155                         os << name;
3156                 }
3157         }
3158
3159         if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3160                 os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
3161
3162         if (!g_settings->get("motd").empty())
3163                 os << std::endl << "# Server: " << g_settings->get("motd");
3164
3165         return os.str();
3166 }
3167
3168 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3169 {
3170         std::set<std::string> privs;
3171         m_script->getAuth(name, NULL, &privs);
3172         return privs;
3173 }
3174
3175 bool Server::checkPriv(const std::string &name, const std::string &priv)
3176 {
3177         std::set<std::string> privs = getPlayerEffectivePrivs(name);
3178         return (privs.count(priv) != 0);
3179 }
3180
3181 void Server::reportPrivsModified(const std::string &name)
3182 {
3183         if (name.empty()) {
3184                 std::vector<session_t> clients = m_clients.getClientIDs();
3185                 for (const session_t client_id : clients) {
3186                         RemotePlayer *player = m_env->getPlayer(client_id);
3187                         reportPrivsModified(player->getName());
3188                 }
3189         } else {
3190                 RemotePlayer *player = m_env->getPlayer(name.c_str());
3191                 if (!player)
3192                         return;
3193                 SendPlayerPrivileges(player->getPeerId());
3194                 PlayerSAO *sao = player->getPlayerSAO();
3195                 if(!sao)
3196                         return;
3197                 sao->updatePrivileges(
3198                                 getPlayerEffectivePrivs(name),
3199                                 isSingleplayer());
3200         }
3201 }
3202
3203 void Server::reportInventoryFormspecModified(const std::string &name)
3204 {
3205         RemotePlayer *player = m_env->getPlayer(name.c_str());
3206         if (!player)
3207                 return;
3208         SendPlayerInventoryFormspec(player->getPeerId());
3209 }
3210
3211 void Server::reportFormspecPrependModified(const std::string &name)
3212 {
3213         RemotePlayer *player = m_env->getPlayer(name.c_str());
3214         if (!player)
3215                 return;
3216         SendPlayerFormspecPrepend(player->getPeerId());
3217 }
3218
3219 void Server::setIpBanned(const std::string &ip, const std::string &name)
3220 {
3221         m_banmanager->add(ip, name);
3222 }
3223
3224 void Server::unsetIpBanned(const std::string &ip_or_name)
3225 {
3226         m_banmanager->remove(ip_or_name);
3227 }
3228
3229 std::string Server::getBanDescription(const std::string &ip_or_name)
3230 {
3231         return m_banmanager->getBanDescription(ip_or_name);
3232 }
3233
3234 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3235 {
3236         // m_env will be NULL if the server is initializing
3237         if (!m_env)
3238                 return;
3239
3240         if (m_admin_nick == name && !m_admin_nick.empty()) {
3241                 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3242         }
3243
3244         RemotePlayer *player = m_env->getPlayer(name);
3245         if (!player) {
3246                 return;
3247         }
3248
3249         if (player->getPeerId() == PEER_ID_INEXISTENT)
3250                 return;
3251
3252         SendChatMessage(player->getPeerId(), ChatMessage(msg));
3253 }
3254
3255 bool Server::showFormspec(const char *playername, const std::string &formspec,
3256         const std::string &formname)
3257 {
3258         // m_env will be NULL if the server is initializing
3259         if (!m_env)
3260                 return false;
3261
3262         RemotePlayer *player = m_env->getPlayer(playername);
3263         if (!player)
3264                 return false;
3265
3266         SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3267         return true;
3268 }
3269
3270 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3271 {
3272         if (!player)
3273                 return -1;
3274
3275         u32 id = player->addHud(form);
3276
3277         SendHUDAdd(player->getPeerId(), id, form);
3278
3279         return id;
3280 }
3281
3282 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3283         if (!player)
3284                 return false;
3285
3286         HudElement* todel = player->removeHud(id);
3287
3288         if (!todel)
3289                 return false;
3290
3291         delete todel;
3292
3293         SendHUDRemove(player->getPeerId(), id);
3294         return true;
3295 }
3296
3297 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3298 {
3299         if (!player)
3300                 return false;
3301
3302         SendHUDChange(player->getPeerId(), id, stat, data);
3303         return true;
3304 }
3305
3306 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3307 {
3308         if (!player)
3309                 return false;
3310
3311         u32 new_hud_flags = (player->hud_flags & ~mask) | flags;
3312         if (new_hud_flags == player->hud_flags) // no change
3313                 return true;
3314
3315         SendHUDSetFlags(player->getPeerId(), flags, mask);
3316         player->hud_flags = new_hud_flags;
3317
3318         PlayerSAO* playersao = player->getPlayerSAO();
3319
3320         if (!playersao)
3321                 return false;
3322
3323         m_script->player_event(playersao, "hud_changed");
3324         return true;
3325 }
3326
3327 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3328 {
3329         if (!player)
3330                 return false;
3331
3332         if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3333                 return false;
3334
3335         player->setHotbarItemcount(hotbar_itemcount);
3336         std::ostringstream os(std::ios::binary);
3337         writeS32(os, hotbar_itemcount);
3338         SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3339         return true;
3340 }
3341
3342 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3343 {
3344         if (!player)
3345                 return;
3346
3347         player->setHotbarImage(name);
3348         SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3349 }
3350
3351 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3352 {
3353         if (!player)
3354                 return;
3355
3356         player->setHotbarSelectedImage(name);
3357         SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3358 }
3359
3360 Address Server::getPeerAddress(session_t peer_id)
3361 {
3362         // Note that this is only set after Init was received in Server::handleCommand_Init
3363         return getClient(peer_id, CS_Invalid)->getAddress();
3364 }
3365
3366 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3367                 v2s32 animation_frames[4], f32 frame_speed)
3368 {
3369         sanity_check(player);
3370         player->setLocalAnimations(animation_frames, frame_speed);
3371         SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3372 }
3373
3374 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3375 {
3376         sanity_check(player);
3377         player->eye_offset_first = first;
3378         player->eye_offset_third = third;
3379         SendEyeOffset(player->getPeerId(), first, third);
3380 }
3381
3382 void Server::setSky(RemotePlayer *player, const SkyboxParams &params)
3383 {
3384         sanity_check(player);
3385         player->setSky(params);
3386         SendSetSky(player->getPeerId(), params);
3387 }
3388
3389 void Server::setSun(RemotePlayer *player, const SunParams &params)
3390 {
3391         sanity_check(player);
3392         player->setSun(params);
3393         SendSetSun(player->getPeerId(), params);
3394 }
3395
3396 void Server::setMoon(RemotePlayer *player, const MoonParams &params)
3397 {
3398         sanity_check(player);
3399         player->setMoon(params);
3400         SendSetMoon(player->getPeerId(), params);
3401 }
3402
3403 void Server::setStars(RemotePlayer *player, const StarParams &params)
3404 {
3405         sanity_check(player);
3406         player->setStars(params);
3407         SendSetStars(player->getPeerId(), params);
3408 }
3409
3410 void Server::setClouds(RemotePlayer *player, const CloudParams &params)
3411 {
3412         sanity_check(player);
3413         player->setCloudParams(params);
3414         SendCloudParams(player->getPeerId(), params);
3415 }
3416
3417 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3418         float ratio)
3419 {
3420         sanity_check(player);
3421         player->overrideDayNightRatio(do_override, ratio);
3422         SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3423 }
3424
3425 void Server::setLighting(RemotePlayer *player, const Lighting &lighting)
3426 {
3427         sanity_check(player);
3428         player->setLighting(lighting);
3429         SendSetLighting(player->getPeerId(), lighting);
3430 }
3431
3432 void Server::notifyPlayers(const std::wstring &msg)
3433 {
3434         SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3435 }
3436
3437 void Server::spawnParticle(const std::string &playername,
3438         const ParticleParameters &p)
3439 {
3440         // m_env will be NULL if the server is initializing
3441         if (!m_env)
3442                 return;
3443
3444         session_t peer_id = PEER_ID_INEXISTENT;
3445         u16 proto_ver = 0;
3446         if (!playername.empty()) {
3447                 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3448                 if (!player)
3449                         return;
3450                 peer_id = player->getPeerId();
3451                 proto_ver = player->protocol_version;
3452         }
3453
3454         SendSpawnParticle(peer_id, proto_ver, p);
3455 }
3456
3457 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3458         ServerActiveObject *attached, const std::string &playername)
3459 {
3460         // m_env will be NULL if the server is initializing
3461         if (!m_env)
3462                 return -1;
3463
3464         session_t peer_id = PEER_ID_INEXISTENT;
3465         u16 proto_ver = 0;
3466         if (!playername.empty()) {
3467                 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3468                 if (!player)
3469                         return -1;
3470                 peer_id = player->getPeerId();
3471                 proto_ver = player->protocol_version;
3472         }
3473
3474         u16 attached_id = attached ? attached->getId() : 0;
3475
3476         u32 id;
3477         if (attached_id == 0)
3478                 id = m_env->addParticleSpawner(p.time);
3479         else
3480                 id = m_env->addParticleSpawner(p.time, attached_id);
3481
3482         SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3483         return id;
3484 }
3485
3486 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3487 {
3488         // m_env will be NULL if the server is initializing
3489         if (!m_env)
3490                 throw ServerError("Can't delete particle spawners during initialisation!");
3491
3492         session_t peer_id = PEER_ID_INEXISTENT;
3493         if (!playername.empty()) {
3494                 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3495                 if (!player)
3496                         return;
3497                 peer_id = player->getPeerId();
3498         }
3499
3500         m_env->deleteParticleSpawner(id);
3501         SendDeleteParticleSpawner(peer_id, id);
3502 }
3503
3504 bool Server::dynamicAddMedia(std::string filepath,
3505         const u32 token, const std::string &to_player, bool ephemeral)
3506 {
3507         std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3508         auto it = m_media.find(filename);
3509         if (it != m_media.end()) {
3510                 // Allow the same path to be "added" again in certain conditions
3511                 if (ephemeral || it->second.path != filepath) {
3512                         errorstream << "Server::dynamicAddMedia(): file \"" << filename
3513                                 << "\" already exists in media cache" << std::endl;
3514                         return false;
3515                 }
3516         }
3517
3518         // Load the file and add it to our media cache
3519         std::string filedata, raw_hash;
3520         bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3521         if (!ok)
3522                 return false;
3523
3524         if (ephemeral) {
3525                 // Create a copy of the file and swap out the path, this removes the
3526                 // requirement that mods keep the file accessible at the original path.
3527                 filepath = fs::CreateTempFile();
3528                 bool ok = ([&] () -> bool {
3529                         if (filepath.empty())
3530                                 return false;
3531                         std::ofstream os(filepath.c_str(), std::ios::binary);
3532                         if (!os.good())
3533                                 return false;
3534                         os << filedata;
3535                         os.close();
3536                         return !os.fail();
3537                 })();
3538                 if (!ok) {
3539                         errorstream << "Server: failed to create a copy of media file "
3540                                 << "\"" << filename << "\"" << std::endl;
3541                         m_media.erase(filename);
3542                         return false;
3543                 }
3544                 verbosestream << "Server: \"" << filename << "\" temporarily copied to "
3545                         << filepath << std::endl;
3546
3547                 m_media[filename].path = filepath;
3548                 m_media[filename].no_announce = true;
3549                 // stepPendingDynMediaCallbacks will clean this up later.
3550         } else if (!to_player.empty()) {
3551                 m_media[filename].no_announce = true;
3552         }
3553
3554         // Push file to existing clients
3555         NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3556         pkt << raw_hash << filename << (bool)ephemeral;
3557
3558         NetworkPacket legacy_pkt = pkt;
3559
3560         // Newer clients get asked to fetch the file (asynchronous)
3561         pkt << token;
3562         // Older clients have an awful hack that just throws the data at them
3563         legacy_pkt.putLongString(filedata);
3564
3565         std::unordered_set<session_t> delivered, waiting;
3566         {
3567                 ClientInterface::AutoLock clientlock(m_clients);
3568                 for (auto &pair : m_clients.getClientList()) {
3569                         if (pair.second->getState() == CS_DefinitionsSent && !ephemeral) {
3570                                 /*
3571                                         If a client is in the DefinitionsSent state it is too late to
3572                                         transfer the file via sendMediaAnnouncement() but at the same
3573                                         time the client cannot accept a media push yet.
3574                                         Short of artificially delaying the joining process there is no
3575                                         way for the server to resolve this so we (currently) opt not to.
3576                                 */
3577                                 warningstream << "The media \"" << filename << "\" (dynamic) could "
3578                                         "not be delivered to " << pair.second->getName()
3579                                         << " due to a race condition." << std::endl;
3580                                 continue;
3581                         }
3582                         if (pair.second->getState() < CS_Active)
3583                                 continue;
3584
3585                         const auto proto_ver = pair.second->net_proto_version;
3586                         if (proto_ver < 39)
3587                                 continue;
3588
3589                         const session_t peer_id = pair.second->peer_id;
3590                         if (!to_player.empty() && getPlayerName(peer_id) != to_player)
3591                                 continue;
3592
3593                         if (proto_ver < 40) {
3594                                 delivered.emplace(peer_id);
3595                                 /*
3596                                         The network layer only guarantees ordered delivery inside a channel.
3597                                         Since the very next packet could be one that uses the media, we have
3598                                         to push the media over ALL channels to ensure it is processed before
3599                                         it is used. In practice this means channels 1 and 0.
3600                                 */
3601                                 m_clients.send(peer_id, 1, &legacy_pkt, true);
3602                                 m_clients.send(peer_id, 0, &legacy_pkt, true);
3603                         } else {
3604                                 waiting.emplace(peer_id);
3605                                 Send(peer_id, &pkt);
3606                         }
3607                 }
3608         }
3609
3610         // Run callback for players that already had the file delivered (legacy-only)
3611         for (session_t peer_id : delivered) {
3612                 if (auto player = m_env->getPlayer(peer_id))
3613                         getScriptIface()->on_dynamic_media_added(token, player->getName());
3614         }
3615
3616         // Save all others in our pending state
3617         auto &state = m_pending_dyn_media[token];
3618         state.waiting_players = std::move(waiting);
3619         // regardless of success throw away the callback after a while
3620         state.expiry_timer = 60.0f;
3621         if (ephemeral)
3622                 state.filename = filename;
3623
3624         return true;
3625 }
3626
3627 // actions: time-reversed list
3628 // Return value: success/failure
3629 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3630                 std::list<std::string> *log)
3631 {
3632         infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3633         ServerMap *map = (ServerMap*)(&m_env->getMap());
3634
3635         // Fail if no actions to handle
3636         if (actions.empty()) {
3637                 assert(log);
3638                 log->push_back("Nothing to do.");
3639                 return false;
3640         }
3641
3642         int num_tried = 0;
3643         int num_failed = 0;
3644
3645         for (const RollbackAction &action : actions) {
3646                 num_tried++;
3647                 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3648                 if(!success){
3649                         num_failed++;
3650                         std::ostringstream os;
3651                         os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3652                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3653                         if (log)
3654                                 log->push_back(os.str());
3655                 }else{
3656                         std::ostringstream os;
3657                         os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3658                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3659                         if (log)
3660                                 log->push_back(os.str());
3661                 }
3662         }
3663
3664         infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3665                         <<" failed"<<std::endl;
3666
3667         // Call it done if less than half failed
3668         return num_failed <= num_tried/2;
3669 }
3670
3671 // IGameDef interface
3672 // Under envlock
3673 IItemDefManager *Server::getItemDefManager()
3674 {
3675         return m_itemdef;
3676 }
3677
3678 const NodeDefManager *Server::getNodeDefManager()
3679 {
3680         return m_nodedef;
3681 }
3682
3683 ICraftDefManager *Server::getCraftDefManager()
3684 {
3685         return m_craftdef;
3686 }
3687
3688 u16 Server::allocateUnknownNodeId(const std::string &name)
3689 {
3690         return m_nodedef->allocateDummy(name);
3691 }
3692
3693 IWritableItemDefManager *Server::getWritableItemDefManager()
3694 {
3695         return m_itemdef;
3696 }
3697
3698 NodeDefManager *Server::getWritableNodeDefManager()
3699 {
3700         return m_nodedef;
3701 }
3702
3703 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3704 {
3705         return m_craftdef;
3706 }
3707
3708 const std::vector<ModSpec> & Server::getMods() const
3709 {
3710         return m_modmgr->getMods();
3711 }
3712
3713 const ModSpec *Server::getModSpec(const std::string &modname) const
3714 {
3715         return m_modmgr->getModSpec(modname);
3716 }
3717
3718 std::string Server::getBuiltinLuaPath()
3719 {
3720         return porting::path_share + DIR_DELIM + "builtin";
3721 }
3722
3723 v3f Server::findSpawnPos()
3724 {
3725         ServerMap &map = m_env->getServerMap();
3726         v3f nodeposf;
3727         if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3728                 return nodeposf * BS;
3729
3730         bool is_good = false;
3731         // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3732         s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3733
3734         // Try to find a good place a few times
3735         for (s32 i = 0; i < 4000 && !is_good; i++) {
3736                 s32 range = MYMIN(1 + i, range_max);
3737                 // We're going to try to throw the player to this position
3738                 v2s16 nodepos2d = v2s16(
3739                         -range + myrand_range(0, range*2),
3740                         -range + myrand_range(0, range*2));
3741                 // Get spawn level at point
3742                 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3743                 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3744                 // signify an unsuitable spawn position, or if outside limits.
3745                 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3746                                 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3747                         continue;
3748
3749                 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3750                 // Consecutive empty nodes
3751                 s32 air_count = 0;
3752
3753                 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3754                 // avoid obstructions in already-generated mapblocks.
3755                 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3756                 // no obstructions, but mapgen decorations are generated after spawn so
3757                 // the player may end up inside one.
3758                 for (s32 i = 0; i < 8; i++) {
3759                         v3s16 blockpos = getNodeBlockPos(nodepos);
3760                         map.emergeBlock(blockpos, true);
3761                         content_t c = map.getNode(nodepos).getContent();
3762
3763                         // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3764                         // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3765                         if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3766                                 air_count++;
3767                                 if (air_count >= 2) {
3768                                         // Spawn in lower empty node
3769                                         nodepos.Y--;
3770                                         nodeposf = intToFloat(nodepos, BS);
3771                                         // Don't spawn the player outside map boundaries
3772                                         if (objectpos_over_limit(nodeposf))
3773                                                 // Exit this loop, positions above are probably over limit
3774                                                 break;
3775
3776                                         // Good position found, cause an exit from main loop
3777                                         is_good = true;
3778                                         break;
3779                                 }
3780                         } else {
3781                                 air_count = 0;
3782                         }
3783                         nodepos.Y++;
3784                 }
3785         }
3786
3787         if (is_good)
3788                 return nodeposf;
3789
3790         // No suitable spawn point found, return fallback 0,0,0
3791         return v3f(0.0f, 0.0f, 0.0f);
3792 }
3793
3794 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3795 {
3796         if (delay == 0.0f) {
3797         // No delay, shutdown immediately
3798                 m_shutdown_state.is_requested = true;
3799                 // only print to the infostream, a chat message saying
3800                 // "Server Shutting Down" is sent when the server destructs.
3801                 infostream << "*** Immediate Server shutdown requested." << std::endl;
3802         } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3803                 // Negative delay, cancel shutdown if requested
3804                 m_shutdown_state.reset();
3805                 std::wstringstream ws;
3806
3807                 ws << L"*** Server shutdown canceled.";
3808
3809                 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3810                 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3811                 // m_shutdown_* are already handled, skip.
3812                 return;
3813         } else if (delay > 0.0f) {
3814         // Positive delay, tell the clients when the server will shut down
3815                 std::wstringstream ws;
3816
3817                 ws << L"*** Server shutting down in "
3818                                 << duration_to_string(myround(delay)).c_str()
3819                                 << ".";
3820
3821                 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3822                 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3823         }
3824
3825         m_shutdown_state.trigger(delay, msg, reconnect);
3826 }
3827
3828 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3829 {
3830         /*
3831                 Try to get an existing player
3832         */
3833         RemotePlayer *player = m_env->getPlayer(name);
3834
3835         // If player is already connected, cancel
3836         if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3837                 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3838                 return NULL;
3839         }
3840
3841         /*
3842                 If player with the wanted peer_id already exists, cancel.
3843         */
3844         if (m_env->getPlayer(peer_id)) {
3845                 infostream<<"emergePlayer(): Player with wrong name but same"
3846                                 " peer_id already exists"<<std::endl;
3847                 return NULL;
3848         }
3849
3850         if (!player) {
3851                 player = new RemotePlayer(name, idef());
3852         }
3853
3854         bool newplayer = false;
3855
3856         // Load player
3857         PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3858
3859         // Complete init with server parts
3860         playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3861         player->protocol_version = proto_version;
3862
3863         /* Run scripts */
3864         if (newplayer) {
3865                 m_script->on_newplayer(playersao);
3866         }
3867
3868         return playersao;
3869 }
3870
3871 void dedicated_server_loop(Server &server, bool &kill)
3872 {
3873         verbosestream<<"dedicated_server_loop()"<<std::endl;
3874
3875         IntervalLimiter m_profiler_interval;
3876
3877         static thread_local const float steplen =
3878                         g_settings->getFloat("dedicated_server_step");
3879         static thread_local const float profiler_print_interval =
3880                         g_settings->getFloat("profiler_print_interval");
3881
3882         /*
3883          * The dedicated server loop only does time-keeping (in Server::step) and
3884          * provides a way to main.cpp to kill the server externally (bool &kill).
3885          */
3886
3887         for(;;) {
3888                 // This is kind of a hack but can be done like this
3889                 // because server.step() is very light
3890                 sleep_ms((int)(steplen*1000.0));
3891                 server.step(steplen);
3892
3893                 if (server.isShutdownRequested() || kill)
3894                         break;
3895
3896                 /*
3897                         Profiler
3898                 */
3899                 if (profiler_print_interval != 0) {
3900                         if(m_profiler_interval.step(steplen, profiler_print_interval))
3901                         {
3902                                 infostream<<"Profiler:"<<std::endl;
3903                                 g_profiler->print(infostream);
3904                                 g_profiler->clear();
3905                         }
3906                 }
3907         }
3908
3909         infostream << "Dedicated server quitting" << std::endl;
3910 #if USE_CURL
3911         if (g_settings->getBool("server_announce"))
3912                 ServerList::sendAnnounce(ServerList::AA_DELETE,
3913                         server.m_bind_addr.getPort());
3914 #endif
3915 }
3916
3917 /*
3918  * Mod channels
3919  */
3920
3921
3922 bool Server::joinModChannel(const std::string &channel)
3923 {
3924         return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3925                         m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3926 }
3927
3928 bool Server::leaveModChannel(const std::string &channel)
3929 {
3930         return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3931 }
3932
3933 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3934 {
3935         if (!m_modchannel_mgr->canWriteOnChannel(channel))
3936                 return false;
3937
3938         broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3939         return true;
3940 }
3941
3942 ModChannel* Server::getModChannel(const std::string &channel)
3943 {
3944         return m_modchannel_mgr->getModChannel(channel);
3945 }
3946
3947 void Server::broadcastModChannelMessage(const std::string &channel,
3948                 const std::string &message, session_t from_peer)
3949 {
3950         const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3951         if (peers.empty())
3952                 return;
3953
3954         if (message.size() > STRING_MAX_LEN) {
3955                 warningstream << "ModChannel message too long, dropping before sending "
3956                                 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3957                                 << channel << ")" << std::endl;
3958                 return;
3959         }
3960
3961         std::string sender;
3962         if (from_peer != PEER_ID_SERVER) {
3963                 sender = getPlayerName(from_peer);
3964         }
3965
3966         NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3967                         2 + channel.size() + 2 + sender.size() + 2 + message.size());
3968         resp_pkt << channel << sender << message;
3969         for (session_t peer_id : peers) {
3970                 // Ignore sender
3971                 if (peer_id == from_peer)
3972                         continue;
3973
3974                 Send(peer_id, &resp_pkt);
3975         }
3976
3977         if (from_peer != PEER_ID_SERVER) {
3978                 m_script->on_modchannel_message(channel, sender, message);
3979         }
3980 }
3981
3982 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3983 {
3984         if (lang_code.empty())
3985                 return nullptr;
3986
3987         auto it = server_translations.find(lang_code);
3988         if (it != server_translations.end())
3989                 return &it->second; // Already loaded
3990
3991         // [] will create an entry
3992         auto *translations = &server_translations[lang_code];
3993
3994         std::string suffix = "." + lang_code + ".tr";
3995         for (const auto &i : m_media) {
3996                 if (str_ends_with(i.first, suffix)) {
3997                         std::string data;
3998                         if (fs::ReadFile(i.second.path, data)) {
3999                                 translations->loadTranslation(data);
4000                         }
4001                 }
4002         }
4003
4004         return translations;
4005 }
4006
4007 ModStorageDatabase *Server::openModStorageDatabase(const std::string &world_path)
4008 {
4009         std::string world_mt_path = world_path + DIR_DELIM + "world.mt";
4010         Settings world_mt;
4011         if (!world_mt.readConfigFile(world_mt_path.c_str()))
4012                 throw BaseException("Cannot read world.mt!");
4013
4014         std::string backend = world_mt.exists("mod_storage_backend") ?
4015                 world_mt.get("mod_storage_backend") : "files";
4016         if (backend == "files")
4017                 warningstream << "/!\\ You are using the old mod storage files backend. "
4018                         << "This backend is deprecated and may be removed in a future release /!\\"
4019                         << std::endl << "Switching to SQLite3 is advised, "
4020                         << "please read http://wiki.minetest.net/Database_backends." << std::endl;
4021
4022         return openModStorageDatabase(backend, world_path, world_mt);
4023 }
4024
4025 ModStorageDatabase *Server::openModStorageDatabase(const std::string &backend,
4026                 const std::string &world_path, const Settings &world_mt)
4027 {
4028         if (backend == "sqlite3")
4029                 return new ModStorageDatabaseSQLite3(world_path);
4030
4031 #if USE_POSTGRESQL
4032         if (backend == "postgresql") {
4033                 std::string connect_string;
4034                 world_mt.getNoEx("pgsql_mod_storage_connection", connect_string);
4035                 return new ModStorageDatabasePostgreSQL(connect_string);
4036         }
4037 #endif // USE_POSTGRESQL
4038
4039         if (backend == "files")
4040                 return new ModStorageDatabaseFiles(world_path);
4041
4042         if (backend == "dummy")
4043                 return new Database_Dummy();
4044
4045         throw BaseException("Mod storage database backend " + backend + " not supported");
4046 }
4047
4048 bool Server::migrateModStorageDatabase(const GameParams &game_params, const Settings &cmd_args)
4049 {
4050         std::string migrate_to = cmd_args.get("migrate-mod-storage");
4051         Settings world_mt;
4052         std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt";
4053         if (!world_mt.readConfigFile(world_mt_path.c_str())) {
4054                 errorstream << "Cannot read world.mt!" << std::endl;
4055                 return false;
4056         }
4057
4058         std::string backend = world_mt.exists("mod_storage_backend") ?
4059                 world_mt.get("mod_storage_backend") : "files";
4060         if (backend == migrate_to) {
4061                 errorstream << "Cannot migrate: new backend is same"
4062                         << " as the old one" << std::endl;
4063                 return false;
4064         }
4065
4066         ModStorageDatabase *srcdb = nullptr;
4067         ModStorageDatabase *dstdb = nullptr;
4068
4069         bool succeeded = false;
4070
4071         try {
4072                 srcdb = Server::openModStorageDatabase(backend, game_params.world_path, world_mt);
4073                 dstdb = Server::openModStorageDatabase(migrate_to, game_params.world_path, world_mt);
4074
4075                 dstdb->beginSave();
4076
4077                 std::vector<std::string> mod_list;
4078                 srcdb->listMods(&mod_list);
4079                 for (const std::string &modname : mod_list) {
4080                         StringMap meta;
4081                         srcdb->getModEntries(modname, &meta);
4082                         for (const auto &pair : meta) {
4083                                 dstdb->setModEntry(modname, pair.first, pair.second);
4084                         }
4085                 }
4086
4087                 dstdb->endSave();
4088
4089                 succeeded = true;
4090
4091                 actionstream << "Successfully migrated the metadata of "
4092                         << mod_list.size() << " mods" << std::endl;
4093                 world_mt.set("mod_storage_backend", migrate_to);
4094                 if (!world_mt.updateConfigFile(world_mt_path.c_str()))
4095                         errorstream << "Failed to update world.mt!" << std::endl;
4096                 else
4097                         actionstream << "world.mt updated" << std::endl;
4098
4099         } catch (BaseException &e) {
4100                 errorstream << "An error occurred during migration: " << e.what() << std::endl;
4101         }
4102
4103         delete srcdb;
4104         delete dstdb;
4105
4106         if (succeeded && backend == "files") {
4107                 // Back up files
4108                 const std::string storage_path = game_params.world_path + DIR_DELIM + "mod_storage";
4109                 const std::string backup_path = game_params.world_path + DIR_DELIM + "mod_storage.bak";
4110                 if (!fs::Rename(storage_path, backup_path))
4111                         warningstream << "After migration, " << storage_path
4112                                 << " could not be renamed to " << backup_path << std::endl;
4113         }
4114
4115         return succeeded;
4116 }