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