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