]> git.lizzy.rs Git - dragonfireclient.git/blob - src/server.cpp
Add API function to invoke player respawn
[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         const auto *prop = playersao->accessObjectProperties();
2788         playersao->setHP(prop->hp_max,
2789                         PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2790         playersao->setBreath(prop->breath_max);
2791
2792         bool repositioned = m_script->on_respawnplayer(playersao);
2793         if (!repositioned) {
2794                 // setPos will send the new position to client
2795                 playersao->setPos(findSpawnPos());
2796         }
2797 }
2798
2799
2800 void Server::DenySudoAccess(session_t peer_id)
2801 {
2802         NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2803         Send(&pkt);
2804 }
2805
2806
2807 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2808                 const std::string &custom_reason, bool reconnect)
2809 {
2810         SendAccessDenied(peer_id, reason, custom_reason, reconnect);
2811         m_clients.event(peer_id, CSE_SetDenied);
2812         DisconnectPeer(peer_id);
2813 }
2814
2815 void Server::DisconnectPeer(session_t peer_id)
2816 {
2817         m_modchannel_mgr->leaveAllChannels(peer_id);
2818         m_con->DisconnectPeer(peer_id);
2819 }
2820
2821 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2822 {
2823         if (!forSudoMode) {
2824                 RemoteClient* client = getClient(peer_id, CS_Invalid);
2825
2826                 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2827
2828                 // Right now, the auth mechs don't change between login and sudo mode.
2829                 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2830                 client->allowed_sudo_mechs = sudo_auth_mechs;
2831
2832                 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2833                                 << g_settings->getFloat("dedicated_server_step")
2834                                 << sudo_auth_mechs;
2835
2836                 Send(&resp_pkt);
2837                 m_clients.event(peer_id, CSE_AuthAccept);
2838         } else {
2839                 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2840
2841                 // We only support SRP right now
2842                 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2843
2844                 resp_pkt << sudo_auth_mechs;
2845                 Send(&resp_pkt);
2846                 m_clients.event(peer_id, CSE_SudoSuccess);
2847         }
2848 }
2849
2850 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2851 {
2852         std::wstring message;
2853         {
2854                 /*
2855                         Clear references to playing sounds
2856                 */
2857                 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2858                                  i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2859                         ServerPlayingSound &psound = i->second;
2860                         psound.clients.erase(peer_id);
2861                         if (psound.clients.empty())
2862                                 m_playing_sounds.erase(i++);
2863                         else
2864                                 ++i;
2865                 }
2866
2867                 // clear formspec info so the next client can't abuse the current state
2868                 m_formspec_state_data.erase(peer_id);
2869
2870                 RemotePlayer *player = m_env->getPlayer(peer_id);
2871
2872                 /* Run scripts and remove from environment */
2873                 if (player) {
2874                         PlayerSAO *playersao = player->getPlayerSAO();
2875                         assert(playersao);
2876
2877                         playersao->clearChildAttachments();
2878                         playersao->clearParentAttachment();
2879
2880                         // inform connected clients
2881                         const std::string &player_name = player->getName();
2882                         NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2883                         // (u16) 1 + std::string represents a vector serialization representation
2884                         notice << (u8) PLAYER_LIST_REMOVE  << (u16) 1 << player_name;
2885                         m_clients.sendToAll(&notice);
2886                         // run scripts
2887                         m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2888
2889                         playersao->disconnected();
2890                 }
2891
2892                 /*
2893                         Print out action
2894                 */
2895                 {
2896                         if (player && reason != CDR_DENY) {
2897                                 std::ostringstream os(std::ios_base::binary);
2898                                 std::vector<session_t> clients = m_clients.getClientIDs();
2899
2900                                 for (const session_t client_id : clients) {
2901                                         // Get player
2902                                         RemotePlayer *player = m_env->getPlayer(client_id);
2903                                         if (!player)
2904                                                 continue;
2905
2906                                         // Get name of player
2907                                         os << player->getName() << " ";
2908                                 }
2909
2910                                 std::string name = player->getName();
2911                                 actionstream << name << " "
2912                                                 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2913                                                 << " List of players: " << os.str() << std::endl;
2914                                 if (m_admin_chat)
2915                                         m_admin_chat->outgoing_queue.push_back(
2916                                                 new ChatEventNick(CET_NICK_REMOVE, name));
2917                         }
2918                 }
2919                 {
2920                         MutexAutoLock env_lock(m_env_mutex);
2921                         m_clients.DeleteClient(peer_id);
2922                 }
2923         }
2924
2925         // Send leave chat message to all remaining clients
2926         if (!message.empty()) {
2927                 SendChatMessage(PEER_ID_INEXISTENT,
2928                                 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2929         }
2930 }
2931
2932 void Server::UpdateCrafting(RemotePlayer *player)
2933 {
2934         InventoryList *clist = player->inventory.getList("craft");
2935         if (!clist || clist->getSize() == 0)
2936                 return;
2937
2938         if (!clist->checkModified())
2939                 return;
2940
2941         // Get a preview for crafting
2942         ItemStack preview;
2943         InventoryLocation loc;
2944         loc.setPlayer(player->getName());
2945         std::vector<ItemStack> output_replacements;
2946         getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2947         m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2948                         clist, loc);
2949
2950         InventoryList *plist = player->inventory.getList("craftpreview");
2951         if (plist && plist->getSize() >= 1) {
2952                 // Put the new preview in
2953                 plist->changeItem(0, preview);
2954         }
2955 }
2956
2957 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2958 {
2959         if (evt->type == CET_NICK_ADD) {
2960                 // The terminal informed us of its nick choice
2961                 m_admin_nick = ((ChatEventNick *)evt)->nick;
2962                 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2963                         errorstream << "You haven't set up an account." << std::endl
2964                                 << "Please log in using the client as '"
2965                                 << m_admin_nick << "' with a secure password." << std::endl
2966                                 << "Until then, you can't execute admin tasks via the console," << std::endl
2967                                 << "and everybody can claim the user account instead of you," << std::endl
2968                                 << "giving them full control over this server." << std::endl;
2969                 }
2970         } else {
2971                 assert(evt->type == CET_CHAT);
2972                 handleAdminChat((ChatEventChat *)evt);
2973         }
2974 }
2975
2976 std::wstring Server::handleChat(const std::string &name,
2977         std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2978 {
2979         // If something goes wrong, this player is to blame
2980         RollbackScopeActor rollback_scope(m_rollback,
2981                         std::string("player:") + name);
2982
2983         if (g_settings->getBool("strip_color_codes"))
2984                 wmessage = unescape_enriched(wmessage);
2985
2986         if (player) {
2987                 switch (player->canSendChatMessage()) {
2988                 case RPLAYER_CHATRESULT_FLOODING: {
2989                         std::wstringstream ws;
2990                         ws << L"You cannot send more messages. You are limited to "
2991                                         << g_settings->getFloat("chat_message_limit_per_10sec")
2992                                         << L" messages per 10 seconds.";
2993                         return ws.str();
2994                 }
2995                 case RPLAYER_CHATRESULT_KICK:
2996                         DenyAccess(player->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING,
2997                                 "You have been kicked due to message flooding.");
2998                         return L"";
2999                 case RPLAYER_CHATRESULT_OK:
3000                         break;
3001                 default:
3002                         FATAL_ERROR("Unhandled chat filtering result found.");
3003                 }
3004         }
3005
3006         if (m_max_chatmessage_length > 0
3007                         && wmessage.length() > m_max_chatmessage_length) {
3008                 return L"Your message exceed the maximum chat message limit set on the server. "
3009                                 L"It was refused. Send a shorter message";
3010         }
3011
3012         auto message = trim(wide_to_utf8(wmessage));
3013         if (message.empty())
3014                 return L"";
3015
3016         if (message.find_first_of("\n\r") != std::wstring::npos) {
3017                 return L"Newlines are not permitted in chat messages";
3018         }
3019
3020         // Run script hook, exit if script ate the chat message
3021         if (m_script->on_chat_message(name, message))
3022                 return L"";
3023
3024         // Line to send
3025         std::wstring line;
3026         // Whether to send line to the player that sent the message, or to all players
3027         bool broadcast_line = true;
3028
3029         if (check_shout_priv && !checkPriv(name, "shout")) {
3030                 line += L"-!- You don't have permission to shout.";
3031                 broadcast_line = false;
3032         } else {
3033                 /*
3034                         Workaround for fixing chat on Android. Lua doesn't handle
3035                         the Cyrillic alphabet and some characters on older Android devices
3036                 */
3037 #ifdef __ANDROID__
3038                 line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
3039 #else
3040                 line += utf8_to_wide(m_script->formatChatMessage(name,
3041                                 wide_to_utf8(wmessage)));
3042 #endif
3043         }
3044
3045         /*
3046                 Tell calling method to send the message to sender
3047         */
3048         if (!broadcast_line)
3049                 return line;
3050
3051         /*
3052                 Send the message to others
3053         */
3054         actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
3055
3056         ChatMessage chatmsg(line);
3057
3058         std::vector<session_t> clients = m_clients.getClientIDs();
3059         for (u16 cid : clients)
3060                 SendChatMessage(cid, chatmsg);
3061
3062         return L"";
3063 }
3064
3065 void Server::handleAdminChat(const ChatEventChat *evt)
3066 {
3067         std::string name = evt->nick;
3068         std::wstring wmessage = evt->evt_msg;
3069
3070         std::wstring answer = handleChat(name, wmessage);
3071
3072         // If asked to send answer to sender
3073         if (!answer.empty()) {
3074                 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3075         }
3076 }
3077
3078 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3079 {
3080         RemoteClient *client = getClientNoEx(peer_id,state_min);
3081         if(!client)
3082                 throw ClientNotFoundException("Client not found");
3083
3084         return client;
3085 }
3086 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3087 {
3088         return m_clients.getClientNoEx(peer_id, state_min);
3089 }
3090
3091 std::string Server::getPlayerName(session_t peer_id)
3092 {
3093         RemotePlayer *player = m_env->getPlayer(peer_id);
3094         if (!player)
3095                 return "[id="+itos(peer_id)+"]";
3096         return player->getName();
3097 }
3098
3099 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3100 {
3101         RemotePlayer *player = m_env->getPlayer(peer_id);
3102         if (!player)
3103                 return NULL;
3104         return player->getPlayerSAO();
3105 }
3106
3107 std::string Server::getStatusString()
3108 {
3109         std::ostringstream os(std::ios_base::binary);
3110         os << "# Server: ";
3111         // Version
3112         os << "version: " << g_version_string;
3113         // Game
3114         os << " | game: " << (m_gamespec.title.empty() ? m_gamespec.id : m_gamespec.title);
3115         // Uptime
3116         os << " | uptime: " << duration_to_string((int) m_uptime_counter->get());
3117         // Max lag estimate
3118         os << " | max lag: " << std::setprecision(3);
3119         os << (m_env ? m_env->getMaxLagEstimate() : 0) << "s";
3120
3121         // Information about clients
3122         bool first = true;
3123         os << " | clients: ";
3124         if (m_env) {
3125                 std::vector<session_t> clients = m_clients.getClientIDs();
3126                 for (session_t client_id : clients) {
3127                         RemotePlayer *player = m_env->getPlayer(client_id);
3128
3129                         // Get name of player
3130                         const char *name = player ? player->getName() : "<unknown>";
3131
3132                         // Add name to information string
3133                         if (!first)
3134                                 os << ", ";
3135                         else
3136                                 first = false;
3137                         os << name;
3138                 }
3139         }
3140
3141         if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3142                 os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
3143
3144         if (!g_settings->get("motd").empty())
3145                 os << std::endl << "# Server: " << g_settings->get("motd");
3146
3147         return os.str();
3148 }
3149
3150 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3151 {
3152         std::set<std::string> privs;
3153         m_script->getAuth(name, NULL, &privs);
3154         return privs;
3155 }
3156
3157 bool Server::checkPriv(const std::string &name, const std::string &priv)
3158 {
3159         std::set<std::string> privs = getPlayerEffectivePrivs(name);
3160         return (privs.count(priv) != 0);
3161 }
3162
3163 void Server::reportPrivsModified(const std::string &name)
3164 {
3165         if (name.empty()) {
3166                 std::vector<session_t> clients = m_clients.getClientIDs();
3167                 for (const session_t client_id : clients) {
3168                         RemotePlayer *player = m_env->getPlayer(client_id);
3169                         reportPrivsModified(player->getName());
3170                 }
3171         } else {
3172                 RemotePlayer *player = m_env->getPlayer(name.c_str());
3173                 if (!player)
3174                         return;
3175                 SendPlayerPrivileges(player->getPeerId());
3176                 PlayerSAO *sao = player->getPlayerSAO();
3177                 if(!sao)
3178                         return;
3179                 sao->updatePrivileges(
3180                                 getPlayerEffectivePrivs(name),
3181                                 isSingleplayer());
3182         }
3183 }
3184
3185 void Server::reportInventoryFormspecModified(const std::string &name)
3186 {
3187         RemotePlayer *player = m_env->getPlayer(name.c_str());
3188         if (!player)
3189                 return;
3190         SendPlayerInventoryFormspec(player->getPeerId());
3191 }
3192
3193 void Server::reportFormspecPrependModified(const std::string &name)
3194 {
3195         RemotePlayer *player = m_env->getPlayer(name.c_str());
3196         if (!player)
3197                 return;
3198         SendPlayerFormspecPrepend(player->getPeerId());
3199 }
3200
3201 void Server::setIpBanned(const std::string &ip, const std::string &name)
3202 {
3203         m_banmanager->add(ip, name);
3204 }
3205
3206 void Server::unsetIpBanned(const std::string &ip_or_name)
3207 {
3208         m_banmanager->remove(ip_or_name);
3209 }
3210
3211 std::string Server::getBanDescription(const std::string &ip_or_name)
3212 {
3213         return m_banmanager->getBanDescription(ip_or_name);
3214 }
3215
3216 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3217 {
3218         // m_env will be NULL if the server is initializing
3219         if (!m_env)
3220                 return;
3221
3222         if (m_admin_nick == name && !m_admin_nick.empty()) {
3223                 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3224         }
3225
3226         RemotePlayer *player = m_env->getPlayer(name);
3227         if (!player) {
3228                 return;
3229         }
3230
3231         if (player->getPeerId() == PEER_ID_INEXISTENT)
3232                 return;
3233
3234         SendChatMessage(player->getPeerId(), ChatMessage(msg));
3235 }
3236
3237 bool Server::showFormspec(const char *playername, const std::string &formspec,
3238         const std::string &formname)
3239 {
3240         // m_env will be NULL if the server is initializing
3241         if (!m_env)
3242                 return false;
3243
3244         RemotePlayer *player = m_env->getPlayer(playername);
3245         if (!player)
3246                 return false;
3247
3248         SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3249         return true;
3250 }
3251
3252 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3253 {
3254         if (!player)
3255                 return -1;
3256
3257         u32 id = player->addHud(form);
3258
3259         SendHUDAdd(player->getPeerId(), id, form);
3260
3261         return id;
3262 }
3263
3264 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3265         if (!player)
3266                 return false;
3267
3268         HudElement* todel = player->removeHud(id);
3269
3270         if (!todel)
3271                 return false;
3272
3273         delete todel;
3274
3275         SendHUDRemove(player->getPeerId(), id);
3276         return true;
3277 }
3278
3279 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3280 {
3281         if (!player)
3282                 return false;
3283
3284         SendHUDChange(player->getPeerId(), id, stat, data);
3285         return true;
3286 }
3287
3288 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3289 {
3290         if (!player)
3291                 return false;
3292
3293         u32 new_hud_flags = (player->hud_flags & ~mask) | flags;
3294         if (new_hud_flags == player->hud_flags) // no change
3295                 return true;
3296         
3297         SendHUDSetFlags(player->getPeerId(), flags, mask);
3298         player->hud_flags = new_hud_flags;
3299
3300         PlayerSAO* playersao = player->getPlayerSAO();
3301
3302         if (!playersao)
3303                 return false;
3304
3305         m_script->player_event(playersao, "hud_changed");
3306         return true;
3307 }
3308
3309 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3310 {
3311         if (!player)
3312                 return false;
3313
3314         if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3315                 return false;
3316
3317         player->setHotbarItemcount(hotbar_itemcount);
3318         std::ostringstream os(std::ios::binary);
3319         writeS32(os, hotbar_itemcount);
3320         SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3321         return true;
3322 }
3323
3324 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3325 {
3326         if (!player)
3327                 return;
3328
3329         player->setHotbarImage(name);
3330         SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3331 }
3332
3333 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3334 {
3335         if (!player)
3336                 return;
3337
3338         player->setHotbarSelectedImage(name);
3339         SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3340 }
3341
3342 Address Server::getPeerAddress(session_t peer_id)
3343 {
3344         // Note that this is only set after Init was received in Server::handleCommand_Init
3345         return getClient(peer_id, CS_Invalid)->getAddress();
3346 }
3347
3348 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3349                 v2s32 animation_frames[4], f32 frame_speed)
3350 {
3351         sanity_check(player);
3352         player->setLocalAnimations(animation_frames, frame_speed);
3353         SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3354 }
3355
3356 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3357 {
3358         sanity_check(player);
3359         player->eye_offset_first = first;
3360         player->eye_offset_third = third;
3361         SendEyeOffset(player->getPeerId(), first, third);
3362 }
3363
3364 void Server::setSky(RemotePlayer *player, const SkyboxParams &params)
3365 {
3366         sanity_check(player);
3367         player->setSky(params);
3368         SendSetSky(player->getPeerId(), params);
3369 }
3370
3371 void Server::setSun(RemotePlayer *player, const SunParams &params)
3372 {
3373         sanity_check(player);
3374         player->setSun(params);
3375         SendSetSun(player->getPeerId(), params);
3376 }
3377
3378 void Server::setMoon(RemotePlayer *player, const MoonParams &params)
3379 {
3380         sanity_check(player);
3381         player->setMoon(params);
3382         SendSetMoon(player->getPeerId(), params);
3383 }
3384
3385 void Server::setStars(RemotePlayer *player, const StarParams &params)
3386 {
3387         sanity_check(player);
3388         player->setStars(params);
3389         SendSetStars(player->getPeerId(), params);
3390 }
3391
3392 void Server::setClouds(RemotePlayer *player, const CloudParams &params)
3393 {
3394         sanity_check(player);
3395         player->setCloudParams(params);
3396         SendCloudParams(player->getPeerId(), params);
3397 }
3398
3399 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3400         float ratio)
3401 {
3402         sanity_check(player);
3403         player->overrideDayNightRatio(do_override, ratio);
3404         SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3405 }
3406
3407 void Server::setLighting(RemotePlayer *player, const Lighting &lighting)
3408 {
3409         sanity_check(player);
3410         player->setLighting(lighting);
3411         SendSetLighting(player->getPeerId(), lighting);
3412 }
3413
3414 void Server::notifyPlayers(const std::wstring &msg)
3415 {
3416         SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3417 }
3418
3419 void Server::spawnParticle(const std::string &playername,
3420         const ParticleParameters &p)
3421 {
3422         // m_env will be NULL if the server is initializing
3423         if (!m_env)
3424                 return;
3425
3426         session_t peer_id = PEER_ID_INEXISTENT;
3427         u16 proto_ver = 0;
3428         if (!playername.empty()) {
3429                 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3430                 if (!player)
3431                         return;
3432                 peer_id = player->getPeerId();
3433                 proto_ver = player->protocol_version;
3434         }
3435
3436         SendSpawnParticle(peer_id, proto_ver, p);
3437 }
3438
3439 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3440         ServerActiveObject *attached, const std::string &playername)
3441 {
3442         // m_env will be NULL if the server is initializing
3443         if (!m_env)
3444                 return -1;
3445
3446         session_t peer_id = PEER_ID_INEXISTENT;
3447         u16 proto_ver = 0;
3448         if (!playername.empty()) {
3449                 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3450                 if (!player)
3451                         return -1;
3452                 peer_id = player->getPeerId();
3453                 proto_ver = player->protocol_version;
3454         }
3455
3456         u16 attached_id = attached ? attached->getId() : 0;
3457
3458         u32 id;
3459         if (attached_id == 0)
3460                 id = m_env->addParticleSpawner(p.time);
3461         else
3462                 id = m_env->addParticleSpawner(p.time, attached_id);
3463
3464         SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3465         return id;
3466 }
3467
3468 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3469 {
3470         // m_env will be NULL if the server is initializing
3471         if (!m_env)
3472                 throw ServerError("Can't delete particle spawners during initialisation!");
3473
3474         session_t peer_id = PEER_ID_INEXISTENT;
3475         if (!playername.empty()) {
3476                 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3477                 if (!player)
3478                         return;
3479                 peer_id = player->getPeerId();
3480         }
3481
3482         m_env->deleteParticleSpawner(id);
3483         SendDeleteParticleSpawner(peer_id, id);
3484 }
3485
3486 bool Server::dynamicAddMedia(std::string filepath,
3487         const u32 token, const std::string &to_player, bool ephemeral)
3488 {
3489         std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3490         auto it = m_media.find(filename);
3491         if (it != m_media.end()) {
3492                 // Allow the same path to be "added" again in certain conditions
3493                 if (ephemeral || it->second.path != filepath) {
3494                         errorstream << "Server::dynamicAddMedia(): file \"" << filename
3495                                 << "\" already exists in media cache" << std::endl;
3496                         return false;
3497                 }
3498         }
3499
3500         // Load the file and add it to our media cache
3501         std::string filedata, raw_hash;
3502         bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3503         if (!ok)
3504                 return false;
3505
3506         if (ephemeral) {
3507                 // Create a copy of the file and swap out the path, this removes the
3508                 // requirement that mods keep the file accessible at the original path.
3509                 filepath = fs::CreateTempFile();
3510                 bool ok = ([&] () -> bool {
3511                         if (filepath.empty())
3512                                 return false;
3513                         std::ofstream os(filepath.c_str(), std::ios::binary);
3514                         if (!os.good())
3515                                 return false;
3516                         os << filedata;
3517                         os.close();
3518                         return !os.fail();
3519                 })();
3520                 if (!ok) {
3521                         errorstream << "Server: failed to create a copy of media file "
3522                                 << "\"" << filename << "\"" << std::endl;
3523                         m_media.erase(filename);
3524                         return false;
3525                 }
3526                 verbosestream << "Server: \"" << filename << "\" temporarily copied to "
3527                         << filepath << std::endl;
3528
3529                 m_media[filename].path = filepath;
3530                 m_media[filename].no_announce = true;
3531                 // stepPendingDynMediaCallbacks will clean this up later.
3532         } else if (!to_player.empty()) {
3533                 m_media[filename].no_announce = true;
3534         }
3535
3536         // Push file to existing clients
3537         NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3538         pkt << raw_hash << filename << (bool)ephemeral;
3539
3540         NetworkPacket legacy_pkt = pkt;
3541
3542         // Newer clients get asked to fetch the file (asynchronous)
3543         pkt << token;
3544         // Older clients have an awful hack that just throws the data at them
3545         legacy_pkt.putLongString(filedata);
3546
3547         std::unordered_set<session_t> delivered, waiting;
3548         {
3549                 ClientInterface::AutoLock clientlock(m_clients);
3550                 for (auto &pair : m_clients.getClientList()) {
3551                         if (pair.second->getState() == CS_DefinitionsSent && !ephemeral) {
3552                                 /*
3553                                         If a client is in the DefinitionsSent state it is too late to
3554                                         transfer the file via sendMediaAnnouncement() but at the same
3555                                         time the client cannot accept a media push yet.
3556                                         Short of artificially delaying the joining process there is no
3557                                         way for the server to resolve this so we (currently) opt not to.
3558                                 */
3559                                 warningstream << "The media \"" << filename << "\" (dynamic) could "
3560                                         "not be delivered to " << pair.second->getName()
3561                                         << " due to a race condition." << std::endl;
3562                                 continue;
3563                         }
3564                         if (pair.second->getState() < CS_Active)
3565                                 continue;
3566
3567                         const auto proto_ver = pair.second->net_proto_version;
3568                         if (proto_ver < 39)
3569                                 continue;
3570
3571                         const session_t peer_id = pair.second->peer_id;
3572                         if (!to_player.empty() && getPlayerName(peer_id) != to_player)
3573                                 continue;
3574
3575                         if (proto_ver < 40) {
3576                                 delivered.emplace(peer_id);
3577                                 /*
3578                                         The network layer only guarantees ordered delivery inside a channel.
3579                                         Since the very next packet could be one that uses the media, we have
3580                                         to push the media over ALL channels to ensure it is processed before
3581                                         it is used. In practice this means channels 1 and 0.
3582                                 */
3583                                 m_clients.send(peer_id, 1, &legacy_pkt, true);
3584                                 m_clients.send(peer_id, 0, &legacy_pkt, true);
3585                         } else {
3586                                 waiting.emplace(peer_id);
3587                                 Send(peer_id, &pkt);
3588                         }
3589                 }
3590         }
3591
3592         // Run callback for players that already had the file delivered (legacy-only)
3593         for (session_t peer_id : delivered) {
3594                 if (auto player = m_env->getPlayer(peer_id))
3595                         getScriptIface()->on_dynamic_media_added(token, player->getName());
3596         }
3597
3598         // Save all others in our pending state
3599         auto &state = m_pending_dyn_media[token];
3600         state.waiting_players = std::move(waiting);
3601         // regardless of success throw away the callback after a while
3602         state.expiry_timer = 60.0f;
3603         if (ephemeral)
3604                 state.filename = filename;
3605
3606         return true;
3607 }
3608
3609 // actions: time-reversed list
3610 // Return value: success/failure
3611 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3612                 std::list<std::string> *log)
3613 {
3614         infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3615         ServerMap *map = (ServerMap*)(&m_env->getMap());
3616
3617         // Fail if no actions to handle
3618         if (actions.empty()) {
3619                 assert(log);
3620                 log->push_back("Nothing to do.");
3621                 return false;
3622         }
3623
3624         int num_tried = 0;
3625         int num_failed = 0;
3626
3627         for (const RollbackAction &action : actions) {
3628                 num_tried++;
3629                 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3630                 if(!success){
3631                         num_failed++;
3632                         std::ostringstream os;
3633                         os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3634                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3635                         if (log)
3636                                 log->push_back(os.str());
3637                 }else{
3638                         std::ostringstream os;
3639                         os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3640                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3641                         if (log)
3642                                 log->push_back(os.str());
3643                 }
3644         }
3645
3646         infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3647                         <<" failed"<<std::endl;
3648
3649         // Call it done if less than half failed
3650         return num_failed <= num_tried/2;
3651 }
3652
3653 // IGameDef interface
3654 // Under envlock
3655 IItemDefManager *Server::getItemDefManager()
3656 {
3657         return m_itemdef;
3658 }
3659
3660 const NodeDefManager *Server::getNodeDefManager()
3661 {
3662         return m_nodedef;
3663 }
3664
3665 ICraftDefManager *Server::getCraftDefManager()
3666 {
3667         return m_craftdef;
3668 }
3669
3670 u16 Server::allocateUnknownNodeId(const std::string &name)
3671 {
3672         return m_nodedef->allocateDummy(name);
3673 }
3674
3675 IWritableItemDefManager *Server::getWritableItemDefManager()
3676 {
3677         return m_itemdef;
3678 }
3679
3680 NodeDefManager *Server::getWritableNodeDefManager()
3681 {
3682         return m_nodedef;
3683 }
3684
3685 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3686 {
3687         return m_craftdef;
3688 }
3689
3690 const std::vector<ModSpec> & Server::getMods() const
3691 {
3692         return m_modmgr->getMods();
3693 }
3694
3695 const ModSpec *Server::getModSpec(const std::string &modname) const
3696 {
3697         return m_modmgr->getModSpec(modname);
3698 }
3699
3700 std::string Server::getBuiltinLuaPath()
3701 {
3702         return porting::path_share + DIR_DELIM + "builtin";
3703 }
3704
3705 v3f Server::findSpawnPos()
3706 {
3707         ServerMap &map = m_env->getServerMap();
3708         v3f nodeposf;
3709         if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3710                 return nodeposf * BS;
3711
3712         bool is_good = false;
3713         // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3714         s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3715
3716         // Try to find a good place a few times
3717         for (s32 i = 0; i < 4000 && !is_good; i++) {
3718                 s32 range = MYMIN(1 + i, range_max);
3719                 // We're going to try to throw the player to this position
3720                 v2s16 nodepos2d = v2s16(
3721                         -range + (myrand() % (range * 2)),
3722                         -range + (myrand() % (range * 2)));
3723                 // Get spawn level at point
3724                 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3725                 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3726                 // signify an unsuitable spawn position, or if outside limits.
3727                 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3728                                 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3729                         continue;
3730
3731                 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3732                 // Consecutive empty nodes
3733                 s32 air_count = 0;
3734
3735                 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3736                 // avoid obstructions in already-generated mapblocks.
3737                 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3738                 // no obstructions, but mapgen decorations are generated after spawn so
3739                 // the player may end up inside one.
3740                 for (s32 i = 0; i < 8; i++) {
3741                         v3s16 blockpos = getNodeBlockPos(nodepos);
3742                         map.emergeBlock(blockpos, true);
3743                         content_t c = map.getNode(nodepos).getContent();
3744
3745                         // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3746                         // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3747                         if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3748                                 air_count++;
3749                                 if (air_count >= 2) {
3750                                         // Spawn in lower empty node
3751                                         nodepos.Y--;
3752                                         nodeposf = intToFloat(nodepos, BS);
3753                                         // Don't spawn the player outside map boundaries
3754                                         if (objectpos_over_limit(nodeposf))
3755                                                 // Exit this loop, positions above are probably over limit
3756                                                 break;
3757
3758                                         // Good position found, cause an exit from main loop
3759                                         is_good = true;
3760                                         break;
3761                                 }
3762                         } else {
3763                                 air_count = 0;
3764                         }
3765                         nodepos.Y++;
3766                 }
3767         }
3768
3769         if (is_good)
3770                 return nodeposf;
3771
3772         // No suitable spawn point found, return fallback 0,0,0
3773         return v3f(0.0f, 0.0f, 0.0f);
3774 }
3775
3776 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3777 {
3778         if (delay == 0.0f) {
3779         // No delay, shutdown immediately
3780                 m_shutdown_state.is_requested = true;
3781                 // only print to the infostream, a chat message saying
3782                 // "Server Shutting Down" is sent when the server destructs.
3783                 infostream << "*** Immediate Server shutdown requested." << std::endl;
3784         } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3785                 // Negative delay, cancel shutdown if requested
3786                 m_shutdown_state.reset();
3787                 std::wstringstream ws;
3788
3789                 ws << L"*** Server shutdown canceled.";
3790
3791                 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3792                 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3793                 // m_shutdown_* are already handled, skip.
3794                 return;
3795         } else if (delay > 0.0f) {
3796         // Positive delay, tell the clients when the server will shut down
3797                 std::wstringstream ws;
3798
3799                 ws << L"*** Server shutting down in "
3800                                 << duration_to_string(myround(delay)).c_str()
3801                                 << ".";
3802
3803                 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3804                 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3805         }
3806
3807         m_shutdown_state.trigger(delay, msg, reconnect);
3808 }
3809
3810 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3811 {
3812         /*
3813                 Try to get an existing player
3814         */
3815         RemotePlayer *player = m_env->getPlayer(name);
3816
3817         // If player is already connected, cancel
3818         if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3819                 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3820                 return NULL;
3821         }
3822
3823         /*
3824                 If player with the wanted peer_id already exists, cancel.
3825         */
3826         if (m_env->getPlayer(peer_id)) {
3827                 infostream<<"emergePlayer(): Player with wrong name but same"
3828                                 " peer_id already exists"<<std::endl;
3829                 return NULL;
3830         }
3831
3832         if (!player) {
3833                 player = new RemotePlayer(name, idef());
3834         }
3835
3836         bool newplayer = false;
3837
3838         // Load player
3839         PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3840
3841         // Complete init with server parts
3842         playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3843         player->protocol_version = proto_version;
3844
3845         /* Run scripts */
3846         if (newplayer) {
3847                 m_script->on_newplayer(playersao);
3848         }
3849
3850         return playersao;
3851 }
3852
3853 bool Server::registerModStorage(ModMetadata *storage)
3854 {
3855         if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3856                 errorstream << "Unable to register same mod storage twice. Storage name: "
3857                                 << storage->getModName() << std::endl;
3858                 return false;
3859         }
3860
3861         m_mod_storages[storage->getModName()] = storage;
3862         return true;
3863 }
3864
3865 void Server::unregisterModStorage(const std::string &name)
3866 {
3867         std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3868         if (it != m_mod_storages.end())
3869                 m_mod_storages.erase(name);
3870 }
3871
3872 void dedicated_server_loop(Server &server, bool &kill)
3873 {
3874         verbosestream<<"dedicated_server_loop()"<<std::endl;
3875
3876         IntervalLimiter m_profiler_interval;
3877
3878         static thread_local const float steplen =
3879                         g_settings->getFloat("dedicated_server_step");
3880         static thread_local const float profiler_print_interval =
3881                         g_settings->getFloat("profiler_print_interval");
3882
3883         /*
3884          * The dedicated server loop only does time-keeping (in Server::step) and
3885          * provides a way to main.cpp to kill the server externally (bool &kill).
3886          */
3887
3888         for(;;) {
3889                 // This is kind of a hack but can be done like this
3890                 // because server.step() is very light
3891                 sleep_ms((int)(steplen*1000.0));
3892                 server.step(steplen);
3893
3894                 if (server.isShutdownRequested() || kill)
3895                         break;
3896
3897                 /*
3898                         Profiler
3899                 */
3900                 if (profiler_print_interval != 0) {
3901                         if(m_profiler_interval.step(steplen, profiler_print_interval))
3902                         {
3903                                 infostream<<"Profiler:"<<std::endl;
3904                                 g_profiler->print(infostream);
3905                                 g_profiler->clear();
3906                         }
3907                 }
3908         }
3909
3910         infostream << "Dedicated server quitting" << std::endl;
3911 #if USE_CURL
3912         if (g_settings->getBool("server_announce"))
3913                 ServerList::sendAnnounce(ServerList::AA_DELETE,
3914                         server.m_bind_addr.getPort());
3915 #endif
3916 }
3917
3918 /*
3919  * Mod channels
3920  */
3921
3922
3923 bool Server::joinModChannel(const std::string &channel)
3924 {
3925         return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3926                         m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3927 }
3928
3929 bool Server::leaveModChannel(const std::string &channel)
3930 {
3931         return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3932 }
3933
3934 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3935 {
3936         if (!m_modchannel_mgr->canWriteOnChannel(channel))
3937                 return false;
3938
3939         broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3940         return true;
3941 }
3942
3943 ModChannel* Server::getModChannel(const std::string &channel)
3944 {
3945         return m_modchannel_mgr->getModChannel(channel);
3946 }
3947
3948 void Server::broadcastModChannelMessage(const std::string &channel,
3949                 const std::string &message, session_t from_peer)
3950 {
3951         const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3952         if (peers.empty())
3953                 return;
3954
3955         if (message.size() > STRING_MAX_LEN) {
3956                 warningstream << "ModChannel message too long, dropping before sending "
3957                                 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3958                                 << channel << ")" << std::endl;
3959                 return;
3960         }
3961
3962         std::string sender;
3963         if (from_peer != PEER_ID_SERVER) {
3964                 sender = getPlayerName(from_peer);
3965         }
3966
3967         NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3968                         2 + channel.size() + 2 + sender.size() + 2 + message.size());
3969         resp_pkt << channel << sender << message;
3970         for (session_t peer_id : peers) {
3971                 // Ignore sender
3972                 if (peer_id == from_peer)
3973                         continue;
3974
3975                 Send(peer_id, &resp_pkt);
3976         }
3977
3978         if (from_peer != PEER_ID_SERVER) {
3979                 m_script->on_modchannel_message(channel, sender, message);
3980         }
3981 }
3982
3983 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3984 {
3985         if (lang_code.empty())
3986                 return nullptr;
3987
3988         auto it = server_translations.find(lang_code);
3989         if (it != server_translations.end())
3990                 return &it->second; // Already loaded
3991
3992         // [] will create an entry
3993         auto *translations = &server_translations[lang_code];
3994
3995         std::string suffix = "." + lang_code + ".tr";
3996         for (const auto &i : m_media) {
3997                 if (str_ends_with(i.first, suffix)) {
3998                         std::string data;
3999                         if (fs::ReadFile(i.second.path, data)) {
4000                                 translations->loadTranslation(data);
4001                         }
4002                 }
4003         }
4004
4005         return translations;
4006 }
4007
4008 ModMetadataDatabase *Server::openModStorageDatabase(const std::string &world_path)
4009 {
4010         std::string world_mt_path = world_path + DIR_DELIM + "world.mt";
4011         Settings world_mt;
4012         if (!world_mt.readConfigFile(world_mt_path.c_str()))
4013                 throw BaseException("Cannot read world.mt!");
4014
4015         std::string backend = world_mt.exists("mod_storage_backend") ?
4016                 world_mt.get("mod_storage_backend") : "files";
4017         if (backend == "files")
4018                 warningstream << "/!\\ You are using the old mod storage files backend. "
4019                         << "This backend is deprecated and may be removed in a future release /!\\"
4020                         << std::endl << "Switching to SQLite3 is advised, "
4021                         << "please read http://wiki.minetest.net/Database_backends." << std::endl;
4022
4023         return openModStorageDatabase(backend, world_path, world_mt);
4024 }
4025
4026 ModMetadataDatabase *Server::openModStorageDatabase(const std::string &backend,
4027                 const std::string &world_path, const Settings &world_mt)
4028 {
4029         if (backend == "sqlite3")
4030                 return new ModMetadataDatabaseSQLite3(world_path);
4031
4032         if (backend == "files")
4033                 return new ModMetadataDatabaseFiles(world_path);
4034
4035         if (backend == "dummy")
4036                 return new Database_Dummy();
4037
4038         throw BaseException("Mod storage database backend " + backend + " not supported");
4039 }
4040
4041 bool Server::migrateModStorageDatabase(const GameParams &game_params, const Settings &cmd_args)
4042 {
4043         std::string migrate_to = cmd_args.get("migrate-mod-storage");
4044         Settings world_mt;
4045         std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt";
4046         if (!world_mt.readConfigFile(world_mt_path.c_str())) {
4047                 errorstream << "Cannot read world.mt!" << std::endl;
4048                 return false;
4049         }
4050
4051         std::string backend = world_mt.exists("mod_storage_backend") ?
4052                 world_mt.get("mod_storage_backend") : "files";
4053         if (backend == migrate_to) {
4054                 errorstream << "Cannot migrate: new backend is same"
4055                         << " as the old one" << std::endl;
4056                 return false;
4057         }
4058
4059         ModMetadataDatabase *srcdb = nullptr;
4060         ModMetadataDatabase *dstdb = nullptr;
4061
4062         bool succeeded = false;
4063
4064         try {
4065                 srcdb = Server::openModStorageDatabase(backend, game_params.world_path, world_mt);
4066                 dstdb = Server::openModStorageDatabase(migrate_to, game_params.world_path, world_mt);
4067
4068                 dstdb->beginSave();
4069
4070                 std::vector<std::string> mod_list;
4071                 srcdb->listMods(&mod_list);
4072                 for (const std::string &modname : mod_list) {
4073                         StringMap meta;
4074                         srcdb->getModEntries(modname, &meta);
4075                         for (const auto &pair : meta) {
4076                                 dstdb->setModEntry(modname, pair.first, pair.second);
4077                         }
4078                 }
4079
4080                 dstdb->endSave();
4081
4082                 succeeded = true;
4083
4084                 actionstream << "Successfully migrated the metadata of "
4085                         << mod_list.size() << " mods" << std::endl;
4086                 world_mt.set("mod_storage_backend", migrate_to);
4087                 if (!world_mt.updateConfigFile(world_mt_path.c_str()))
4088                         errorstream << "Failed to update world.mt!" << std::endl;
4089                 else
4090                         actionstream << "world.mt updated" << std::endl;
4091
4092         } catch (BaseException &e) {
4093                 errorstream << "An error occurred during migration: " << e.what() << std::endl;
4094         }
4095
4096         delete srcdb;
4097         delete dstdb;
4098
4099         if (succeeded && backend == "files") {
4100                 // Back up files
4101                 const std::string storage_path = game_params.world_path + DIR_DELIM + "mod_storage";
4102                 const std::string backup_path = game_params.world_path + DIR_DELIM + "mod_storage.bak";
4103                 if (!fs::Rename(storage_path, backup_path))
4104                         warningstream << "After migration, " << storage_path
4105                                 << " could not be renamed to " << backup_path << std::endl;
4106         }
4107
4108         return succeeded;
4109 }