]> git.lizzy.rs Git - minetest.git/blob - src/server.cpp
Report collisionMoveSimple for client and server. (#13105)
[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         pkt << lighting.exposure.luminance_min
1870                         << lighting.exposure.luminance_max
1871                         << lighting.exposure.exposure_correction
1872                         << lighting.exposure.speed_dark_bright
1873                         << lighting.exposure.speed_bright_dark
1874                         << lighting.exposure.center_weight_power;
1875
1876         Send(&pkt);
1877 }
1878
1879 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1880 {
1881         NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1882         pkt << time << time_speed;
1883
1884         if (peer_id == PEER_ID_INEXISTENT) {
1885                 m_clients.sendToAll(&pkt);
1886         }
1887         else {
1888                 Send(&pkt);
1889         }
1890 }
1891
1892 void Server::SendPlayerBreath(PlayerSAO *sao)
1893 {
1894         assert(sao);
1895
1896         m_script->player_event(sao, "breath_changed");
1897         SendBreath(sao->getPeerID(), sao->getBreath());
1898 }
1899
1900 void Server::SendMovePlayer(session_t peer_id)
1901 {
1902         RemotePlayer *player = m_env->getPlayer(peer_id);
1903         assert(player);
1904         PlayerSAO *sao = player->getPlayerSAO();
1905         assert(sao);
1906
1907         // Send attachment updates instantly to the client prior updating position
1908         sao->sendOutdatedData();
1909
1910         NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1911         pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1912
1913         {
1914                 v3f pos = sao->getBasePosition();
1915                 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1916                                 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1917                                 << " pitch=" << sao->getLookPitch()
1918                                 << " yaw=" << sao->getRotation().Y
1919                                 << std::endl;
1920         }
1921
1922         Send(&pkt);
1923 }
1924
1925 void Server::SendPlayerFov(session_t peer_id)
1926 {
1927         NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1928
1929         PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1930         pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1931
1932         Send(&pkt);
1933 }
1934
1935 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1936                 f32 animation_speed)
1937 {
1938         NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1939                 peer_id);
1940
1941         pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1942                         << animation_frames[3] << animation_speed;
1943
1944         Send(&pkt);
1945 }
1946
1947 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1948 {
1949         NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1950         pkt << first << third;
1951         Send(&pkt);
1952 }
1953
1954 void Server::SendPlayerPrivileges(session_t peer_id)
1955 {
1956         RemotePlayer *player = m_env->getPlayer(peer_id);
1957         assert(player);
1958         if(player->getPeerId() == PEER_ID_INEXISTENT)
1959                 return;
1960
1961         std::set<std::string> privs;
1962         m_script->getAuth(player->getName(), NULL, &privs);
1963
1964         NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1965         pkt << (u16) privs.size();
1966
1967         for (const std::string &priv : privs) {
1968                 pkt << priv;
1969         }
1970
1971         Send(&pkt);
1972 }
1973
1974 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1975 {
1976         RemotePlayer *player = m_env->getPlayer(peer_id);
1977         assert(player);
1978         if (player->getPeerId() == PEER_ID_INEXISTENT)
1979                 return;
1980
1981         NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1982         pkt.putLongString(player->inventory_formspec);
1983
1984         Send(&pkt);
1985 }
1986
1987 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1988 {
1989         RemotePlayer *player = m_env->getPlayer(peer_id);
1990         assert(player);
1991         if (player->getPeerId() == PEER_ID_INEXISTENT)
1992                 return;
1993
1994         NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1995         pkt << player->formspec_prepend;
1996         Send(&pkt);
1997 }
1998
1999 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
2000 {
2001         // Radius inside which objects are active
2002         static thread_local const s16 radius =
2003                 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
2004
2005         // Radius inside which players are active
2006         static thread_local const bool is_transfer_limited =
2007                 g_settings->exists("unlimited_player_transfer_distance") &&
2008                 !g_settings->getBool("unlimited_player_transfer_distance");
2009
2010         static thread_local const s16 player_transfer_dist =
2011                 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
2012
2013         s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
2014                 radius : player_transfer_dist;
2015
2016         s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
2017         if (my_radius <= 0)
2018                 my_radius = radius;
2019
2020         std::queue<u16> removed_objects, added_objects;
2021         m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
2022                 client->m_known_objects, removed_objects);
2023         m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
2024                 client->m_known_objects, added_objects);
2025
2026         int removed_count = removed_objects.size();
2027         int added_count   = added_objects.size();
2028
2029         if (removed_objects.empty() && added_objects.empty())
2030                 return;
2031
2032         char buf[4];
2033         std::string data;
2034
2035         // Handle removed objects
2036         writeU16((u8*)buf, removed_objects.size());
2037         data.append(buf, 2);
2038         while (!removed_objects.empty()) {
2039                 // Get object
2040                 u16 id = removed_objects.front();
2041                 ServerActiveObject* obj = m_env->getActiveObject(id);
2042
2043                 // Add to data buffer for sending
2044                 writeU16((u8*)buf, id);
2045                 data.append(buf, 2);
2046
2047                 // Remove from known objects
2048                 client->m_known_objects.erase(id);
2049
2050                 if (obj && obj->m_known_by_count > 0)
2051                         obj->m_known_by_count--;
2052
2053                 removed_objects.pop();
2054         }
2055
2056         // Handle added objects
2057         writeU16((u8*)buf, added_objects.size());
2058         data.append(buf, 2);
2059         while (!added_objects.empty()) {
2060                 // Get object
2061                 u16 id = added_objects.front();
2062                 ServerActiveObject *obj = m_env->getActiveObject(id);
2063                 added_objects.pop();
2064
2065                 if (!obj) {
2066                         warningstream << FUNCTION_NAME << ": NULL object id="
2067                                 << (int)id << std::endl;
2068                         continue;
2069                 }
2070
2071                 // Get object type
2072                 u8 type = obj->getSendType();
2073
2074                 // Add to data buffer for sending
2075                 writeU16((u8*)buf, id);
2076                 data.append(buf, 2);
2077                 writeU8((u8*)buf, type);
2078                 data.append(buf, 1);
2079
2080                 data.append(serializeString32(
2081                         obj->getClientInitializationData(client->net_proto_version)));
2082
2083                 // Add to known objects
2084                 client->m_known_objects.insert(id);
2085
2086                 obj->m_known_by_count++;
2087         }
2088
2089         NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2090         pkt.putRawString(data.c_str(), data.size());
2091         Send(&pkt);
2092
2093         verbosestream << "Server::SendActiveObjectRemoveAdd: "
2094                 << removed_count << " removed, " << added_count << " added, "
2095                 << "packet size is " << pkt.getSize() << std::endl;
2096 }
2097
2098 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2099                 bool reliable)
2100 {
2101         NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2102                         datas.size(), peer_id);
2103
2104         pkt.putRawString(datas.c_str(), datas.size());
2105
2106         m_clients.send(pkt.getPeerId(),
2107                         reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2108                         &pkt, reliable);
2109 }
2110
2111 void Server::SendCSMRestrictionFlags(session_t peer_id)
2112 {
2113         NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2114                 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2115         pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2116         Send(&pkt);
2117 }
2118
2119 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2120 {
2121         NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2122         pkt << added_vel;
2123         Send(&pkt);
2124 }
2125
2126 inline s32 Server::nextSoundId()
2127 {
2128         s32 ret = m_next_sound_id;
2129         if (m_next_sound_id == INT32_MAX)
2130                 m_next_sound_id = 0; // signed overflow is undefined
2131         else
2132                 m_next_sound_id++;
2133         return ret;
2134 }
2135
2136 s32 Server::playSound(ServerPlayingSound &params, bool ephemeral)
2137 {
2138         // Find out initial position of sound
2139         bool pos_exists = false;
2140         const v3f pos = params.getPos(m_env, &pos_exists);
2141         // If position is not found while it should be, cancel sound
2142         if(pos_exists != (params.type != SoundLocation::Local))
2143                 return -1;
2144
2145         // Filter destination clients
2146         std::vector<session_t> dst_clients;
2147         if (!params.to_player.empty()) {
2148                 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2149                 if(!player){
2150                         infostream<<"Server::playSound: Player \""<<params.to_player
2151                                         <<"\" not found"<<std::endl;
2152                         return -1;
2153                 }
2154                 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2155                         infostream<<"Server::playSound: Player \""<<params.to_player
2156                                         <<"\" not connected"<<std::endl;
2157                         return -1;
2158                 }
2159                 dst_clients.push_back(player->getPeerId());
2160         } else {
2161                 std::vector<session_t> clients = m_clients.getClientIDs();
2162
2163                 for (const session_t client_id : clients) {
2164                         RemotePlayer *player = m_env->getPlayer(client_id);
2165                         if (!player)
2166                                 continue;
2167                         if (!params.exclude_player.empty() &&
2168                                         params.exclude_player == player->getName())
2169                                 continue;
2170
2171                         PlayerSAO *sao = player->getPlayerSAO();
2172                         if (!sao)
2173                                 continue;
2174
2175                         if (pos_exists) {
2176                                 if(sao->getBasePosition().getDistanceFrom(pos) >
2177                                                 params.max_hear_distance)
2178                                         continue;
2179                         }
2180                         dst_clients.push_back(client_id);
2181                 }
2182         }
2183
2184         if(dst_clients.empty())
2185                 return -1;
2186
2187         // old clients will still use this, so pick a reserved ID (-1)
2188         const s32 id = ephemeral ? -1 : nextSoundId();
2189
2190         float gain = params.gain * params.spec.gain;
2191         NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2192         pkt << id << params.spec.name << gain
2193                         << (u8) params.type << pos << params.object
2194                         << params.spec.loop << params.spec.fade << params.spec.pitch
2195                         << ephemeral;
2196
2197         bool as_reliable = !ephemeral;
2198
2199         for (const session_t peer_id : dst_clients) {
2200                 if (!ephemeral)
2201                         params.clients.insert(peer_id);
2202                 m_clients.send(peer_id, 0, &pkt, as_reliable);
2203         }
2204
2205         if (!ephemeral)
2206                 m_playing_sounds[id] = std::move(params);
2207         return id;
2208 }
2209 void Server::stopSound(s32 handle)
2210 {
2211         auto it = m_playing_sounds.find(handle);
2212         if (it == m_playing_sounds.end())
2213                 return;
2214
2215         ServerPlayingSound &psound = it->second;
2216
2217         NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2218         pkt << handle;
2219
2220         for (session_t peer_id : psound.clients) {
2221                 // Send as reliable
2222                 m_clients.send(peer_id, 0, &pkt, true);
2223         }
2224
2225         // Remove sound reference
2226         m_playing_sounds.erase(it);
2227 }
2228
2229 void Server::fadeSound(s32 handle, float step, float gain)
2230 {
2231         auto it = m_playing_sounds.find(handle);
2232         if (it == m_playing_sounds.end())
2233                 return;
2234
2235         ServerPlayingSound &psound = it->second;
2236         psound.gain = gain; // destination gain
2237
2238         NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2239         pkt << handle << step << gain;
2240
2241         for (session_t peer_id : psound.clients) {
2242                 // Send as reliable
2243                 m_clients.send(peer_id, 0, &pkt, true);
2244         }
2245
2246         // Remove sound reference
2247         if (gain <= 0 || psound.clients.empty())
2248                 m_playing_sounds.erase(it);
2249 }
2250
2251 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2252                 float far_d_nodes)
2253 {
2254         v3f p_f = intToFloat(p, BS);
2255         v3s16 block_pos = getNodeBlockPos(p);
2256
2257         NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2258         pkt << p;
2259
2260         sendNodeChangePkt(pkt, block_pos, p_f, far_d_nodes, far_players);
2261 }
2262
2263 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2264                 float far_d_nodes, bool remove_metadata)
2265 {
2266         v3f p_f = intToFloat(p, BS);
2267         v3s16 block_pos = getNodeBlockPos(p);
2268
2269         NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2270         pkt << p << n.param0 << n.param1 << n.param2
2271                         << (u8) (remove_metadata ? 0 : 1);
2272         sendNodeChangePkt(pkt, block_pos, p_f, far_d_nodes, far_players);
2273 }
2274
2275 void Server::sendNodeChangePkt(NetworkPacket &pkt, v3s16 block_pos,
2276                 v3f p, float far_d_nodes, std::unordered_set<u16> *far_players)
2277 {
2278         float maxd = far_d_nodes * BS;
2279         std::vector<session_t> clients = m_clients.getClientIDs();
2280         ClientInterface::AutoLock clientlock(m_clients);
2281
2282         for (session_t client_id : clients) {
2283                 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2284                 if (!client)
2285                         continue;
2286
2287                 RemotePlayer *player = m_env->getPlayer(client_id);
2288                 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2289
2290                 // If player is far away, only set modified blocks not sent
2291                 if (!client->isBlockSent(block_pos) || (sao &&
2292                                 sao->getBasePosition().getDistanceFrom(p) > maxd)) {
2293                         if (far_players)
2294                                 far_players->emplace(client_id);
2295                         else
2296                                 client->SetBlockNotSent(block_pos);
2297                         continue;
2298                 }
2299
2300                 // Send as reliable
2301                 m_clients.send(client_id, 0, &pkt, true);
2302         }
2303 }
2304
2305 void Server::sendMetadataChanged(const std::unordered_set<v3s16> &positions, float far_d_nodes)
2306 {
2307         NodeMetadataList meta_updates_list(false);
2308         std::ostringstream os(std::ios::binary);
2309
2310         std::vector<session_t> clients = m_clients.getClientIDs();
2311         ClientInterface::AutoLock clientlock(m_clients);
2312
2313         for (session_t i : clients) {
2314                 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2315                 if (!client)
2316                         continue;
2317
2318                 ServerActiveObject *player = getPlayerSAO(i);
2319                 v3s16 player_pos;
2320                 if (player)
2321                         player_pos = floatToInt(player->getBasePosition(), BS);
2322
2323                 for (const v3s16 pos : positions) {
2324                         NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2325
2326                         if (!meta)
2327                                 continue;
2328
2329                         v3s16 block_pos = getNodeBlockPos(pos);
2330                         if (!client->isBlockSent(block_pos) ||
2331                                         player_pos.getDistanceFrom(pos) > far_d_nodes) {
2332                                 client->SetBlockNotSent(block_pos);
2333                                 continue;
2334                         }
2335
2336                         // Add the change to send list
2337                         meta_updates_list.set(pos, meta);
2338                 }
2339                 if (meta_updates_list.size() == 0)
2340                         continue;
2341
2342                 // Send the meta changes
2343                 os.str("");
2344                 meta_updates_list.serialize(os, client->serialization_version, false, true, true);
2345                 std::string raw = os.str();
2346                 os.str("");
2347                 compressZlib(raw, os);
2348
2349                 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0, i);
2350                 pkt.putLongString(os.str());
2351                 Send(&pkt);
2352
2353                 meta_updates_list.clear();
2354         }
2355 }
2356
2357 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2358                 u16 net_proto_version, SerializedBlockCache *cache)
2359 {
2360         thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
2361         std::string s, *sptr = nullptr;
2362
2363         if (cache) {
2364                 auto it = cache->find({block->getPos(), ver});
2365                 if (it != cache->end())
2366                         sptr = &it->second;
2367         }
2368
2369         // Serialize the block in the right format
2370         if (!sptr) {
2371                 std::ostringstream os(std::ios_base::binary);
2372                 block->serialize(os, ver, false, net_compression_level);
2373                 block->serializeNetworkSpecific(os);
2374                 s = os.str();
2375                 sptr = &s;
2376         }
2377
2378         NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + sptr->size(), peer_id);
2379         pkt << block->getPos();
2380         pkt.putRawString(*sptr);
2381         Send(&pkt);
2382
2383         // Store away in cache
2384         if (cache && sptr == &s)
2385                 (*cache)[{block->getPos(), ver}] = std::move(s);
2386 }
2387
2388 void Server::SendBlocks(float dtime)
2389 {
2390         MutexAutoLock envlock(m_env_mutex);
2391         //TODO check if one big lock could be faster then multiple small ones
2392
2393         std::vector<PrioritySortedBlockTransfer> queue;
2394
2395         u32 total_sending = 0, unique_clients = 0;
2396
2397         {
2398                 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2399
2400                 std::vector<session_t> clients = m_clients.getClientIDs();
2401
2402                 ClientInterface::AutoLock clientlock(m_clients);
2403                 for (const session_t client_id : clients) {
2404                         RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2405
2406                         if (!client)
2407                                 continue;
2408
2409                         total_sending += client->getSendingCount();
2410                         const auto old_count = queue.size();
2411                         client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2412                         unique_clients += queue.size() > old_count ? 1 : 0;
2413                 }
2414         }
2415
2416         // Sort.
2417         // Lowest priority number comes first.
2418         // Lowest is most important.
2419         std::sort(queue.begin(), queue.end());
2420
2421         ClientInterface::AutoLock clientlock(m_clients);
2422
2423         // Maximal total count calculation
2424         // The per-client block sends is halved with the maximal online users
2425         u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2426                 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2427
2428         ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2429         Map &map = m_env->getMap();
2430
2431         SerializedBlockCache cache, *cache_ptr = nullptr;
2432         if (unique_clients > 1) {
2433                 // caching is pointless with a single client
2434                 cache_ptr = &cache;
2435         }
2436
2437         for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2438                 if (total_sending >= max_blocks_to_send)
2439                         break;
2440
2441                 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2442                 if (!block)
2443                         continue;
2444
2445                 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2446                                 CS_Active);
2447                 if (!client)
2448                         continue;
2449
2450                 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2451                                 client->net_proto_version, cache_ptr);
2452
2453                 client->SentBlock(block_to_send.pos);
2454                 total_sending++;
2455         }
2456 }
2457
2458 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2459 {
2460         MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2461         if (!block)
2462                 return false;
2463
2464         ClientInterface::AutoLock clientlock(m_clients);
2465         RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2466         if (!client || client->isBlockSent(blockpos))
2467                 return false;
2468         SendBlockNoLock(peer_id, block, client->serialization_version,
2469                         client->net_proto_version);
2470
2471         return true;
2472 }
2473
2474 bool Server::addMediaFile(const std::string &filename,
2475         const std::string &filepath, std::string *filedata_to,
2476         std::string *digest_to)
2477 {
2478         // If name contains illegal characters, ignore the file
2479         if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2480                 infostream << "Server: ignoring illegal file name: \""
2481                                 << filename << "\"" << std::endl;
2482                 return false;
2483         }
2484         // If name is not in a supported format, ignore it
2485         const char *supported_ext[] = {
2486                 ".png", ".jpg", ".bmp", ".tga",
2487                 ".ogg",
2488                 ".x", ".b3d", ".obj",
2489                 // Custom translation file format
2490                 ".tr",
2491                 NULL
2492         };
2493         if (removeStringEnd(filename, supported_ext).empty()) {
2494                 infostream << "Server: ignoring unsupported file extension: \""
2495                                 << filename << "\"" << std::endl;
2496                 return false;
2497         }
2498         // Ok, attempt to load the file and add to cache
2499
2500         // Read data
2501         std::string filedata;
2502         if (!fs::ReadFile(filepath, filedata)) {
2503                 errorstream << "Server::addMediaFile(): Failed to open \""
2504                                         << filename << "\" for reading" << std::endl;
2505                 return false;
2506         }
2507
2508         if (filedata.empty()) {
2509                 errorstream << "Server::addMediaFile(): Empty file \""
2510                                 << filepath << "\"" << std::endl;
2511                 return false;
2512         }
2513
2514         SHA1 sha1;
2515         sha1.addBytes(filedata.c_str(), filedata.length());
2516
2517         unsigned char *digest = sha1.getDigest();
2518         std::string sha1_base64 = base64_encode(digest, 20);
2519         std::string sha1_hex = hex_encode((char*) digest, 20);
2520         if (digest_to)
2521                 *digest_to = std::string((char*) digest, 20);
2522         free(digest);
2523
2524         // Put in list
2525         m_media[filename] = MediaInfo(filepath, sha1_base64);
2526         verbosestream << "Server: " << sha1_hex << " is " << filename
2527                         << std::endl;
2528
2529         if (filedata_to)
2530                 *filedata_to = std::move(filedata);
2531         return true;
2532 }
2533
2534 void Server::fillMediaCache()
2535 {
2536         infostream << "Server: Calculating media file checksums" << std::endl;
2537
2538         // Collect all media file paths
2539         std::vector<std::string> paths;
2540
2541         // ordered in descending priority
2542         paths.push_back(getBuiltinLuaPath() + DIR_DELIM + "locale");
2543         fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2544         fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2545         m_modmgr->getModsMediaPaths(paths);
2546
2547         // Collect media file information from paths into cache
2548         for (const std::string &mediapath : paths) {
2549                 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2550                 for (const fs::DirListNode &dln : dirlist) {
2551                         if (dln.dir) // Ignore dirs (already in paths)
2552                                 continue;
2553
2554                         const std::string &filename = dln.name;
2555                         if (m_media.find(filename) != m_media.end()) // Do not override
2556                                 continue;
2557
2558                         std::string filepath = mediapath;
2559                         filepath.append(DIR_DELIM).append(filename);
2560                         addMediaFile(filename, filepath);
2561                 }
2562         }
2563
2564         infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2565 }
2566
2567 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2568 {
2569         // Make packet
2570         NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2571
2572         u16 media_sent = 0;
2573         std::string lang_suffix;
2574         lang_suffix.append(".").append(lang_code).append(".tr");
2575         for (const auto &i : m_media) {
2576                 if (i.second.no_announce)
2577                         continue;
2578                 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2579                         continue;
2580                 media_sent++;
2581         }
2582
2583         pkt << media_sent;
2584
2585         for (const auto &i : m_media) {
2586                 if (i.second.no_announce)
2587                         continue;
2588                 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2589                         continue;
2590                 pkt << i.first << i.second.sha1_digest;
2591         }
2592
2593         pkt << g_settings->get("remote_media");
2594         Send(&pkt);
2595
2596         verbosestream << "Server: Announcing files to id(" << peer_id
2597                 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2598 }
2599
2600 struct SendableMedia
2601 {
2602         std::string name;
2603         std::string path;
2604         std::string data;
2605
2606         SendableMedia(const std::string &name, const std::string &path,
2607                         std::string &&data):
2608                 name(name), path(path), data(std::move(data))
2609         {}
2610 };
2611
2612 void Server::sendRequestedMedia(session_t peer_id,
2613                 const std::vector<std::string> &tosend)
2614 {
2615         verbosestream<<"Server::sendRequestedMedia(): "
2616                         <<"Sending files to client"<<std::endl;
2617
2618         /* Read files */
2619
2620         // Put 5kB in one bunch (this is not accurate)
2621         u32 bytes_per_bunch = 5000;
2622
2623         std::vector< std::vector<SendableMedia> > file_bunches;
2624         file_bunches.emplace_back();
2625
2626         u32 file_size_bunch_total = 0;
2627
2628         for (const std::string &name : tosend) {
2629                 if (m_media.find(name) == m_media.end()) {
2630                         errorstream<<"Server::sendRequestedMedia(): Client asked for "
2631                                         <<"unknown file \""<<(name)<<"\""<<std::endl;
2632                         continue;
2633                 }
2634
2635                 const auto &m = m_media[name];
2636
2637                 // Read data
2638                 std::string data;
2639                 if (!fs::ReadFile(m.path, data)) {
2640                         errorstream << "Server::sendRequestedMedia(): Failed to read \""
2641                                         << name << "\"" << std::endl;
2642                         continue;
2643                 }
2644                 file_size_bunch_total += data.size();
2645
2646                 // Put in list
2647                 file_bunches.back().emplace_back(name, m.path, std::move(data));
2648
2649                 // Start next bunch if got enough data
2650                 if(file_size_bunch_total >= bytes_per_bunch) {
2651                         file_bunches.emplace_back();
2652                         file_size_bunch_total = 0;
2653                 }
2654
2655         }
2656
2657         /* Create and send packets */
2658
2659         u16 num_bunches = file_bunches.size();
2660         for (u16 i = 0; i < num_bunches; i++) {
2661                 /*
2662                         u16 command
2663                         u16 total number of texture bunches
2664                         u16 index of this bunch
2665                         u32 number of files in this bunch
2666                         for each file {
2667                                 u16 length of name
2668                                 string name
2669                                 u32 length of data
2670                                 data
2671                         }
2672                 */
2673
2674                 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2675                 pkt << num_bunches << i << (u32) file_bunches[i].size();
2676
2677                 for (const SendableMedia &j : file_bunches[i]) {
2678                         pkt << j.name;
2679                         pkt.putLongString(j.data);
2680                 }
2681
2682                 verbosestream << "Server::sendRequestedMedia(): bunch "
2683                                 << i << "/" << num_bunches
2684                                 << " files=" << file_bunches[i].size()
2685                                 << " size="  << pkt.getSize() << std::endl;
2686                 Send(&pkt);
2687         }
2688 }
2689
2690 void Server::stepPendingDynMediaCallbacks(float dtime)
2691 {
2692         MutexAutoLock lock(m_env_mutex);
2693
2694         for (auto it = m_pending_dyn_media.begin(); it != m_pending_dyn_media.end();) {
2695                 it->second.expiry_timer -= dtime;
2696                 bool del = it->second.waiting_players.empty() || it->second.expiry_timer < 0;
2697
2698                 if (!del) {
2699                         it++;
2700                         continue;
2701                 }
2702
2703                 const auto &name = it->second.filename;
2704                 if (!name.empty()) {
2705                         assert(m_media.count(name));
2706                         // if no_announce isn't set we're definitely deleting the wrong file!
2707                         sanity_check(m_media[name].no_announce);
2708
2709                         fs::DeleteSingleFileOrEmptyDirectory(m_media[name].path);
2710                         m_media.erase(name);
2711                 }
2712                 getScriptIface()->freeDynamicMediaCallback(it->first);
2713                 it = m_pending_dyn_media.erase(it);
2714         }
2715 }
2716
2717 void Server::SendMinimapModes(session_t peer_id,
2718                 std::vector<MinimapMode> &modes, size_t wanted_mode)
2719 {
2720         RemotePlayer *player = m_env->getPlayer(peer_id);
2721         assert(player);
2722         if (player->getPeerId() == PEER_ID_INEXISTENT)
2723                 return;
2724
2725         NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2726         pkt << (u16)modes.size() << (u16)wanted_mode;
2727
2728         for (auto &mode : modes)
2729                 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2730
2731         Send(&pkt);
2732 }
2733
2734 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2735 {
2736         NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2737         pkt << name;
2738
2739         if (!inventory) {
2740                 pkt << false; // Remove inventory
2741         } else {
2742                 pkt << true; // Update inventory
2743
2744                 // Serialization & NetworkPacket isn't a love story
2745                 std::ostringstream os(std::ios_base::binary);
2746                 inventory->serialize(os);
2747                 inventory->setModified(false);
2748
2749                 const std::string &os_str = os.str();
2750                 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2751                 pkt.putRawString(os_str);
2752         }
2753
2754         if (peer_id == PEER_ID_INEXISTENT)
2755                 m_clients.sendToAll(&pkt);
2756         else
2757                 Send(&pkt);
2758 }
2759
2760 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2761 {
2762         // Lookup player name, to filter detached inventories just after
2763         std::string peer_name;
2764         if (peer_id != PEER_ID_INEXISTENT) {
2765                 peer_name = getClient(peer_id, CS_Created)->getName();
2766         }
2767
2768         auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2769                 sendDetachedInventory(inv, name, peer_id);
2770         };
2771
2772         m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2773 }
2774
2775 /*
2776         Something random
2777 */
2778
2779 void Server::HandlePlayerDeath(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
2780 {
2781         infostream << "Server::DiePlayer(): Player "
2782                         << playersao->getPlayer()->getName()
2783                         << " dies" << std::endl;
2784
2785         playersao->clearParentAttachment();
2786
2787         // Trigger scripted stuff
2788         m_script->on_dieplayer(playersao, reason);
2789
2790         SendDeathscreen(playersao->getPeerID(), false, v3f(0,0,0));
2791 }
2792
2793 void Server::RespawnPlayer(session_t peer_id)
2794 {
2795         PlayerSAO *playersao = getPlayerSAO(peer_id);
2796         assert(playersao);
2797
2798         infostream << "Server::RespawnPlayer(): Player "
2799                         << playersao->getPlayer()->getName()
2800                         << " respawns" << std::endl;
2801
2802         const auto *prop = playersao->accessObjectProperties();
2803         playersao->setHP(prop->hp_max,
2804                         PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2805         playersao->setBreath(prop->breath_max);
2806
2807         bool repositioned = m_script->on_respawnplayer(playersao);
2808         if (!repositioned) {
2809                 // setPos will send the new position to client
2810                 playersao->setPos(findSpawnPos());
2811         }
2812 }
2813
2814
2815 void Server::DenySudoAccess(session_t peer_id)
2816 {
2817         NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2818         Send(&pkt);
2819 }
2820
2821
2822 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2823                 const std::string &custom_reason, bool reconnect)
2824 {
2825         SendAccessDenied(peer_id, reason, custom_reason, reconnect);
2826         m_clients.event(peer_id, CSE_SetDenied);
2827         DisconnectPeer(peer_id);
2828 }
2829
2830 void Server::DisconnectPeer(session_t peer_id)
2831 {
2832         m_modchannel_mgr->leaveAllChannels(peer_id);
2833         m_con->DisconnectPeer(peer_id);
2834 }
2835
2836 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2837 {
2838         if (!forSudoMode) {
2839                 RemoteClient* client = getClient(peer_id, CS_Invalid);
2840
2841                 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2842
2843                 // Right now, the auth mechs don't change between login and sudo mode.
2844                 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2845                 client->allowed_sudo_mechs = sudo_auth_mechs;
2846
2847                 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2848                                 << g_settings->getFloat("dedicated_server_step")
2849                                 << sudo_auth_mechs;
2850
2851                 Send(&resp_pkt);
2852                 m_clients.event(peer_id, CSE_AuthAccept);
2853         } else {
2854                 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2855
2856                 // We only support SRP right now
2857                 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2858
2859                 resp_pkt << sudo_auth_mechs;
2860                 Send(&resp_pkt);
2861                 m_clients.event(peer_id, CSE_SudoSuccess);
2862         }
2863 }
2864
2865 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2866 {
2867         std::wstring message;
2868         {
2869                 /*
2870                         Clear references to playing sounds
2871                 */
2872                 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2873                                  i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2874                         ServerPlayingSound &psound = i->second;
2875                         psound.clients.erase(peer_id);
2876                         if (psound.clients.empty())
2877                                 m_playing_sounds.erase(i++);
2878                         else
2879                                 ++i;
2880                 }
2881
2882                 // clear formspec info so the next client can't abuse the current state
2883                 m_formspec_state_data.erase(peer_id);
2884
2885                 RemotePlayer *player = m_env->getPlayer(peer_id);
2886
2887                 /* Run scripts and remove from environment */
2888                 if (player) {
2889                         PlayerSAO *playersao = player->getPlayerSAO();
2890                         assert(playersao);
2891
2892                         playersao->clearChildAttachments();
2893                         playersao->clearParentAttachment();
2894
2895                         // inform connected clients
2896                         const std::string &player_name = player->getName();
2897                         NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2898                         // (u16) 1 + std::string represents a vector serialization representation
2899                         notice << (u8) PLAYER_LIST_REMOVE  << (u16) 1 << player_name;
2900                         m_clients.sendToAll(&notice);
2901                         // run scripts
2902                         m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2903
2904                         playersao->disconnected();
2905                 }
2906
2907                 /*
2908                         Print out action
2909                 */
2910                 {
2911                         if (player && reason != CDR_DENY) {
2912                                 std::ostringstream os(std::ios_base::binary);
2913                                 std::vector<session_t> clients = m_clients.getClientIDs();
2914
2915                                 for (const session_t client_id : clients) {
2916                                         // Get player
2917                                         RemotePlayer *player = m_env->getPlayer(client_id);
2918                                         if (!player)
2919                                                 continue;
2920
2921                                         // Get name of player
2922                                         os << player->getName() << " ";
2923                                 }
2924
2925                                 std::string name = player->getName();
2926                                 actionstream << name << " "
2927                                                 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2928                                                 << " List of players: " << os.str() << std::endl;
2929                                 if (m_admin_chat)
2930                                         m_admin_chat->outgoing_queue.push_back(
2931                                                 new ChatEventNick(CET_NICK_REMOVE, name));
2932                         }
2933                 }
2934                 {
2935                         MutexAutoLock env_lock(m_env_mutex);
2936                         m_clients.DeleteClient(peer_id);
2937                 }
2938         }
2939
2940         // Send leave chat message to all remaining clients
2941         if (!message.empty()) {
2942                 SendChatMessage(PEER_ID_INEXISTENT,
2943                                 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2944         }
2945 }
2946
2947 void Server::UpdateCrafting(RemotePlayer *player)
2948 {
2949         InventoryList *clist = player->inventory.getList("craft");
2950         if (!clist || clist->getSize() == 0)
2951                 return;
2952
2953         if (!clist->checkModified())
2954                 return;
2955
2956         // Get a preview for crafting
2957         ItemStack preview;
2958         InventoryLocation loc;
2959         loc.setPlayer(player->getName());
2960         std::vector<ItemStack> output_replacements;
2961         getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2962         m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2963                         clist, loc);
2964
2965         InventoryList *plist = player->inventory.getList("craftpreview");
2966         if (plist && plist->getSize() >= 1) {
2967                 // Put the new preview in
2968                 plist->changeItem(0, preview);
2969         }
2970 }
2971
2972 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2973 {
2974         if (evt->type == CET_NICK_ADD) {
2975                 // The terminal informed us of its nick choice
2976                 m_admin_nick = ((ChatEventNick *)evt)->nick;
2977                 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2978                         errorstream << "You haven't set up an account." << std::endl
2979                                 << "Please log in using the client as '"
2980                                 << m_admin_nick << "' with a secure password." << std::endl
2981                                 << "Until then, you can't execute admin tasks via the console," << std::endl
2982                                 << "and everybody can claim the user account instead of you," << std::endl
2983                                 << "giving them full control over this server." << std::endl;
2984                 }
2985         } else {
2986                 assert(evt->type == CET_CHAT);
2987                 handleAdminChat((ChatEventChat *)evt);
2988         }
2989 }
2990
2991 std::wstring Server::handleChat(const std::string &name,
2992         std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2993 {
2994         // If something goes wrong, this player is to blame
2995         RollbackScopeActor rollback_scope(m_rollback,
2996                         std::string("player:") + name);
2997
2998         if (g_settings->getBool("strip_color_codes"))
2999                 wmessage = unescape_enriched(wmessage);
3000
3001         if (player) {
3002                 switch (player->canSendChatMessage()) {
3003                 case RPLAYER_CHATRESULT_FLOODING: {
3004                         std::wstringstream ws;
3005                         ws << L"You cannot send more messages. You are limited to "
3006                                         << g_settings->getFloat("chat_message_limit_per_10sec")
3007                                         << L" messages per 10 seconds.";
3008                         return ws.str();
3009                 }
3010                 case RPLAYER_CHATRESULT_KICK:
3011                         DenyAccess(player->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING,
3012                                 "You have been kicked due to message flooding.");
3013                         return L"";
3014                 case RPLAYER_CHATRESULT_OK:
3015                         break;
3016                 default:
3017                         FATAL_ERROR("Unhandled chat filtering result found.");
3018                 }
3019         }
3020
3021         if (m_max_chatmessage_length > 0
3022                         && wmessage.length() > m_max_chatmessage_length) {
3023                 return L"Your message exceed the maximum chat message limit set on the server. "
3024                                 L"It was refused. Send a shorter message";
3025         }
3026
3027         auto message = trim(wide_to_utf8(wmessage));
3028         if (message.empty())
3029                 return L"";
3030
3031         if (message.find_first_of("\n\r") != std::wstring::npos) {
3032                 return L"Newlines are not permitted in chat messages";
3033         }
3034
3035         // Run script hook, exit if script ate the chat message
3036         if (m_script->on_chat_message(name, message))
3037                 return L"";
3038
3039         // Line to send
3040         std::wstring line;
3041         // Whether to send line to the player that sent the message, or to all players
3042         bool broadcast_line = true;
3043
3044         if (check_shout_priv && !checkPriv(name, "shout")) {
3045                 line += L"-!- You don't have permission to shout.";
3046                 broadcast_line = false;
3047         } else {
3048                 /*
3049                         Workaround for fixing chat on Android. Lua doesn't handle
3050                         the Cyrillic alphabet and some characters on older Android devices
3051                 */
3052 #ifdef __ANDROID__
3053                 line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
3054 #else
3055                 line += utf8_to_wide(m_script->formatChatMessage(name,
3056                                 wide_to_utf8(wmessage)));
3057 #endif
3058         }
3059
3060         /*
3061                 Tell calling method to send the message to sender
3062         */
3063         if (!broadcast_line)
3064                 return line;
3065
3066         /*
3067                 Send the message to others
3068         */
3069         actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
3070
3071         ChatMessage chatmsg(line);
3072
3073         std::vector<session_t> clients = m_clients.getClientIDs();
3074         for (u16 cid : clients)
3075                 SendChatMessage(cid, chatmsg);
3076
3077         return L"";
3078 }
3079
3080 void Server::handleAdminChat(const ChatEventChat *evt)
3081 {
3082         std::string name = evt->nick;
3083         std::wstring wmessage = evt->evt_msg;
3084
3085         std::wstring answer = handleChat(name, wmessage);
3086
3087         // If asked to send answer to sender
3088         if (!answer.empty()) {
3089                 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3090         }
3091 }
3092
3093 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3094 {
3095         RemoteClient *client = getClientNoEx(peer_id,state_min);
3096         if(!client)
3097                 throw ClientNotFoundException("Client not found");
3098
3099         return client;
3100 }
3101 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3102 {
3103         return m_clients.getClientNoEx(peer_id, state_min);
3104 }
3105
3106 std::string Server::getPlayerName(session_t peer_id)
3107 {
3108         RemotePlayer *player = m_env->getPlayer(peer_id);
3109         if (!player)
3110                 return "[id="+itos(peer_id)+"]";
3111         return player->getName();
3112 }
3113
3114 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3115 {
3116         RemotePlayer *player = m_env->getPlayer(peer_id);
3117         if (!player)
3118                 return NULL;
3119         return player->getPlayerSAO();
3120 }
3121
3122 std::string Server::getStatusString()
3123 {
3124         std::ostringstream os(std::ios_base::binary);
3125         os << "# Server: ";
3126         // Version
3127         os << "version: " << g_version_string;
3128         // Game
3129         os << " | game: " << (m_gamespec.title.empty() ? m_gamespec.id : m_gamespec.title);
3130         // Uptime
3131         os << " | uptime: " << duration_to_string((int) m_uptime_counter->get());
3132         // Max lag estimate
3133         os << " | max lag: " << std::setprecision(3);
3134         os << (m_env ? m_env->getMaxLagEstimate() : 0) << "s";
3135
3136         // Information about clients
3137         bool first = true;
3138         os << " | clients: ";
3139         if (m_env) {
3140                 std::vector<session_t> clients = m_clients.getClientIDs();
3141                 for (session_t client_id : clients) {
3142                         RemotePlayer *player = m_env->getPlayer(client_id);
3143
3144                         // Get name of player
3145                         const char *name = player ? player->getName() : "<unknown>";
3146
3147                         // Add name to information string
3148                         if (!first)
3149                                 os << ", ";
3150                         else
3151                                 first = false;
3152                         os << name;
3153                 }
3154         }
3155
3156         if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3157                 os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
3158
3159         if (!g_settings->get("motd").empty())
3160                 os << std::endl << "# Server: " << g_settings->get("motd");
3161
3162         return os.str();
3163 }
3164
3165 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3166 {
3167         std::set<std::string> privs;
3168         m_script->getAuth(name, NULL, &privs);
3169         return privs;
3170 }
3171
3172 bool Server::checkPriv(const std::string &name, const std::string &priv)
3173 {
3174         std::set<std::string> privs = getPlayerEffectivePrivs(name);
3175         return (privs.count(priv) != 0);
3176 }
3177
3178 void Server::reportPrivsModified(const std::string &name)
3179 {
3180         if (name.empty()) {
3181                 std::vector<session_t> clients = m_clients.getClientIDs();
3182                 for (const session_t client_id : clients) {
3183                         RemotePlayer *player = m_env->getPlayer(client_id);
3184                         reportPrivsModified(player->getName());
3185                 }
3186         } else {
3187                 RemotePlayer *player = m_env->getPlayer(name.c_str());
3188                 if (!player)
3189                         return;
3190                 SendPlayerPrivileges(player->getPeerId());
3191                 PlayerSAO *sao = player->getPlayerSAO();
3192                 if(!sao)
3193                         return;
3194                 sao->updatePrivileges(
3195                                 getPlayerEffectivePrivs(name),
3196                                 isSingleplayer());
3197         }
3198 }
3199
3200 void Server::reportInventoryFormspecModified(const std::string &name)
3201 {
3202         RemotePlayer *player = m_env->getPlayer(name.c_str());
3203         if (!player)
3204                 return;
3205         SendPlayerInventoryFormspec(player->getPeerId());
3206 }
3207
3208 void Server::reportFormspecPrependModified(const std::string &name)
3209 {
3210         RemotePlayer *player = m_env->getPlayer(name.c_str());
3211         if (!player)
3212                 return;
3213         SendPlayerFormspecPrepend(player->getPeerId());
3214 }
3215
3216 void Server::setIpBanned(const std::string &ip, const std::string &name)
3217 {
3218         m_banmanager->add(ip, name);
3219 }
3220
3221 void Server::unsetIpBanned(const std::string &ip_or_name)
3222 {
3223         m_banmanager->remove(ip_or_name);
3224 }
3225
3226 std::string Server::getBanDescription(const std::string &ip_or_name)
3227 {
3228         return m_banmanager->getBanDescription(ip_or_name);
3229 }
3230
3231 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3232 {
3233         // m_env will be NULL if the server is initializing
3234         if (!m_env)
3235                 return;
3236
3237         if (m_admin_nick == name && !m_admin_nick.empty()) {
3238                 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3239         }
3240
3241         RemotePlayer *player = m_env->getPlayer(name);
3242         if (!player) {
3243                 return;
3244         }
3245
3246         if (player->getPeerId() == PEER_ID_INEXISTENT)
3247                 return;
3248
3249         SendChatMessage(player->getPeerId(), ChatMessage(msg));
3250 }
3251
3252 bool Server::showFormspec(const char *playername, const std::string &formspec,
3253         const std::string &formname)
3254 {
3255         // m_env will be NULL if the server is initializing
3256         if (!m_env)
3257                 return false;
3258
3259         RemotePlayer *player = m_env->getPlayer(playername);
3260         if (!player)
3261                 return false;
3262
3263         SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3264         return true;
3265 }
3266
3267 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3268 {
3269         if (!player)
3270                 return -1;
3271
3272         u32 id = player->addHud(form);
3273
3274         SendHUDAdd(player->getPeerId(), id, form);
3275
3276         return id;
3277 }
3278
3279 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3280         if (!player)
3281                 return false;
3282
3283         HudElement* todel = player->removeHud(id);
3284
3285         if (!todel)
3286                 return false;
3287
3288         delete todel;
3289
3290         SendHUDRemove(player->getPeerId(), id);
3291         return true;
3292 }
3293
3294 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3295 {
3296         if (!player)
3297                 return false;
3298
3299         SendHUDChange(player->getPeerId(), id, stat, data);
3300         return true;
3301 }
3302
3303 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3304 {
3305         if (!player)
3306                 return false;
3307
3308         u32 new_hud_flags = (player->hud_flags & ~mask) | flags;
3309         if (new_hud_flags == player->hud_flags) // no change
3310                 return true;
3311
3312         SendHUDSetFlags(player->getPeerId(), flags, mask);
3313         player->hud_flags = new_hud_flags;
3314
3315         PlayerSAO* playersao = player->getPlayerSAO();
3316
3317         if (!playersao)
3318                 return false;
3319
3320         m_script->player_event(playersao, "hud_changed");
3321         return true;
3322 }
3323
3324 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3325 {
3326         if (!player)
3327                 return false;
3328
3329         if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3330                 return false;
3331
3332         player->setHotbarItemcount(hotbar_itemcount);
3333         std::ostringstream os(std::ios::binary);
3334         writeS32(os, hotbar_itemcount);
3335         SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3336         return true;
3337 }
3338
3339 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3340 {
3341         if (!player)
3342                 return;
3343
3344         player->setHotbarImage(name);
3345         SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3346 }
3347
3348 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3349 {
3350         if (!player)
3351                 return;
3352
3353         player->setHotbarSelectedImage(name);
3354         SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3355 }
3356
3357 Address Server::getPeerAddress(session_t peer_id)
3358 {
3359         // Note that this is only set after Init was received in Server::handleCommand_Init
3360         return getClient(peer_id, CS_Invalid)->getAddress();
3361 }
3362
3363 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3364                 v2s32 animation_frames[4], f32 frame_speed)
3365 {
3366         sanity_check(player);
3367         player->setLocalAnimations(animation_frames, frame_speed);
3368         SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3369 }
3370
3371 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3372 {
3373         sanity_check(player);
3374         player->eye_offset_first = first;
3375         player->eye_offset_third = third;
3376         SendEyeOffset(player->getPeerId(), first, third);
3377 }
3378
3379 void Server::setSky(RemotePlayer *player, const SkyboxParams &params)
3380 {
3381         sanity_check(player);
3382         player->setSky(params);
3383         SendSetSky(player->getPeerId(), params);
3384 }
3385
3386 void Server::setSun(RemotePlayer *player, const SunParams &params)
3387 {
3388         sanity_check(player);
3389         player->setSun(params);
3390         SendSetSun(player->getPeerId(), params);
3391 }
3392
3393 void Server::setMoon(RemotePlayer *player, const MoonParams &params)
3394 {
3395         sanity_check(player);
3396         player->setMoon(params);
3397         SendSetMoon(player->getPeerId(), params);
3398 }
3399
3400 void Server::setStars(RemotePlayer *player, const StarParams &params)
3401 {
3402         sanity_check(player);
3403         player->setStars(params);
3404         SendSetStars(player->getPeerId(), params);
3405 }
3406
3407 void Server::setClouds(RemotePlayer *player, const CloudParams &params)
3408 {
3409         sanity_check(player);
3410         player->setCloudParams(params);
3411         SendCloudParams(player->getPeerId(), params);
3412 }
3413
3414 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3415         float ratio)
3416 {
3417         sanity_check(player);
3418         player->overrideDayNightRatio(do_override, ratio);
3419         SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3420 }
3421
3422 void Server::setLighting(RemotePlayer *player, const Lighting &lighting)
3423 {
3424         sanity_check(player);
3425         player->setLighting(lighting);
3426         SendSetLighting(player->getPeerId(), lighting);
3427 }
3428
3429 void Server::notifyPlayers(const std::wstring &msg)
3430 {
3431         SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3432 }
3433
3434 void Server::spawnParticle(const std::string &playername,
3435         const ParticleParameters &p)
3436 {
3437         // m_env will be NULL if the server is initializing
3438         if (!m_env)
3439                 return;
3440
3441         session_t peer_id = PEER_ID_INEXISTENT;
3442         u16 proto_ver = 0;
3443         if (!playername.empty()) {
3444                 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3445                 if (!player)
3446                         return;
3447                 peer_id = player->getPeerId();
3448                 proto_ver = player->protocol_version;
3449         }
3450
3451         SendSpawnParticle(peer_id, proto_ver, p);
3452 }
3453
3454 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3455         ServerActiveObject *attached, const std::string &playername)
3456 {
3457         // m_env will be NULL if the server is initializing
3458         if (!m_env)
3459                 return -1;
3460
3461         session_t peer_id = PEER_ID_INEXISTENT;
3462         u16 proto_ver = 0;
3463         if (!playername.empty()) {
3464                 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3465                 if (!player)
3466                         return -1;
3467                 peer_id = player->getPeerId();
3468                 proto_ver = player->protocol_version;
3469         }
3470
3471         u16 attached_id = attached ? attached->getId() : 0;
3472
3473         u32 id;
3474         if (attached_id == 0)
3475                 id = m_env->addParticleSpawner(p.time);
3476         else
3477                 id = m_env->addParticleSpawner(p.time, attached_id);
3478
3479         SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3480         return id;
3481 }
3482
3483 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3484 {
3485         // m_env will be NULL if the server is initializing
3486         if (!m_env)
3487                 throw ServerError("Can't delete particle spawners during initialisation!");
3488
3489         session_t peer_id = PEER_ID_INEXISTENT;
3490         if (!playername.empty()) {
3491                 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3492                 if (!player)
3493                         return;
3494                 peer_id = player->getPeerId();
3495         }
3496
3497         m_env->deleteParticleSpawner(id);
3498         SendDeleteParticleSpawner(peer_id, id);
3499 }
3500
3501 bool Server::dynamicAddMedia(std::string filepath,
3502         const u32 token, const std::string &to_player, bool ephemeral)
3503 {
3504         std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3505         auto it = m_media.find(filename);
3506         if (it != m_media.end()) {
3507                 // Allow the same path to be "added" again in certain conditions
3508                 if (ephemeral || it->second.path != filepath) {
3509                         errorstream << "Server::dynamicAddMedia(): file \"" << filename
3510                                 << "\" already exists in media cache" << std::endl;
3511                         return false;
3512                 }
3513         }
3514
3515         // Load the file and add it to our media cache
3516         std::string filedata, raw_hash;
3517         bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3518         if (!ok)
3519                 return false;
3520
3521         if (ephemeral) {
3522                 // Create a copy of the file and swap out the path, this removes the
3523                 // requirement that mods keep the file accessible at the original path.
3524                 filepath = fs::CreateTempFile();
3525                 bool ok = ([&] () -> bool {
3526                         if (filepath.empty())
3527                                 return false;
3528                         std::ofstream os(filepath.c_str(), std::ios::binary);
3529                         if (!os.good())
3530                                 return false;
3531                         os << filedata;
3532                         os.close();
3533                         return !os.fail();
3534                 })();
3535                 if (!ok) {
3536                         errorstream << "Server: failed to create a copy of media file "
3537                                 << "\"" << filename << "\"" << std::endl;
3538                         m_media.erase(filename);
3539                         return false;
3540                 }
3541                 verbosestream << "Server: \"" << filename << "\" temporarily copied to "
3542                         << filepath << std::endl;
3543
3544                 m_media[filename].path = filepath;
3545                 m_media[filename].no_announce = true;
3546                 // stepPendingDynMediaCallbacks will clean this up later.
3547         } else if (!to_player.empty()) {
3548                 m_media[filename].no_announce = true;
3549         }
3550
3551         // Push file to existing clients
3552         NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3553         pkt << raw_hash << filename << (bool)ephemeral;
3554
3555         NetworkPacket legacy_pkt = pkt;
3556
3557         // Newer clients get asked to fetch the file (asynchronous)
3558         pkt << token;
3559         // Older clients have an awful hack that just throws the data at them
3560         legacy_pkt.putLongString(filedata);
3561
3562         std::unordered_set<session_t> delivered, waiting;
3563         {
3564                 ClientInterface::AutoLock clientlock(m_clients);
3565                 for (auto &pair : m_clients.getClientList()) {
3566                         if (pair.second->getState() == CS_DefinitionsSent && !ephemeral) {
3567                                 /*
3568                                         If a client is in the DefinitionsSent state it is too late to
3569                                         transfer the file via sendMediaAnnouncement() but at the same
3570                                         time the client cannot accept a media push yet.
3571                                         Short of artificially delaying the joining process there is no
3572                                         way for the server to resolve this so we (currently) opt not to.
3573                                 */
3574                                 warningstream << "The media \"" << filename << "\" (dynamic) could "
3575                                         "not be delivered to " << pair.second->getName()
3576                                         << " due to a race condition." << std::endl;
3577                                 continue;
3578                         }
3579                         if (pair.second->getState() < CS_Active)
3580                                 continue;
3581
3582                         const auto proto_ver = pair.second->net_proto_version;
3583                         if (proto_ver < 39)
3584                                 continue;
3585
3586                         const session_t peer_id = pair.second->peer_id;
3587                         if (!to_player.empty() && getPlayerName(peer_id) != to_player)
3588                                 continue;
3589
3590                         if (proto_ver < 40) {
3591                                 delivered.emplace(peer_id);
3592                                 /*
3593                                         The network layer only guarantees ordered delivery inside a channel.
3594                                         Since the very next packet could be one that uses the media, we have
3595                                         to push the media over ALL channels to ensure it is processed before
3596                                         it is used. In practice this means channels 1 and 0.
3597                                 */
3598                                 m_clients.send(peer_id, 1, &legacy_pkt, true);
3599                                 m_clients.send(peer_id, 0, &legacy_pkt, true);
3600                         } else {
3601                                 waiting.emplace(peer_id);
3602                                 Send(peer_id, &pkt);
3603                         }
3604                 }
3605         }
3606
3607         // Run callback for players that already had the file delivered (legacy-only)
3608         for (session_t peer_id : delivered) {
3609                 if (auto player = m_env->getPlayer(peer_id))
3610                         getScriptIface()->on_dynamic_media_added(token, player->getName());
3611         }
3612
3613         // Save all others in our pending state
3614         auto &state = m_pending_dyn_media[token];
3615         state.waiting_players = std::move(waiting);
3616         // regardless of success throw away the callback after a while
3617         state.expiry_timer = 60.0f;
3618         if (ephemeral)
3619                 state.filename = filename;
3620
3621         return true;
3622 }
3623
3624 // actions: time-reversed list
3625 // Return value: success/failure
3626 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3627                 std::list<std::string> *log)
3628 {
3629         infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3630         ServerMap *map = (ServerMap*)(&m_env->getMap());
3631
3632         // Fail if no actions to handle
3633         if (actions.empty()) {
3634                 assert(log);
3635                 log->push_back("Nothing to do.");
3636                 return false;
3637         }
3638
3639         int num_tried = 0;
3640         int num_failed = 0;
3641
3642         for (const RollbackAction &action : actions) {
3643                 num_tried++;
3644                 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3645                 if(!success){
3646                         num_failed++;
3647                         std::ostringstream os;
3648                         os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3649                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3650                         if (log)
3651                                 log->push_back(os.str());
3652                 }else{
3653                         std::ostringstream os;
3654                         os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3655                         infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3656                         if (log)
3657                                 log->push_back(os.str());
3658                 }
3659         }
3660
3661         infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3662                         <<" failed"<<std::endl;
3663
3664         // Call it done if less than half failed
3665         return num_failed <= num_tried/2;
3666 }
3667
3668 // IGameDef interface
3669 // Under envlock
3670 IItemDefManager *Server::getItemDefManager()
3671 {
3672         return m_itemdef;
3673 }
3674
3675 const NodeDefManager *Server::getNodeDefManager()
3676 {
3677         return m_nodedef;
3678 }
3679
3680 ICraftDefManager *Server::getCraftDefManager()
3681 {
3682         return m_craftdef;
3683 }
3684
3685 u16 Server::allocateUnknownNodeId(const std::string &name)
3686 {
3687         return m_nodedef->allocateDummy(name);
3688 }
3689
3690 IWritableItemDefManager *Server::getWritableItemDefManager()
3691 {
3692         return m_itemdef;
3693 }
3694
3695 NodeDefManager *Server::getWritableNodeDefManager()
3696 {
3697         return m_nodedef;
3698 }
3699
3700 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3701 {
3702         return m_craftdef;
3703 }
3704
3705 const std::vector<ModSpec> & Server::getMods() const
3706 {
3707         return m_modmgr->getMods();
3708 }
3709
3710 const ModSpec *Server::getModSpec(const std::string &modname) const
3711 {
3712         return m_modmgr->getModSpec(modname);
3713 }
3714
3715 std::string Server::getBuiltinLuaPath()
3716 {
3717         return porting::path_share + DIR_DELIM + "builtin";
3718 }
3719
3720 v3f Server::findSpawnPos()
3721 {
3722         ServerMap &map = m_env->getServerMap();
3723         v3f nodeposf;
3724         if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3725                 return nodeposf * BS;
3726
3727         bool is_good = false;
3728         // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3729         s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3730
3731         // Try to find a good place a few times
3732         for (s32 i = 0; i < 4000 && !is_good; i++) {
3733                 s32 range = MYMIN(1 + i, range_max);
3734                 // We're going to try to throw the player to this position
3735                 v2s16 nodepos2d = v2s16(
3736                         -range + myrand_range(0, range*2),
3737                         -range + myrand_range(0, range*2));
3738                 // Get spawn level at point
3739                 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3740                 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3741                 // signify an unsuitable spawn position, or if outside limits.
3742                 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3743                                 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3744                         continue;
3745
3746                 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3747                 // Consecutive empty nodes
3748                 s32 air_count = 0;
3749
3750                 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3751                 // avoid obstructions in already-generated mapblocks.
3752                 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3753                 // no obstructions, but mapgen decorations are generated after spawn so
3754                 // the player may end up inside one.
3755                 for (s32 i = 0; i < 8; i++) {
3756                         v3s16 blockpos = getNodeBlockPos(nodepos);
3757                         map.emergeBlock(blockpos, true);
3758                         content_t c = map.getNode(nodepos).getContent();
3759
3760                         // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3761                         // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3762                         if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3763                                 air_count++;
3764                                 if (air_count >= 2) {
3765                                         // Spawn in lower empty node
3766                                         nodepos.Y--;
3767                                         nodeposf = intToFloat(nodepos, BS);
3768                                         // Don't spawn the player outside map boundaries
3769                                         if (objectpos_over_limit(nodeposf))
3770                                                 // Exit this loop, positions above are probably over limit
3771                                                 break;
3772
3773                                         // Good position found, cause an exit from main loop
3774                                         is_good = true;
3775                                         break;
3776                                 }
3777                         } else {
3778                                 air_count = 0;
3779                         }
3780                         nodepos.Y++;
3781                 }
3782         }
3783
3784         if (is_good)
3785                 return nodeposf;
3786
3787         // No suitable spawn point found, return fallback 0,0,0
3788         return v3f(0.0f, 0.0f, 0.0f);
3789 }
3790
3791 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3792 {
3793         if (delay == 0.0f) {
3794         // No delay, shutdown immediately
3795                 m_shutdown_state.is_requested = true;
3796                 // only print to the infostream, a chat message saying
3797                 // "Server Shutting Down" is sent when the server destructs.
3798                 infostream << "*** Immediate Server shutdown requested." << std::endl;
3799         } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3800                 // Negative delay, cancel shutdown if requested
3801                 m_shutdown_state.reset();
3802                 std::wstringstream ws;
3803
3804                 ws << L"*** Server shutdown canceled.";
3805
3806                 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3807                 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3808                 // m_shutdown_* are already handled, skip.
3809                 return;
3810         } else if (delay > 0.0f) {
3811         // Positive delay, tell the clients when the server will shut down
3812                 std::wstringstream ws;
3813
3814                 ws << L"*** Server shutting down in "
3815                                 << duration_to_string(myround(delay)).c_str()
3816                                 << ".";
3817
3818                 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3819                 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3820         }
3821
3822         m_shutdown_state.trigger(delay, msg, reconnect);
3823 }
3824
3825 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3826 {
3827         /*
3828                 Try to get an existing player
3829         */
3830         RemotePlayer *player = m_env->getPlayer(name);
3831
3832         // If player is already connected, cancel
3833         if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3834                 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3835                 return NULL;
3836         }
3837
3838         /*
3839                 If player with the wanted peer_id already exists, cancel.
3840         */
3841         if (m_env->getPlayer(peer_id)) {
3842                 infostream<<"emergePlayer(): Player with wrong name but same"
3843                                 " peer_id already exists"<<std::endl;
3844                 return NULL;
3845         }
3846
3847         if (!player) {
3848                 player = new RemotePlayer(name, idef());
3849         }
3850
3851         bool newplayer = false;
3852
3853         // Load player
3854         PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3855
3856         // Complete init with server parts
3857         playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3858         player->protocol_version = proto_version;
3859
3860         /* Run scripts */
3861         if (newplayer) {
3862                 m_script->on_newplayer(playersao);
3863         }
3864
3865         return playersao;
3866 }
3867
3868 void dedicated_server_loop(Server &server, bool &kill)
3869 {
3870         verbosestream<<"dedicated_server_loop()"<<std::endl;
3871
3872         IntervalLimiter m_profiler_interval;
3873
3874         static thread_local const float steplen =
3875                         g_settings->getFloat("dedicated_server_step");
3876         static thread_local const float profiler_print_interval =
3877                         g_settings->getFloat("profiler_print_interval");
3878
3879         /*
3880          * The dedicated server loop only does time-keeping (in Server::step) and
3881          * provides a way to main.cpp to kill the server externally (bool &kill).
3882          */
3883
3884         for(;;) {
3885                 // This is kind of a hack but can be done like this
3886                 // because server.step() is very light
3887                 sleep_ms((int)(steplen*1000.0));
3888                 server.step(steplen);
3889
3890                 if (server.isShutdownRequested() || kill)
3891                         break;
3892
3893                 /*
3894                         Profiler
3895                 */
3896                 if (profiler_print_interval != 0) {
3897                         if(m_profiler_interval.step(steplen, profiler_print_interval))
3898                         {
3899                                 infostream<<"Profiler:"<<std::endl;
3900                                 g_profiler->print(infostream);
3901                                 g_profiler->clear();
3902                         }
3903                 }
3904         }
3905
3906         infostream << "Dedicated server quitting" << std::endl;
3907 #if USE_CURL
3908         if (g_settings->getBool("server_announce"))
3909                 ServerList::sendAnnounce(ServerList::AA_DELETE,
3910                         server.m_bind_addr.getPort());
3911 #endif
3912 }
3913
3914 /*
3915  * Mod channels
3916  */
3917
3918
3919 bool Server::joinModChannel(const std::string &channel)
3920 {
3921         return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3922                         m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3923 }
3924
3925 bool Server::leaveModChannel(const std::string &channel)
3926 {
3927         return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3928 }
3929
3930 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3931 {
3932         if (!m_modchannel_mgr->canWriteOnChannel(channel))
3933                 return false;
3934
3935         broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3936         return true;
3937 }
3938
3939 ModChannel* Server::getModChannel(const std::string &channel)
3940 {
3941         return m_modchannel_mgr->getModChannel(channel);
3942 }
3943
3944 void Server::broadcastModChannelMessage(const std::string &channel,
3945                 const std::string &message, session_t from_peer)
3946 {
3947         const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3948         if (peers.empty())
3949                 return;
3950
3951         if (message.size() > STRING_MAX_LEN) {
3952                 warningstream << "ModChannel message too long, dropping before sending "
3953                                 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3954                                 << channel << ")" << std::endl;
3955                 return;
3956         }
3957
3958         std::string sender;
3959         if (from_peer != PEER_ID_SERVER) {
3960                 sender = getPlayerName(from_peer);
3961         }
3962
3963         NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3964                         2 + channel.size() + 2 + sender.size() + 2 + message.size());
3965         resp_pkt << channel << sender << message;
3966         for (session_t peer_id : peers) {
3967                 // Ignore sender
3968                 if (peer_id == from_peer)
3969                         continue;
3970
3971                 Send(peer_id, &resp_pkt);
3972         }
3973
3974         if (from_peer != PEER_ID_SERVER) {
3975                 m_script->on_modchannel_message(channel, sender, message);
3976         }
3977 }
3978
3979 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3980 {
3981         if (lang_code.empty())
3982                 return nullptr;
3983
3984         auto it = server_translations.find(lang_code);
3985         if (it != server_translations.end())
3986                 return &it->second; // Already loaded
3987
3988         // [] will create an entry
3989         auto *translations = &server_translations[lang_code];
3990
3991         std::string suffix = "." + lang_code + ".tr";
3992         for (const auto &i : m_media) {
3993                 if (str_ends_with(i.first, suffix)) {
3994                         std::string data;
3995                         if (fs::ReadFile(i.second.path, data)) {
3996                                 translations->loadTranslation(data);
3997                         }
3998                 }
3999         }
4000
4001         return translations;
4002 }
4003
4004 ModStorageDatabase *Server::openModStorageDatabase(const std::string &world_path)
4005 {
4006         std::string world_mt_path = world_path + DIR_DELIM + "world.mt";
4007         Settings world_mt;
4008         if (!world_mt.readConfigFile(world_mt_path.c_str()))
4009                 throw BaseException("Cannot read world.mt!");
4010
4011         std::string backend = world_mt.exists("mod_storage_backend") ?
4012                 world_mt.get("mod_storage_backend") : "files";
4013         if (backend == "files")
4014                 warningstream << "/!\\ You are using the old mod storage files backend. "
4015                         << "This backend is deprecated and may be removed in a future release /!\\"
4016                         << std::endl << "Switching to SQLite3 is advised, "
4017                         << "please read http://wiki.minetest.net/Database_backends." << std::endl;
4018
4019         return openModStorageDatabase(backend, world_path, world_mt);
4020 }
4021
4022 ModStorageDatabase *Server::openModStorageDatabase(const std::string &backend,
4023                 const std::string &world_path, const Settings &world_mt)
4024 {
4025         if (backend == "sqlite3")
4026                 return new ModStorageDatabaseSQLite3(world_path);
4027
4028 #if USE_POSTGRESQL
4029         if (backend == "postgresql") {
4030                 std::string connect_string;
4031                 world_mt.getNoEx("pgsql_mod_storage_connection", connect_string);
4032                 return new ModStorageDatabasePostgreSQL(connect_string);
4033         }
4034 #endif // USE_POSTGRESQL
4035
4036         if (backend == "files")
4037                 return new ModStorageDatabaseFiles(world_path);
4038
4039         if (backend == "dummy")
4040                 return new Database_Dummy();
4041
4042         throw BaseException("Mod storage database backend " + backend + " not supported");
4043 }
4044
4045 bool Server::migrateModStorageDatabase(const GameParams &game_params, const Settings &cmd_args)
4046 {
4047         std::string migrate_to = cmd_args.get("migrate-mod-storage");
4048         Settings world_mt;
4049         std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt";
4050         if (!world_mt.readConfigFile(world_mt_path.c_str())) {
4051                 errorstream << "Cannot read world.mt!" << std::endl;
4052                 return false;
4053         }
4054
4055         std::string backend = world_mt.exists("mod_storage_backend") ?
4056                 world_mt.get("mod_storage_backend") : "files";
4057         if (backend == migrate_to) {
4058                 errorstream << "Cannot migrate: new backend is same"
4059                         << " as the old one" << std::endl;
4060                 return false;
4061         }
4062
4063         ModStorageDatabase *srcdb = nullptr;
4064         ModStorageDatabase *dstdb = nullptr;
4065
4066         bool succeeded = false;
4067
4068         try {
4069                 srcdb = Server::openModStorageDatabase(backend, game_params.world_path, world_mt);
4070                 dstdb = Server::openModStorageDatabase(migrate_to, game_params.world_path, world_mt);
4071
4072                 dstdb->beginSave();
4073
4074                 std::vector<std::string> mod_list;
4075                 srcdb->listMods(&mod_list);
4076                 for (const std::string &modname : mod_list) {
4077                         StringMap meta;
4078                         srcdb->getModEntries(modname, &meta);
4079                         for (const auto &pair : meta) {
4080                                 dstdb->setModEntry(modname, pair.first, pair.second);
4081                         }
4082                 }
4083
4084                 dstdb->endSave();
4085
4086                 succeeded = true;
4087
4088                 actionstream << "Successfully migrated the metadata of "
4089                         << mod_list.size() << " mods" << std::endl;
4090                 world_mt.set("mod_storage_backend", migrate_to);
4091                 if (!world_mt.updateConfigFile(world_mt_path.c_str()))
4092                         errorstream << "Failed to update world.mt!" << std::endl;
4093                 else
4094                         actionstream << "world.mt updated" << std::endl;
4095
4096         } catch (BaseException &e) {
4097                 errorstream << "An error occurred during migration: " << e.what() << std::endl;
4098         }
4099
4100         delete srcdb;
4101         delete dstdb;
4102
4103         if (succeeded && backend == "files") {
4104                 // Back up files
4105                 const std::string storage_path = game_params.world_path + DIR_DELIM + "mod_storage";
4106                 const std::string backup_path = game_params.world_path + DIR_DELIM + "mod_storage.bak";
4107                 if (!fs::Rename(storage_path, backup_path))
4108                         warningstream << "After migration, " << storage_path
4109                                 << " could not be renamed to " << backup_path << std::endl;
4110         }
4111
4112         return succeeded;
4113 }