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