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