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