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