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