3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "server/serveractiveobject.h"
41 #include "scripting_server.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"
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"
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"
70 class ClientNotFoundException : public BaseException
73 ClientNotFoundException(const char *s):
78 class ServerThread : public Thread
82 ServerThread(Server *server):
93 void *ServerThread::run()
95 BEGIN_DEBUG_EXCEPTION_HANDLER
98 * The real business of the server happens on the ServerThread.
100 * AsyncRunStep() runs an actual server step as soon as enough time has
101 * passed (dedicated_server_loop keeps track of that).
102 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
103 * doesn't busy wait) and will process any remaining packets.
106 m_server->AsyncRunStep(true);
108 while (!stopRequested()) {
110 m_server->AsyncRunStep();
114 } catch (con::PeerNotFoundException &e) {
115 infostream<<"Server: PeerNotFoundException"<<std::endl;
116 } catch (ClientNotFoundException &e) {
117 } catch (con::ConnectionBindFailed &e) {
118 m_server->setAsyncFatalError(e.what());
119 } catch (LuaError &e) {
120 m_server->setAsyncFatalError(
121 "ServerThread::run Lua: " + std::string(e.what()));
125 END_DEBUG_EXCEPTION_HANDLER
130 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
132 if(pos_exists) *pos_exists = false;
137 if(pos_exists) *pos_exists = true;
142 ServerActiveObject *sao = env->getActiveObject(object);
145 if(pos_exists) *pos_exists = true;
146 return sao->getBasePosition(); }
151 void Server::ShutdownState::reset()
155 should_reconnect = false;
156 is_requested = false;
159 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
163 should_reconnect = reconnect;
166 void Server::ShutdownState::tick(float dtime, Server *server)
172 static const float shutdown_msg_times[] =
174 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
177 // Automated messages
178 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
179 for (float t : shutdown_msg_times) {
180 // If shutdown timer matches an automessage, shot it
181 if (m_timer > t && m_timer - dtime < t) {
182 std::wstring periodicMsg = getShutdownTimerMessage();
184 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
185 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
192 if (m_timer < 0.0f) {
198 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
200 std::wstringstream ws;
201 ws << L"*** Server shutting down in "
202 << duration_to_string(myround(m_timer)).c_str() << ".";
211 const std::string &path_world,
212 const SubgameSpec &gamespec,
213 bool simple_singleplayer_mode,
216 ChatInterface *iface,
217 std::string *on_shutdown_errmsg
219 m_bind_addr(bind_addr),
220 m_path_world(path_world),
221 m_gamespec(gamespec),
222 m_simple_singleplayer_mode(simple_singleplayer_mode),
223 m_dedicated(dedicated),
224 m_async_fatal_error(""),
225 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
228 m_bind_addr.isIPv6(),
230 m_itemdef(createItemDefManager()),
231 m_nodedef(createNodeDefManager()),
232 m_craftdef(createCraftDefManager()),
233 m_thread(new ServerThread(this)),
236 m_on_shutdown_errmsg(on_shutdown_errmsg),
237 m_modchannel_mgr(new ModChannelMgr())
239 if (m_path_world.empty())
240 throw ServerError("Supplied empty world path");
242 if (!gamespec.isValid())
243 throw ServerError("Supplied invalid gamespec");
246 m_metrics_backend = std::unique_ptr<MetricsBackend>(createPrometheusMetricsBackend());
248 m_metrics_backend = std::unique_ptr<MetricsBackend>(new MetricsBackend());
251 m_uptime_counter = m_metrics_backend->addCounter("minetest_core_server_uptime", "Server uptime (in seconds)");
252 m_player_gauge = m_metrics_backend->addGauge("minetest_core_player_number", "Number of connected players");
254 m_timeofday_gauge = m_metrics_backend->addGauge(
255 "minetest_core_timeofday",
256 "Time of day value");
258 m_lag_gauge = m_metrics_backend->addGauge(
259 "minetest_core_latency",
260 "Latency value (in seconds)");
262 m_aom_buffer_counter = m_metrics_backend->addCounter(
263 "minetest_core_aom_generated_count",
264 "Number of active object messages generated");
266 m_packet_recv_counter = m_metrics_backend->addCounter(
267 "minetest_core_server_packet_recv",
268 "Processable packets received");
270 m_packet_recv_processed_counter = m_metrics_backend->addCounter(
271 "minetest_core_server_packet_recv_processed",
272 "Valid received packets processed");
274 m_lag_gauge->set(g_settings->getFloat("dedicated_server_step"));
280 // Send shutdown message
281 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
282 L"*** Server shutting down"));
285 MutexAutoLock envlock(m_env_mutex);
287 infostream << "Server: Saving players" << std::endl;
288 m_env->saveLoadedPlayers();
290 infostream << "Server: Kicking players" << std::endl;
291 std::string kick_msg;
292 bool reconnect = false;
293 if (isShutdownRequested()) {
294 reconnect = m_shutdown_state.should_reconnect;
295 kick_msg = m_shutdown_state.message;
297 if (kick_msg.empty()) {
298 kick_msg = g_settings->get("kick_msg_shutdown");
300 m_env->saveLoadedPlayers(true);
301 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
302 kick_msg, reconnect);
305 actionstream << "Server: Shutting down" << std::endl;
307 // Do this before stopping the server in case mapgen callbacks need to access
308 // server-controlled resources (like ModStorages). Also do them before
309 // shutdown callbacks since they may modify state that is finalized in a
312 m_emerge->stopThreads();
315 MutexAutoLock envlock(m_env_mutex);
317 // Execute script shutdown hooks
318 infostream << "Executing shutdown hooks" << std::endl;
320 m_script->on_shutdown();
321 } catch (ModError &e) {
322 errorstream << "ModError: " << e.what() << std::endl;
323 if (m_on_shutdown_errmsg) {
324 if (m_on_shutdown_errmsg->empty()) {
325 *m_on_shutdown_errmsg = std::string("ModError: ") + e.what();
327 *m_on_shutdown_errmsg += std::string("\nModError: ") + e.what();
332 infostream << "Server: Saving environment metadata" << std::endl;
342 // Delete things in the reverse order of creation
351 // Deinitialize scripting
352 infostream << "Server: Deinitializing scripting" << std::endl;
354 delete m_startup_server_map; // if available
355 delete m_game_settings;
357 while (!m_unsent_map_edit_queue.empty()) {
358 delete m_unsent_map_edit_queue.front();
359 m_unsent_map_edit_queue.pop();
365 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
366 if (m_simple_singleplayer_mode)
367 infostream << " in simple singleplayer mode" << std::endl;
369 infostream << std::endl;
370 infostream << "- world: " << m_path_world << std::endl;
371 infostream << "- game: " << m_gamespec.path << std::endl;
373 m_game_settings = Settings::createLayer(SL_GAME);
375 // Create world if it doesn't exist
377 loadGameConfAndInitWorld(m_path_world,
378 fs::GetFilenameFromPath(m_path_world.c_str()),
380 } catch (const BaseException &e) {
381 throw ServerError(std::string("Failed to initialize world: ") + e.what());
384 // Create emerge manager
385 m_emerge = new EmergeManager(this);
387 // Create ban manager
388 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
389 m_banmanager = new BanManager(ban_path);
391 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
392 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
393 // complain about mods with unsatisfied dependencies
394 if (!m_modmgr->isConsistent()) {
395 m_modmgr->printUnsatisfiedModsError();
399 MutexAutoLock envlock(m_env_mutex);
401 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
402 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge, m_metrics_backend.get());
403 m_startup_server_map = servermap;
405 // Initialize scripting
406 infostream << "Server: Initializing Lua" << std::endl;
408 m_script = new ServerScripting(this);
410 // Must be created before mod loading because we have some inventory creation
411 m_inventory_mgr = std::unique_ptr<ServerInventoryManager>(new ServerInventoryManager());
413 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
415 m_modmgr->loadMods(m_script);
417 // Read Textures and calculate sha1 sums
420 // Apply item aliases in the node definition manager
421 m_nodedef->updateAliases(m_itemdef);
423 // Apply texture overrides from texturepack/override.txt
424 std::vector<std::string> paths;
425 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
426 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
427 for (const std::string &path : paths) {
428 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
429 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
430 m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
433 m_nodedef->setNodeRegistrationStatus(true);
435 // Perform pending node name resolutions
436 m_nodedef->runNodeResolveCallbacks();
438 // unmap node names in cross-references
439 m_nodedef->resolveCrossrefs();
441 // init the recipe hashes to speed up crafting
442 m_craftdef->initHashes(this);
444 // Initialize Environment
445 m_startup_server_map = nullptr; // Ownership moved to ServerEnvironment
446 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
448 m_inventory_mgr->setEnv(m_env);
449 m_clients.setEnv(m_env);
451 if (!servermap->settings_mgr.makeMapgenParams())
452 FATAL_ERROR("Couldn't create any mapgen type");
454 // Initialize mapgens
455 m_emerge->initMapgens(servermap->getMapgenParams());
457 if (g_settings->getBool("enable_rollback_recording")) {
458 // Create rollback manager
459 m_rollback = new RollbackManager(m_path_world, this);
462 // Give environment reference to scripting api
463 m_script->initializeEnvironment(m_env);
465 // Register us to receive map edit events
466 servermap->addEventReceiver(this);
470 // Those settings can be overwritten in world.mt, they are
471 // intended to be cached after environment loading.
472 m_liquid_transform_every = g_settings->getFloat("liquid_update");
473 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
474 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
475 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
482 infostream << "Starting server on " << m_bind_addr.serializeString()
483 << "..." << std::endl;
485 // Stop thread if already running
488 // Initialize connection
489 m_con->SetTimeoutMs(30);
490 m_con->Serve(m_bind_addr);
495 // ASCII art for the win!
497 << " .__ __ __ " << std::endl
498 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
499 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
500 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
501 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
502 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
503 actionstream << "World at [" << m_path_world << "]" << std::endl;
504 actionstream << "Server for gameid=\"" << m_gamespec.id
505 << "\" listening on " << m_bind_addr.serializeString() << ":"
506 << m_bind_addr.getPort() << "." << std::endl;
511 infostream<<"Server: Stopping and waiting threads"<<std::endl;
513 // Stop threads (set run=false first so both start stopping)
515 //m_emergethread.setRun(false);
517 //m_emergethread.stop();
519 infostream<<"Server: Threads stopped"<<std::endl;
522 void Server::step(float dtime)
528 MutexAutoLock lock(m_step_dtime_mutex);
529 m_step_dtime += dtime;
531 // Throw if fatal error occurred in thread
532 std::string async_err = m_async_fatal_error.get();
533 if (!async_err.empty()) {
534 if (!m_simple_singleplayer_mode) {
535 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
536 g_settings->get("kick_msg_crash"),
537 g_settings->getBool("ask_reconnect_on_crash"));
539 throw ServerError("AsyncErr: " + async_err);
543 void Server::AsyncRunStep(bool initial_step)
548 MutexAutoLock lock1(m_step_dtime_mutex);
549 dtime = m_step_dtime;
553 // Send blocks to clients
557 if((dtime < 0.001) && !initial_step)
560 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
563 MutexAutoLock lock1(m_step_dtime_mutex);
564 m_step_dtime -= dtime;
570 m_uptime_counter->increment(dtime);
575 Update time of day and overall game time
577 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
580 Send to clients at constant intervals
583 m_time_of_day_send_timer -= dtime;
584 if (m_time_of_day_send_timer < 0.0) {
585 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
586 u16 time = m_env->getTimeOfDay();
587 float time_speed = g_settings->getFloat("time_speed");
588 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
590 m_timeofday_gauge->set(time);
594 MutexAutoLock lock(m_env_mutex);
595 // Figure out and report maximum lag to environment
596 float max_lag = m_env->getMaxLagEstimate();
597 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
599 if(dtime > 0.1 && dtime > max_lag * 2.0)
600 infostream<<"Server: Maximum lag peaked to "<<dtime
604 m_env->reportMaxLagEstimate(max_lag);
609 static const float map_timer_and_unload_dtime = 2.92;
610 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
612 MutexAutoLock lock(m_env_mutex);
613 // Run Map's timers and unload unused data
614 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
615 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
616 g_settings->getFloat("server_unload_unused_data_timeout"),
621 Listen to the admin chat, if available
624 if (!m_admin_chat->command_queue.empty()) {
625 MutexAutoLock lock(m_env_mutex);
626 while (!m_admin_chat->command_queue.empty()) {
627 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
628 handleChatInterfaceEvent(evt);
632 m_admin_chat->outgoing_queue.push_back(
633 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
640 /* Transform liquids */
641 m_liquid_transform_timer += dtime;
642 if(m_liquid_transform_timer >= m_liquid_transform_every)
644 m_liquid_transform_timer -= m_liquid_transform_every;
646 MutexAutoLock lock(m_env_mutex);
648 ScopeProfiler sp(g_profiler, "Server: liquid transform");
650 std::map<v3s16, MapBlock*> modified_blocks;
651 m_env->getMap().transformLiquids(modified_blocks, m_env);
654 Set the modified blocks unsent for all the clients
656 if (!modified_blocks.empty()) {
657 SetBlocksNotSent(modified_blocks);
660 m_clients.step(dtime);
662 // increase/decrease lag gauge gradually
663 if (m_lag_gauge->get() > dtime) {
664 m_lag_gauge->decrement(dtime/100);
666 m_lag_gauge->increment(dtime/100);
670 float &counter = m_step_pending_dyn_media_timer;
672 if (counter >= 5.0f) {
673 stepPendingDynMediaCallbacks(counter);
680 // send masterserver announce
682 float &counter = m_masterserver_timer;
683 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
684 g_settings->getBool("server_announce")) {
685 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
686 ServerList::AA_START,
687 m_bind_addr.getPort(),
688 m_clients.getPlayerNames(),
689 m_uptime_counter->get(),
690 m_env->getGameTime(),
693 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
703 Check added and deleted active objects
706 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
707 MutexAutoLock envlock(m_env_mutex);
710 const RemoteClientMap &clients = m_clients.getClientList();
711 ScopeProfiler sp(g_profiler, "Server: update objects within range");
713 m_player_gauge->set(clients.size());
714 for (const auto &client_it : clients) {
715 RemoteClient *client = client_it.second;
717 if (client->getState() < CS_DefinitionsSent)
720 // This can happen if the client times out somehow
721 if (!m_env->getPlayer(client->peer_id))
724 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
728 SendActiveObjectRemoveAdd(client, playersao);
732 // Save mod storages if modified
733 m_mod_storage_save_timer -= dtime;
734 if (m_mod_storage_save_timer <= 0.0f) {
735 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
737 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
738 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
739 if (it->second->isModified()) {
740 it->second->save(getModStoragePath());
745 infostream << "Saved " << n << " modified mod storages." << std::endl;
753 MutexAutoLock envlock(m_env_mutex);
754 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
757 // Value = data sent by object
758 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
760 // Get active object messages from environment
761 ActiveObjectMessage aom(0);
764 if (!m_env->getActiveObjectMessage(&aom))
767 std::vector<ActiveObjectMessage>* message_list = nullptr;
768 auto n = buffered_messages.find(aom.id);
769 if (n == buffered_messages.end()) {
770 message_list = new std::vector<ActiveObjectMessage>;
771 buffered_messages[aom.id] = message_list;
773 message_list = n->second;
775 message_list->push_back(std::move(aom));
779 m_aom_buffer_counter->increment(aom_count);
782 const RemoteClientMap &clients = m_clients.getClientList();
783 // Route data to every client
784 std::string reliable_data, unreliable_data;
785 for (const auto &client_it : clients) {
786 reliable_data.clear();
787 unreliable_data.clear();
788 RemoteClient *client = client_it.second;
789 PlayerSAO *player = getPlayerSAO(client->peer_id);
790 // Go through all objects in message buffer
791 for (const auto &buffered_message : buffered_messages) {
792 // If object does not exist or is not known by client, skip it
793 u16 id = buffered_message.first;
794 ServerActiveObject *sao = m_env->getActiveObject(id);
795 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
798 // Get message list of object
799 std::vector<ActiveObjectMessage>* list = buffered_message.second;
800 // Go through every message
801 for (const ActiveObjectMessage &aom : *list) {
802 // Send position updates to players who do not see the attachment
803 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
804 if (sao->getId() == player->getId())
807 // Do not send position updates for attached players
808 // as long the parent is known to the client
809 ServerActiveObject *parent = sao->getParent();
810 if (parent && client->m_known_objects.find(parent->getId()) !=
811 client->m_known_objects.end())
815 // Add full new data to appropriate buffer
816 std::string &buffer = aom.reliable ? reliable_data : unreliable_data;
818 writeU16((u8*) idbuf, aom.id);
821 buffer.append(idbuf, sizeof(idbuf));
822 buffer.append(serializeString16(aom.datastring));
826 reliable_data and unreliable_data are now ready.
829 if (!reliable_data.empty()) {
830 SendActiveObjectMessages(client->peer_id, reliable_data);
833 if (!unreliable_data.empty()) {
834 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
839 // Clear buffered_messages
840 for (auto &buffered_message : buffered_messages) {
841 delete buffered_message.second;
846 Send queued-for-sending map edit events.
849 // We will be accessing the environment
850 MutexAutoLock lock(m_env_mutex);
852 // Don't send too many at a time
855 // Single change sending is disabled if queue size is not small
856 bool disable_single_change_sending = false;
857 if(m_unsent_map_edit_queue.size() >= 4)
858 disable_single_change_sending = true;
860 int event_count = m_unsent_map_edit_queue.size();
862 // We'll log the amount of each
865 std::list<v3s16> node_meta_updates;
867 while (!m_unsent_map_edit_queue.empty()) {
868 MapEditEvent* event = m_unsent_map_edit_queue.front();
869 m_unsent_map_edit_queue.pop();
871 // Players far away from the change are stored here.
872 // Instead of sending the changes, MapBlocks are set not sent
874 std::unordered_set<u16> far_players;
876 switch (event->type) {
879 prof.add("MEET_ADDNODE", 1);
880 sendAddNode(event->p, event->n, &far_players,
881 disable_single_change_sending ? 5 : 30,
882 event->type == MEET_ADDNODE);
884 case MEET_REMOVENODE:
885 prof.add("MEET_REMOVENODE", 1);
886 sendRemoveNode(event->p, &far_players,
887 disable_single_change_sending ? 5 : 30);
889 case MEET_BLOCK_NODE_METADATA_CHANGED: {
890 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
891 if (!event->is_private_change) {
892 // Don't send the change yet. Collect them to eliminate dupes.
893 node_meta_updates.remove(event->p);
894 node_meta_updates.push_back(event->p);
897 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
898 getNodeBlockPos(event->p))) {
899 block->raiseModified(MOD_STATE_WRITE_NEEDED,
900 MOD_REASON_REPORT_META_CHANGE);
905 prof.add("MEET_OTHER", 1);
906 for (const v3s16 &modified_block : event->modified_blocks) {
907 m_clients.markBlockposAsNotSent(modified_block);
911 prof.add("unknown", 1);
912 warningstream << "Server: Unknown MapEditEvent "
913 << ((u32)event->type) << std::endl;
918 Set blocks not sent to far players
920 if (!far_players.empty()) {
921 // Convert list format to that wanted by SetBlocksNotSent
922 std::map<v3s16, MapBlock*> modified_blocks2;
923 for (const v3s16 &modified_block : event->modified_blocks) {
924 modified_blocks2[modified_block] =
925 m_env->getMap().getBlockNoCreateNoEx(modified_block);
928 // Set blocks not sent
929 for (const u16 far_player : far_players) {
930 if (RemoteClient *client = getClient(far_player))
931 client->SetBlocksNotSent(modified_blocks2);
938 if (event_count >= 5) {
939 infostream << "Server: MapEditEvents:" << std::endl;
940 prof.print(infostream);
941 } else if (event_count != 0) {
942 verbosestream << "Server: MapEditEvents:" << std::endl;
943 prof.print(verbosestream);
946 // Send all metadata updates
947 if (node_meta_updates.size())
948 sendMetadataChanged(node_meta_updates);
952 Trigger emergethread (it somehow gets to a non-triggered but
953 bysy state sometimes)
956 float &counter = m_emergethread_trigger_timer;
958 if (counter >= 2.0) {
961 m_emerge->startThreads();
965 // Save map, players and auth stuff
967 float &counter = m_savemap_timer;
969 static thread_local const float save_interval =
970 g_settings->getFloat("server_map_save_interval");
971 if (counter >= save_interval) {
973 MutexAutoLock lock(m_env_mutex);
975 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
978 if (m_banmanager->isModified()) {
979 m_banmanager->save();
982 // Save changed parts of map
983 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
986 m_env->saveLoadedPlayers();
988 // Save environment metadata
993 m_shutdown_state.tick(dtime, this);
996 void Server::Receive()
1006 In the first iteration *wait* for a packet, afterwards process
1007 all packets that are immediately available (no waiting).
1010 m_con->Receive(&pkt);
1013 if (!m_con->TryReceive(&pkt))
1017 peer_id = pkt.getPeerId();
1018 m_packet_recv_counter->increment();
1020 m_packet_recv_processed_counter->increment();
1021 } catch (const con::InvalidIncomingDataException &e) {
1022 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1023 << e.what() << std::endl;
1024 } catch (const SerializationError &e) {
1025 infostream << "Server::Receive(): SerializationError: what()="
1026 << e.what() << std::endl;
1027 } catch (const ClientStateError &e) {
1028 errorstream << "ProcessData: peer=" << peer_id << " what()="
1029 << e.what() << std::endl;
1030 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1031 L"Try reconnecting or updating your client");
1032 } catch (const con::PeerNotFoundException &e) {
1034 } catch (const con::NoIncomingDataException &e) {
1040 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1042 std::string playername;
1043 PlayerSAO *playersao = NULL;
1046 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1048 playername = client->getName();
1049 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1051 } catch (std::exception &e) {
1057 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1059 // If failed, cancel
1060 if (!playersao || !player) {
1061 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1062 actionstream << "Server: Failed to emerge player \"" << playername
1063 << "\" (player allocated to an another client)" << std::endl;
1064 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1065 L"name. If your client closed unexpectedly, try again in "
1068 errorstream << "Server: " << playername << ": Failed to emerge player"
1070 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1076 Send complete position information
1078 SendMovePlayer(peer_id);
1081 SendPlayerPrivileges(peer_id);
1083 // Send inventory formspec
1084 SendPlayerInventoryFormspec(peer_id);
1087 SendInventory(playersao, false);
1089 // Send HP or death screen
1090 if (playersao->isDead())
1091 SendDeathscreen(peer_id, false, v3f(0,0,0));
1093 SendPlayerHP(peer_id);
1096 SendPlayerBreath(playersao);
1102 Address addr = getPeerAddress(player->getPeerId());
1103 std::string ip_str = addr.serializeString();
1104 const std::vector<std::string> &names = m_clients.getPlayerNames();
1106 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1108 for (const std::string &name : names) {
1109 actionstream << name << " ";
1112 actionstream << player->getName() <<std::endl;
1117 inline void Server::handleCommand(NetworkPacket *pkt)
1119 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1120 (this->*opHandle.handler)(pkt);
1123 void Server::ProcessData(NetworkPacket *pkt)
1125 // Environment is locked first.
1126 MutexAutoLock envlock(m_env_mutex);
1128 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1129 u32 peer_id = pkt->getPeerId();
1132 Address address = getPeerAddress(peer_id);
1133 std::string addr_s = address.serializeString();
1135 if(m_banmanager->isIpBanned(addr_s)) {
1136 std::string ban_name = m_banmanager->getBanName(addr_s);
1137 infostream << "Server: A banned client tried to connect from "
1138 << addr_s << "; banned name was "
1139 << ban_name << std::endl;
1140 // This actually doesn't seem to transfer to the client
1141 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1142 + utf8_to_wide(ban_name));
1146 catch(con::PeerNotFoundException &e) {
1148 * no peer for this packet found
1149 * most common reason is peer timeout, e.g. peer didn't
1150 * respond for some time, your server was overloaded or
1153 infostream << "Server::ProcessData(): Canceling: peer "
1154 << peer_id << " not found" << std::endl;
1159 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1161 // Command must be handled into ToServerCommandHandler
1162 if (command >= TOSERVER_NUM_MSG_TYPES) {
1163 infostream << "Server: Ignoring unknown command "
1164 << command << std::endl;
1168 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1173 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1175 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1176 errorstream << "Server::ProcessData(): Cancelling: Peer"
1177 " serialization format invalid or not initialized."
1178 " Skipping incoming command=" << command << std::endl;
1182 /* Handle commands related to client startup */
1183 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1188 if (m_clients.getClientState(peer_id) < CS_Active) {
1189 if (command == TOSERVER_PLAYERPOS) return;
1191 errorstream << "Got packet command: " << command << " for peer id "
1192 << peer_id << " but client isn't active yet. Dropping packet "
1198 } catch (SendFailedException &e) {
1199 errorstream << "Server::ProcessData(): SendFailedException: "
1200 << "what=" << e.what()
1202 } catch (PacketError &e) {
1203 actionstream << "Server::ProcessData(): PacketError: "
1204 << "what=" << e.what()
1209 void Server::setTimeOfDay(u32 time)
1211 m_env->setTimeOfDay(time);
1212 m_time_of_day_send_timer = 0;
1215 void Server::onMapEditEvent(const MapEditEvent &event)
1217 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1220 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1223 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1225 std::vector<session_t> clients = m_clients.getClientIDs();
1227 // Set the modified blocks unsent for all the clients
1228 for (const session_t client_id : clients) {
1229 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1230 client->SetBlocksNotSent(block);
1235 void Server::peerAdded(con::Peer *peer)
1237 verbosestream<<"Server::peerAdded(): peer->id="
1238 <<peer->id<<std::endl;
1240 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1243 void Server::deletingPeer(con::Peer *peer, bool timeout)
1245 verbosestream<<"Server::deletingPeer(): peer->id="
1246 <<peer->id<<", timeout="<<timeout<<std::endl;
1248 m_clients.event(peer->id, CSE_Disconnect);
1249 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1252 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1254 *retval = m_con->getPeerStat(peer_id,type);
1255 return *retval != -1;
1258 bool Server::getClientInfo(session_t peer_id, ClientInfo &ret)
1261 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1268 ret.state = client->getState();
1269 ret.addr = client->getAddress();
1270 ret.uptime = client->uptime();
1271 ret.ser_vers = client->serialization_version;
1272 ret.prot_vers = client->net_proto_version;
1274 ret.major = client->getMajor();
1275 ret.minor = client->getMinor();
1276 ret.patch = client->getPatch();
1277 ret.vers_string = client->getFullVer();
1279 ret.lang_code = client->getLangCode();
1286 void Server::handlePeerChanges()
1288 while(!m_peer_change_queue.empty())
1290 con::PeerChange c = m_peer_change_queue.front();
1291 m_peer_change_queue.pop();
1293 verbosestream<<"Server: Handling peer change: "
1294 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1299 case con::PEER_ADDED:
1300 m_clients.CreateClient(c.peer_id);
1303 case con::PEER_REMOVED:
1304 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1308 FATAL_ERROR("Invalid peer change event received!");
1314 void Server::printToConsoleOnly(const std::string &text)
1317 m_admin_chat->outgoing_queue.push_back(
1318 new ChatEventChat("", utf8_to_wide(text)));
1320 std::cout << text << std::endl;
1324 void Server::Send(NetworkPacket *pkt)
1326 Send(pkt->getPeerId(), pkt);
1329 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1331 m_clients.send(peer_id,
1332 clientCommandFactoryTable[pkt->getCommand()].channel,
1334 clientCommandFactoryTable[pkt->getCommand()].reliable);
1337 void Server::SendMovement(session_t peer_id)
1339 std::ostringstream os(std::ios_base::binary);
1341 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1343 pkt << g_settings->getFloat("movement_acceleration_default");
1344 pkt << g_settings->getFloat("movement_acceleration_air");
1345 pkt << g_settings->getFloat("movement_acceleration_fast");
1346 pkt << g_settings->getFloat("movement_speed_walk");
1347 pkt << g_settings->getFloat("movement_speed_crouch");
1348 pkt << g_settings->getFloat("movement_speed_fast");
1349 pkt << g_settings->getFloat("movement_speed_climb");
1350 pkt << g_settings->getFloat("movement_speed_jump");
1351 pkt << g_settings->getFloat("movement_liquid_fluidity");
1352 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1353 pkt << g_settings->getFloat("movement_liquid_sink");
1354 pkt << g_settings->getFloat("movement_gravity");
1359 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1361 if (playersao->isImmortal())
1364 session_t peer_id = playersao->getPeerID();
1365 bool is_alive = !playersao->isDead();
1368 SendPlayerHP(peer_id);
1370 DiePlayer(peer_id, reason);
1373 void Server::SendHP(session_t peer_id, u16 hp)
1375 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1380 void Server::SendBreath(session_t peer_id, u16 breath)
1382 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1383 pkt << (u16) breath;
1387 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1388 const std::string &custom_reason, bool reconnect)
1390 assert(reason < SERVER_ACCESSDENIED_MAX);
1392 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1394 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1395 pkt << custom_reason;
1396 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1397 reason == SERVER_ACCESSDENIED_CRASH)
1398 pkt << custom_reason << (u8)reconnect;
1402 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1404 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1409 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1410 v3f camera_point_target)
1412 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1413 pkt << set_camera_point_target << camera_point_target;
1417 void Server::SendItemDef(session_t peer_id,
1418 IItemDefManager *itemdef, u16 protocol_version)
1420 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1424 u32 length of the next item
1425 zlib-compressed serialized ItemDefManager
1427 std::ostringstream tmp_os(std::ios::binary);
1428 itemdef->serialize(tmp_os, protocol_version);
1429 std::ostringstream tmp_os2(std::ios::binary);
1430 compressZlib(tmp_os.str(), tmp_os2);
1431 pkt.putLongString(tmp_os2.str());
1434 verbosestream << "Server: Sending item definitions to id(" << peer_id
1435 << "): size=" << pkt.getSize() << std::endl;
1440 void Server::SendNodeDef(session_t peer_id,
1441 const NodeDefManager *nodedef, u16 protocol_version)
1443 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1447 u32 length of the next item
1448 zlib-compressed serialized NodeDefManager
1450 std::ostringstream tmp_os(std::ios::binary);
1451 nodedef->serialize(tmp_os, protocol_version);
1452 std::ostringstream tmp_os2(std::ios::binary);
1453 compressZlib(tmp_os.str(), tmp_os2);
1455 pkt.putLongString(tmp_os2.str());
1458 verbosestream << "Server: Sending node definitions to id(" << peer_id
1459 << "): size=" << pkt.getSize() << std::endl;
1465 Non-static send methods
1468 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1470 RemotePlayer *player = sao->getPlayer();
1472 // Do not send new format to old clients
1473 incremental &= player->protocol_version >= 38;
1475 UpdateCrafting(player);
1481 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1483 std::ostringstream os(std::ios::binary);
1484 sao->getInventory()->serialize(os, incremental);
1485 sao->getInventory()->setModified(false);
1486 player->setModified(true);
1488 const std::string &s = os.str();
1489 pkt.putRawString(s.c_str(), s.size());
1493 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1495 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1497 u8 type = message.type;
1498 pkt << version << type << message.sender << message.message
1499 << static_cast<u64>(message.timestamp);
1501 if (peer_id != PEER_ID_INEXISTENT) {
1502 RemotePlayer *player = m_env->getPlayer(peer_id);
1508 m_clients.sendToAll(&pkt);
1512 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1513 const std::string &formname)
1515 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1516 if (formspec.empty()){
1517 //the client should close the formspec
1518 //but make sure there wasn't another one open in meantime
1519 const auto it = m_formspec_state_data.find(peer_id);
1520 if (it != m_formspec_state_data.end() && it->second == formname) {
1521 m_formspec_state_data.erase(peer_id);
1523 pkt.putLongString("");
1525 m_formspec_state_data[peer_id] = formname;
1526 pkt.putLongString(formspec);
1533 // Spawns a particle on peer with peer_id
1534 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1535 const ParticleParameters &p)
1537 static thread_local const float radius =
1538 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1540 if (peer_id == PEER_ID_INEXISTENT) {
1541 std::vector<session_t> clients = m_clients.getClientIDs();
1542 const v3f pos = p.pos * BS;
1543 const float radius_sq = radius * radius;
1545 for (const session_t client_id : clients) {
1546 RemotePlayer *player = m_env->getPlayer(client_id);
1550 PlayerSAO *sao = player->getPlayerSAO();
1554 // Do not send to distant clients
1555 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1558 SendSpawnParticle(client_id, player->protocol_version, p);
1562 assert(protocol_version != 0);
1564 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1567 // NetworkPacket and iostreams are incompatible...
1568 std::ostringstream oss(std::ios_base::binary);
1569 p.serialize(oss, protocol_version);
1570 pkt.putRawString(oss.str());
1576 // Adds a ParticleSpawner on peer with peer_id
1577 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1578 const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1580 static thread_local const float radius =
1581 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1583 if (peer_id == PEER_ID_INEXISTENT) {
1584 std::vector<session_t> clients = m_clients.getClientIDs();
1585 const v3f pos = (p.minpos + p.maxpos) / 2.0f * BS;
1586 const float radius_sq = radius * radius;
1587 /* Don't send short-lived spawners to distant players.
1588 * This could be replaced with proper tracking at some point. */
1589 const bool distance_check = !attached_id && p.time <= 1.0f;
1591 for (const session_t client_id : clients) {
1592 RemotePlayer *player = m_env->getPlayer(client_id);
1596 if (distance_check) {
1597 PlayerSAO *sao = player->getPlayerSAO();
1600 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1604 SendAddParticleSpawner(client_id, player->protocol_version,
1605 p, attached_id, id);
1609 assert(protocol_version != 0);
1611 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1613 pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
1614 << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
1615 << p.minsize << p.maxsize << p.collisiondetection;
1617 pkt.putLongString(p.texture);
1619 pkt << id << p.vertical << p.collision_removal << attached_id;
1621 std::ostringstream os(std::ios_base::binary);
1622 p.animation.serialize(os, protocol_version);
1623 pkt.putRawString(os.str());
1625 pkt << p.glow << p.object_collision;
1626 pkt << p.node.param0 << p.node.param2 << p.node_tile;
1631 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1633 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1637 if (peer_id != PEER_ID_INEXISTENT)
1640 m_clients.sendToAll(&pkt);
1644 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1646 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1648 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1649 << form->text << form->number << form->item << form->dir
1650 << form->align << form->offset << form->world_pos << form->size
1651 << form->z_index << form->text2 << form->style;
1656 void Server::SendHUDRemove(session_t peer_id, u32 id)
1658 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1663 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1665 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1666 pkt << id << (u8) stat;
1670 case HUD_STAT_SCALE:
1671 case HUD_STAT_ALIGN:
1672 case HUD_STAT_OFFSET:
1673 pkt << *(v2f *) value;
1677 case HUD_STAT_TEXT2:
1678 pkt << *(std::string *) value;
1680 case HUD_STAT_WORLD_POS:
1681 pkt << *(v3f *) value;
1684 pkt << *(v2s32 *) value;
1686 default: // all other types
1687 pkt << *(u32 *) value;
1694 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1696 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1698 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1700 pkt << flags << mask;
1705 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1707 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1708 pkt << param << value;
1712 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1714 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1716 // Handle prior clients here
1717 if (m_clients.getProtocolVersion(peer_id) < 39) {
1718 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1720 for (const std::string& texture : params.textures)
1723 pkt << params.clouds;
1724 } else { // Handle current clients and future clients
1725 pkt << params.bgcolor << params.type
1726 << params.clouds << params.fog_sun_tint
1727 << params.fog_moon_tint << params.fog_tint_type;
1729 if (params.type == "skybox") {
1730 pkt << (u16) params.textures.size();
1731 for (const std::string &texture : params.textures)
1733 } else if (params.type == "regular") {
1734 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1735 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1736 << params.sky_color.night_sky << params.sky_color.night_horizon
1737 << params.sky_color.indoors;
1744 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1746 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1747 pkt << params.visible << params.texture
1748 << params.tonemap << params.sunrise
1749 << params.sunrise_visible << params.scale;
1753 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1755 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1757 pkt << params.visible << params.texture
1758 << params.tonemap << params.scale;
1762 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1764 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1766 pkt << params.visible << params.count
1767 << params.starcolor << params.scale;
1772 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1774 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1775 pkt << params.density << params.color_bright << params.color_ambient
1776 << params.height << params.thickness << params.speed;
1780 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1783 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1786 pkt << do_override << (u16) (ratio * 65535);
1791 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1793 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1794 pkt << time << time_speed;
1796 if (peer_id == PEER_ID_INEXISTENT) {
1797 m_clients.sendToAll(&pkt);
1804 void Server::SendPlayerHP(session_t peer_id)
1806 PlayerSAO *playersao = getPlayerSAO(peer_id);
1809 SendHP(peer_id, playersao->getHP());
1810 m_script->player_event(playersao,"health_changed");
1812 // Send to other clients
1813 playersao->sendPunchCommand();
1816 void Server::SendPlayerBreath(PlayerSAO *sao)
1820 m_script->player_event(sao, "breath_changed");
1821 SendBreath(sao->getPeerID(), sao->getBreath());
1824 void Server::SendMovePlayer(session_t peer_id)
1826 RemotePlayer *player = m_env->getPlayer(peer_id);
1828 PlayerSAO *sao = player->getPlayerSAO();
1831 // Send attachment updates instantly to the client prior updating position
1832 sao->sendOutdatedData();
1834 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1835 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1838 v3f pos = sao->getBasePosition();
1839 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1840 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1841 << " pitch=" << sao->getLookPitch()
1842 << " yaw=" << sao->getRotation().Y
1849 void Server::SendPlayerFov(session_t peer_id)
1851 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1853 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1854 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1859 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1860 f32 animation_speed)
1862 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1865 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1866 << animation_frames[3] << animation_speed;
1871 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1873 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1874 pkt << first << third;
1878 void Server::SendPlayerPrivileges(session_t peer_id)
1880 RemotePlayer *player = m_env->getPlayer(peer_id);
1882 if(player->getPeerId() == PEER_ID_INEXISTENT)
1885 std::set<std::string> privs;
1886 m_script->getAuth(player->getName(), NULL, &privs);
1888 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1889 pkt << (u16) privs.size();
1891 for (const std::string &priv : privs) {
1898 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1900 RemotePlayer *player = m_env->getPlayer(peer_id);
1902 if (player->getPeerId() == PEER_ID_INEXISTENT)
1905 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1906 pkt.putLongString(player->inventory_formspec);
1911 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1913 RemotePlayer *player = m_env->getPlayer(peer_id);
1915 if (player->getPeerId() == PEER_ID_INEXISTENT)
1918 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1919 pkt << player->formspec_prepend;
1923 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1925 // Radius inside which objects are active
1926 static thread_local const s16 radius =
1927 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1929 // Radius inside which players are active
1930 static thread_local const bool is_transfer_limited =
1931 g_settings->exists("unlimited_player_transfer_distance") &&
1932 !g_settings->getBool("unlimited_player_transfer_distance");
1934 static thread_local const s16 player_transfer_dist =
1935 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1937 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1938 radius : player_transfer_dist;
1940 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1944 std::queue<u16> removed_objects, added_objects;
1945 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1946 client->m_known_objects, removed_objects);
1947 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1948 client->m_known_objects, added_objects);
1950 int removed_count = removed_objects.size();
1951 int added_count = added_objects.size();
1953 if (removed_objects.empty() && added_objects.empty())
1959 // Handle removed objects
1960 writeU16((u8*)buf, removed_objects.size());
1961 data.append(buf, 2);
1962 while (!removed_objects.empty()) {
1964 u16 id = removed_objects.front();
1965 ServerActiveObject* obj = m_env->getActiveObject(id);
1967 // Add to data buffer for sending
1968 writeU16((u8*)buf, id);
1969 data.append(buf, 2);
1971 // Remove from known objects
1972 client->m_known_objects.erase(id);
1974 if (obj && obj->m_known_by_count > 0)
1975 obj->m_known_by_count--;
1977 removed_objects.pop();
1980 // Handle added objects
1981 writeU16((u8*)buf, added_objects.size());
1982 data.append(buf, 2);
1983 while (!added_objects.empty()) {
1985 u16 id = added_objects.front();
1986 ServerActiveObject *obj = m_env->getActiveObject(id);
1987 added_objects.pop();
1990 warningstream << FUNCTION_NAME << ": NULL object id="
1991 << (int)id << std::endl;
1996 u8 type = obj->getSendType();
1998 // Add to data buffer for sending
1999 writeU16((u8*)buf, id);
2000 data.append(buf, 2);
2001 writeU8((u8*)buf, type);
2002 data.append(buf, 1);
2004 data.append(serializeString32(
2005 obj->getClientInitializationData(client->net_proto_version)));
2007 // Add to known objects
2008 client->m_known_objects.insert(id);
2010 obj->m_known_by_count++;
2013 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2014 pkt.putRawString(data.c_str(), data.size());
2017 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2018 << removed_count << " removed, " << added_count << " added, "
2019 << "packet size is " << pkt.getSize() << std::endl;
2022 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2025 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2026 datas.size(), peer_id);
2028 pkt.putRawString(datas.c_str(), datas.size());
2030 m_clients.send(pkt.getPeerId(),
2031 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2035 void Server::SendCSMRestrictionFlags(session_t peer_id)
2037 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2038 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2039 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2043 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2045 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2050 inline s32 Server::nextSoundId()
2052 s32 ret = m_next_sound_id;
2053 if (m_next_sound_id == INT32_MAX)
2054 m_next_sound_id = 0; // signed overflow is undefined
2060 s32 Server::playSound(const SimpleSoundSpec &spec,
2061 const ServerSoundParams ¶ms, bool ephemeral)
2063 // Find out initial position of sound
2064 bool pos_exists = false;
2065 v3f pos = params.getPos(m_env, &pos_exists);
2066 // If position is not found while it should be, cancel sound
2067 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2070 // Filter destination clients
2071 std::vector<session_t> dst_clients;
2072 if (!params.to_player.empty()) {
2073 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2075 infostream<<"Server::playSound: Player \""<<params.to_player
2076 <<"\" not found"<<std::endl;
2079 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2080 infostream<<"Server::playSound: Player \""<<params.to_player
2081 <<"\" not connected"<<std::endl;
2084 dst_clients.push_back(player->getPeerId());
2086 std::vector<session_t> clients = m_clients.getClientIDs();
2088 for (const session_t client_id : clients) {
2089 RemotePlayer *player = m_env->getPlayer(client_id);
2092 if (!params.exclude_player.empty() &&
2093 params.exclude_player == player->getName())
2096 PlayerSAO *sao = player->getPlayerSAO();
2101 if(sao->getBasePosition().getDistanceFrom(pos) >
2102 params.max_hear_distance)
2105 dst_clients.push_back(client_id);
2109 if(dst_clients.empty())
2114 ServerPlayingSound *psound = nullptr;
2116 id = -1; // old clients will still use this, so pick a reserved ID
2119 // The sound will exist as a reference in m_playing_sounds
2120 m_playing_sounds[id] = ServerPlayingSound();
2121 psound = &m_playing_sounds[id];
2122 psound->params = params;
2123 psound->spec = spec;
2126 float gain = params.gain * spec.gain;
2127 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2128 pkt << id << spec.name << gain
2129 << (u8) params.type << pos << params.object
2130 << params.loop << params.fade << params.pitch
2133 bool as_reliable = !ephemeral;
2135 for (const u16 dst_client : dst_clients) {
2137 psound->clients.insert(dst_client);
2138 m_clients.send(dst_client, 0, &pkt, as_reliable);
2142 void Server::stopSound(s32 handle)
2144 // Get sound reference
2145 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2146 m_playing_sounds.find(handle);
2147 if (i == m_playing_sounds.end())
2149 ServerPlayingSound &psound = i->second;
2151 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2154 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2155 si != psound.clients.end(); ++si) {
2157 m_clients.send(*si, 0, &pkt, true);
2159 // Remove sound reference
2160 m_playing_sounds.erase(i);
2163 void Server::fadeSound(s32 handle, float step, float gain)
2165 // Get sound reference
2166 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2167 m_playing_sounds.find(handle);
2168 if (i == m_playing_sounds.end())
2171 ServerPlayingSound &psound = i->second;
2172 psound.params.gain = gain;
2174 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2175 pkt << handle << step << gain;
2177 // Backwards compability
2178 bool play_sound = gain > 0;
2179 ServerPlayingSound compat_psound = psound;
2180 compat_psound.clients.clear();
2182 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2183 compat_pkt << handle;
2185 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2186 it != psound.clients.end();) {
2187 if (m_clients.getProtocolVersion(*it) >= 32) {
2189 m_clients.send(*it, 0, &pkt, true);
2192 compat_psound.clients.insert(*it);
2194 m_clients.send(*it, 0, &compat_pkt, true);
2195 psound.clients.erase(it++);
2199 // Remove sound reference
2200 if (!play_sound || psound.clients.empty())
2201 m_playing_sounds.erase(i);
2203 if (play_sound && !compat_psound.clients.empty()) {
2204 // Play new sound volume on older clients
2205 playSound(compat_psound.spec, compat_psound.params);
2209 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2212 float maxd = far_d_nodes * BS;
2213 v3f p_f = intToFloat(p, BS);
2214 v3s16 block_pos = getNodeBlockPos(p);
2216 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2219 std::vector<session_t> clients = m_clients.getClientIDs();
2222 for (session_t client_id : clients) {
2223 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2227 RemotePlayer *player = m_env->getPlayer(client_id);
2228 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2230 // If player is far away, only set modified blocks not sent
2231 if (!client->isBlockSent(block_pos) || (sao &&
2232 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2234 far_players->emplace(client_id);
2236 client->SetBlockNotSent(block_pos);
2241 m_clients.send(client_id, 0, &pkt, true);
2247 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2248 float far_d_nodes, bool remove_metadata)
2250 float maxd = far_d_nodes * BS;
2251 v3f p_f = intToFloat(p, BS);
2252 v3s16 block_pos = getNodeBlockPos(p);
2254 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2255 pkt << p << n.param0 << n.param1 << n.param2
2256 << (u8) (remove_metadata ? 0 : 1);
2258 std::vector<session_t> clients = m_clients.getClientIDs();
2261 for (session_t client_id : clients) {
2262 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2266 RemotePlayer *player = m_env->getPlayer(client_id);
2267 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2269 // If player is far away, only set modified blocks not sent
2270 if (!client->isBlockSent(block_pos) || (sao &&
2271 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2273 far_players->emplace(client_id);
2275 client->SetBlockNotSent(block_pos);
2280 m_clients.send(client_id, 0, &pkt, true);
2286 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2288 float maxd = far_d_nodes * BS;
2289 NodeMetadataList meta_updates_list(false);
2290 std::vector<session_t> clients = m_clients.getClientIDs();
2294 for (session_t i : clients) {
2295 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2299 ServerActiveObject *player = m_env->getActiveObject(i);
2300 v3f player_pos = player ? player->getBasePosition() : v3f();
2302 for (const v3s16 &pos : meta_updates) {
2303 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2308 v3s16 block_pos = getNodeBlockPos(pos);
2309 if (!client->isBlockSent(block_pos) || (player &&
2310 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2311 client->SetBlockNotSent(block_pos);
2315 // Add the change to send list
2316 meta_updates_list.set(pos, meta);
2318 if (meta_updates_list.size() == 0)
2321 // Send the meta changes
2322 std::ostringstream os(std::ios::binary);
2323 meta_updates_list.serialize(os, client->serialization_version, false, true, true);
2324 std::ostringstream oss(std::ios::binary);
2325 compressZlib(os.str(), oss);
2327 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2328 pkt.putLongString(oss.str());
2329 m_clients.send(i, 0, &pkt, true);
2331 meta_updates_list.clear();
2337 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2338 u16 net_proto_version)
2341 Create a packet with the block in the right format
2343 thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
2344 std::ostringstream os(std::ios_base::binary);
2345 block->serialize(os, ver, false, net_compression_level);
2346 block->serializeNetworkSpecific(os);
2347 std::string s = os.str();
2349 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + s.size(), peer_id);
2351 pkt << block->getPos();
2352 pkt.putRawString(s.c_str(), s.size());
2356 void Server::SendBlocks(float dtime)
2358 MutexAutoLock envlock(m_env_mutex);
2359 //TODO check if one big lock could be faster then multiple small ones
2361 std::vector<PrioritySortedBlockTransfer> queue;
2363 u32 total_sending = 0;
2366 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2368 std::vector<session_t> clients = m_clients.getClientIDs();
2371 for (const session_t client_id : clients) {
2372 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2377 total_sending += client->getSendingCount();
2378 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2384 // Lowest priority number comes first.
2385 // Lowest is most important.
2386 std::sort(queue.begin(), queue.end());
2390 // Maximal total count calculation
2391 // The per-client block sends is halved with the maximal online users
2392 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2393 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2395 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2396 Map &map = m_env->getMap();
2398 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2399 if (total_sending >= max_blocks_to_send)
2402 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2406 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2411 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2412 client->net_proto_version);
2414 client->SentBlock(block_to_send.pos);
2420 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2422 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2427 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2428 if (!client || client->isBlockSent(blockpos)) {
2432 SendBlockNoLock(peer_id, block, client->serialization_version,
2433 client->net_proto_version);
2439 bool Server::addMediaFile(const std::string &filename,
2440 const std::string &filepath, std::string *filedata_to,
2441 std::string *digest_to)
2443 // If name contains illegal characters, ignore the file
2444 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2445 infostream << "Server: ignoring illegal file name: \""
2446 << filename << "\"" << std::endl;
2449 // If name is not in a supported format, ignore it
2450 const char *supported_ext[] = {
2451 ".png", ".jpg", ".bmp",
2453 ".x", ".b3d", ".obj",
2454 // Custom translation file format
2458 if (removeStringEnd(filename, supported_ext).empty()) {
2459 infostream << "Server: ignoring unsupported file extension: \""
2460 << filename << "\"" << std::endl;
2463 // Ok, attempt to load the file and add to cache
2466 std::string filedata;
2467 if (!fs::ReadFile(filepath, filedata)) {
2468 errorstream << "Server::addMediaFile(): Failed to open \""
2469 << filename << "\" for reading" << std::endl;
2473 if (filedata.empty()) {
2474 errorstream << "Server::addMediaFile(): Empty file \""
2475 << filepath << "\"" << std::endl;
2480 sha1.addBytes(filedata.c_str(), filedata.length());
2482 unsigned char *digest = sha1.getDigest();
2483 std::string sha1_base64 = base64_encode(digest, 20);
2484 std::string sha1_hex = hex_encode((char*) digest, 20);
2486 *digest_to = std::string((char*) digest, 20);
2490 m_media[filename] = MediaInfo(filepath, sha1_base64);
2491 verbosestream << "Server: " << sha1_hex << " is " << filename
2495 *filedata_to = std::move(filedata);
2499 void Server::fillMediaCache()
2501 infostream << "Server: Calculating media file checksums" << std::endl;
2503 // Collect all media file paths
2504 std::vector<std::string> paths;
2506 // ordered in descending priority
2507 paths.push_back(getBuiltinLuaPath() + DIR_DELIM + "locale");
2508 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2509 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2510 m_modmgr->getModsMediaPaths(paths);
2512 // Collect media file information from paths into cache
2513 for (const std::string &mediapath : paths) {
2514 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2515 for (const fs::DirListNode &dln : dirlist) {
2516 if (dln.dir) // Ignore dirs (already in paths)
2519 const std::string &filename = dln.name;
2520 if (m_media.find(filename) != m_media.end()) // Do not override
2523 std::string filepath = mediapath;
2524 filepath.append(DIR_DELIM).append(filename);
2525 addMediaFile(filename, filepath);
2529 infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2532 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2535 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2538 std::string lang_suffix;
2539 lang_suffix.append(".").append(lang_code).append(".tr");
2540 for (const auto &i : m_media) {
2541 if (i.second.no_announce)
2543 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2550 for (const auto &i : m_media) {
2551 if (i.second.no_announce)
2553 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2555 pkt << i.first << i.second.sha1_digest;
2558 pkt << g_settings->get("remote_media");
2561 verbosestream << "Server: Announcing files to id(" << peer_id
2562 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2565 struct SendableMedia
2571 SendableMedia(const std::string &name, const std::string &path,
2572 std::string &&data):
2573 name(name), path(path), data(std::move(data))
2577 void Server::sendRequestedMedia(session_t peer_id,
2578 const std::vector<std::string> &tosend)
2580 verbosestream<<"Server::sendRequestedMedia(): "
2581 <<"Sending files to client"<<std::endl;
2585 // Put 5kB in one bunch (this is not accurate)
2586 u32 bytes_per_bunch = 5000;
2588 std::vector< std::vector<SendableMedia> > file_bunches;
2589 file_bunches.emplace_back();
2591 u32 file_size_bunch_total = 0;
2593 for (const std::string &name : tosend) {
2594 if (m_media.find(name) == m_media.end()) {
2595 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2596 <<"unknown file \""<<(name)<<"\""<<std::endl;
2600 const auto &m = m_media[name];
2604 if (!fs::ReadFile(m.path, data)) {
2605 errorstream << "Server::sendRequestedMedia(): Failed to read \""
2606 << name << "\"" << std::endl;
2609 file_size_bunch_total += data.size();
2612 file_bunches.back().emplace_back(name, m.path, std::move(data));
2614 // Start next bunch if got enough data
2615 if(file_size_bunch_total >= bytes_per_bunch) {
2616 file_bunches.emplace_back();
2617 file_size_bunch_total = 0;
2622 /* Create and send packets */
2624 u16 num_bunches = file_bunches.size();
2625 for (u16 i = 0; i < num_bunches; i++) {
2628 u16 total number of texture bunches
2629 u16 index of this bunch
2630 u32 number of files in this bunch
2639 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2640 pkt << num_bunches << i << (u32) file_bunches[i].size();
2642 for (const SendableMedia &j : file_bunches[i]) {
2644 pkt.putLongString(j.data);
2647 verbosestream << "Server::sendRequestedMedia(): bunch "
2648 << i << "/" << num_bunches
2649 << " files=" << file_bunches[i].size()
2650 << " size=" << pkt.getSize() << std::endl;
2655 void Server::stepPendingDynMediaCallbacks(float dtime)
2657 MutexAutoLock lock(m_env_mutex);
2659 for (auto it = m_pending_dyn_media.begin(); it != m_pending_dyn_media.end();) {
2660 it->second.expiry_timer -= dtime;
2661 bool del = it->second.waiting_players.empty() || it->second.expiry_timer < 0;
2668 const auto &name = it->second.filename;
2669 if (!name.empty()) {
2670 assert(m_media.count(name));
2671 // if no_announce isn't set we're definitely deleting the wrong file!
2672 sanity_check(m_media[name].no_announce);
2674 fs::DeleteSingleFileOrEmptyDirectory(m_media[name].path);
2675 m_media.erase(name);
2677 getScriptIface()->freeDynamicMediaCallback(it->first);
2678 it = m_pending_dyn_media.erase(it);
2682 void Server::SendMinimapModes(session_t peer_id,
2683 std::vector<MinimapMode> &modes, size_t wanted_mode)
2685 RemotePlayer *player = m_env->getPlayer(peer_id);
2687 if (player->getPeerId() == PEER_ID_INEXISTENT)
2690 NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2691 pkt << (u16)modes.size() << (u16)wanted_mode;
2693 for (auto &mode : modes)
2694 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2699 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2701 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2705 pkt << false; // Remove inventory
2707 pkt << true; // Update inventory
2709 // Serialization & NetworkPacket isn't a love story
2710 std::ostringstream os(std::ios_base::binary);
2711 inventory->serialize(os);
2712 inventory->setModified(false);
2714 const std::string &os_str = os.str();
2715 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2716 pkt.putRawString(os_str);
2719 if (peer_id == PEER_ID_INEXISTENT)
2720 m_clients.sendToAll(&pkt);
2725 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2727 // Lookup player name, to filter detached inventories just after
2728 std::string peer_name;
2729 if (peer_id != PEER_ID_INEXISTENT) {
2730 peer_name = getClient(peer_id, CS_Created)->getName();
2733 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2734 sendDetachedInventory(inv, name, peer_id);
2737 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2744 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2746 PlayerSAO *playersao = getPlayerSAO(peer_id);
2749 infostream << "Server::DiePlayer(): Player "
2750 << playersao->getPlayer()->getName()
2751 << " dies" << std::endl;
2753 playersao->setHP(0, reason);
2754 playersao->clearParentAttachment();
2756 // Trigger scripted stuff
2757 m_script->on_dieplayer(playersao, reason);
2759 SendPlayerHP(peer_id);
2760 SendDeathscreen(peer_id, false, v3f(0,0,0));
2763 void Server::RespawnPlayer(session_t peer_id)
2765 PlayerSAO *playersao = getPlayerSAO(peer_id);
2768 infostream << "Server::RespawnPlayer(): Player "
2769 << playersao->getPlayer()->getName()
2770 << " respawns" << std::endl;
2772 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2773 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2774 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2776 bool repositioned = m_script->on_respawnplayer(playersao);
2777 if (!repositioned) {
2778 // setPos will send the new position to client
2779 playersao->setPos(findSpawnPos());
2782 SendPlayerHP(peer_id);
2786 void Server::DenySudoAccess(session_t peer_id)
2788 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2793 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2794 const std::string &str_reason, bool reconnect)
2796 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2798 m_clients.event(peer_id, CSE_SetDenied);
2799 DisconnectPeer(peer_id);
2803 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2804 const std::string &custom_reason)
2806 SendAccessDenied(peer_id, reason, custom_reason);
2807 m_clients.event(peer_id, CSE_SetDenied);
2808 DisconnectPeer(peer_id);
2811 // 13/03/15: remove this function when protocol version 25 will become
2812 // the minimum version for MT users, maybe in 1 year
2813 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2815 SendAccessDenied_Legacy(peer_id, reason);
2816 m_clients.event(peer_id, CSE_SetDenied);
2817 DisconnectPeer(peer_id);
2820 void Server::DisconnectPeer(session_t peer_id)
2822 m_modchannel_mgr->leaveAllChannels(peer_id);
2823 m_con->DisconnectPeer(peer_id);
2826 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2829 RemoteClient* client = getClient(peer_id, CS_Invalid);
2831 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2833 // Right now, the auth mechs don't change between login and sudo mode.
2834 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2835 client->allowed_sudo_mechs = sudo_auth_mechs;
2837 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2838 << g_settings->getFloat("dedicated_server_step")
2842 m_clients.event(peer_id, CSE_AuthAccept);
2844 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2846 // We only support SRP right now
2847 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2849 resp_pkt << sudo_auth_mechs;
2851 m_clients.event(peer_id, CSE_SudoSuccess);
2855 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2857 std::wstring message;
2860 Clear references to playing sounds
2862 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2863 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2864 ServerPlayingSound &psound = i->second;
2865 psound.clients.erase(peer_id);
2866 if (psound.clients.empty())
2867 m_playing_sounds.erase(i++);
2872 // clear formspec info so the next client can't abuse the current state
2873 m_formspec_state_data.erase(peer_id);
2875 RemotePlayer *player = m_env->getPlayer(peer_id);
2877 /* Run scripts and remove from environment */
2879 PlayerSAO *playersao = player->getPlayerSAO();
2882 playersao->clearChildAttachments();
2883 playersao->clearParentAttachment();
2885 // inform connected clients
2886 const std::string &player_name = player->getName();
2887 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2888 // (u16) 1 + std::string represents a vector serialization representation
2889 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2890 m_clients.sendToAll(¬ice);
2892 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2894 playersao->disconnected();
2901 if (player && reason != CDR_DENY) {
2902 std::ostringstream os(std::ios_base::binary);
2903 std::vector<session_t> clients = m_clients.getClientIDs();
2905 for (const session_t client_id : clients) {
2907 RemotePlayer *player = m_env->getPlayer(client_id);
2911 // Get name of player
2912 os << player->getName() << " ";
2915 std::string name = player->getName();
2916 actionstream << name << " "
2917 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2918 << " List of players: " << os.str() << std::endl;
2920 m_admin_chat->outgoing_queue.push_back(
2921 new ChatEventNick(CET_NICK_REMOVE, name));
2925 MutexAutoLock env_lock(m_env_mutex);
2926 m_clients.DeleteClient(peer_id);
2930 // Send leave chat message to all remaining clients
2931 if (!message.empty()) {
2932 SendChatMessage(PEER_ID_INEXISTENT,
2933 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2937 void Server::UpdateCrafting(RemotePlayer *player)
2939 InventoryList *clist = player->inventory.getList("craft");
2940 if (!clist || clist->getSize() == 0)
2943 if (!clist->checkModified())
2946 // Get a preview for crafting
2948 InventoryLocation loc;
2949 loc.setPlayer(player->getName());
2950 std::vector<ItemStack> output_replacements;
2951 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2952 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2955 InventoryList *plist = player->inventory.getList("craftpreview");
2956 if (plist && plist->getSize() >= 1) {
2957 // Put the new preview in
2958 plist->changeItem(0, preview);
2962 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2964 if (evt->type == CET_NICK_ADD) {
2965 // The terminal informed us of its nick choice
2966 m_admin_nick = ((ChatEventNick *)evt)->nick;
2967 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2968 errorstream << "You haven't set up an account." << std::endl
2969 << "Please log in using the client as '"
2970 << m_admin_nick << "' with a secure password." << std::endl
2971 << "Until then, you can't execute admin tasks via the console," << std::endl
2972 << "and everybody can claim the user account instead of you," << std::endl
2973 << "giving them full control over this server." << std::endl;
2976 assert(evt->type == CET_CHAT);
2977 handleAdminChat((ChatEventChat *)evt);
2981 std::wstring Server::handleChat(const std::string &name,
2982 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2984 // If something goes wrong, this player is to blame
2985 RollbackScopeActor rollback_scope(m_rollback,
2986 std::string("player:") + name);
2988 if (g_settings->getBool("strip_color_codes"))
2989 wmessage = unescape_enriched(wmessage);
2992 switch (player->canSendChatMessage()) {
2993 case RPLAYER_CHATRESULT_FLOODING: {
2994 std::wstringstream ws;
2995 ws << L"You cannot send more messages. You are limited to "
2996 << g_settings->getFloat("chat_message_limit_per_10sec")
2997 << L" messages per 10 seconds.";
3000 case RPLAYER_CHATRESULT_KICK:
3001 DenyAccess_Legacy(player->getPeerId(),
3002 L"You have been kicked due to message flooding.");
3004 case RPLAYER_CHATRESULT_OK:
3007 FATAL_ERROR("Unhandled chat filtering result found.");
3011 if (m_max_chatmessage_length > 0
3012 && wmessage.length() > m_max_chatmessage_length) {
3013 return L"Your message exceed the maximum chat message limit set on the server. "
3014 L"It was refused. Send a shorter message";
3017 auto message = trim(wide_to_utf8(wmessage));
3018 if (message.empty())
3021 if (message.find_first_of("\n\r") != std::wstring::npos) {
3022 return L"Newlines are not permitted in chat messages";
3025 // Run script hook, exit if script ate the chat message
3026 if (m_script->on_chat_message(name, message))
3031 // Whether to send line to the player that sent the message, or to all players
3032 bool broadcast_line = true;
3034 if (check_shout_priv && !checkPriv(name, "shout")) {
3035 line += L"-!- You don't have permission to shout.";
3036 broadcast_line = false;
3039 Workaround for fixing chat on Android. Lua doesn't handle
3040 the Cyrillic alphabet and some characters on older Android devices
3043 line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
3045 line += utf8_to_wide(m_script->formatChatMessage(name,
3046 wide_to_utf8(wmessage)));
3051 Tell calling method to send the message to sender
3053 if (!broadcast_line)
3057 Send the message to others
3059 actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
3061 ChatMessage chatmsg(line);
3063 std::vector<session_t> clients = m_clients.getClientIDs();
3064 for (u16 cid : clients)
3065 SendChatMessage(cid, chatmsg);
3070 void Server::handleAdminChat(const ChatEventChat *evt)
3072 std::string name = evt->nick;
3073 std::wstring wmessage = evt->evt_msg;
3075 std::wstring answer = handleChat(name, wmessage);
3077 // If asked to send answer to sender
3078 if (!answer.empty()) {
3079 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3083 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3085 RemoteClient *client = getClientNoEx(peer_id,state_min);
3087 throw ClientNotFoundException("Client not found");
3091 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3093 return m_clients.getClientNoEx(peer_id, state_min);
3096 std::string Server::getPlayerName(session_t peer_id)
3098 RemotePlayer *player = m_env->getPlayer(peer_id);
3100 return "[id="+itos(peer_id)+"]";
3101 return player->getName();
3104 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3106 RemotePlayer *player = m_env->getPlayer(peer_id);
3109 return player->getPlayerSAO();
3112 std::string Server::getStatusString()
3114 std::ostringstream os(std::ios_base::binary);
3117 os << "version=" << g_version_string;
3119 os << ", uptime=" << m_uptime_counter->get();
3121 os << ", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3123 // Information about clients
3125 os << ", clients={";
3127 std::vector<session_t> clients = m_clients.getClientIDs();
3128 for (session_t client_id : clients) {
3129 RemotePlayer *player = m_env->getPlayer(client_id);
3131 // Get name of player
3132 const char *name = player ? player->getName() : "<unknown>";
3134 // Add name to information string
3144 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3145 os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
3147 if (!g_settings->get("motd").empty())
3148 os << std::endl << "# Server: " << g_settings->get("motd");
3153 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3155 std::set<std::string> privs;
3156 m_script->getAuth(name, NULL, &privs);
3160 bool Server::checkPriv(const std::string &name, const std::string &priv)
3162 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3163 return (privs.count(priv) != 0);
3166 void Server::reportPrivsModified(const std::string &name)
3169 std::vector<session_t> clients = m_clients.getClientIDs();
3170 for (const session_t client_id : clients) {
3171 RemotePlayer *player = m_env->getPlayer(client_id);
3172 reportPrivsModified(player->getName());
3175 RemotePlayer *player = m_env->getPlayer(name.c_str());
3178 SendPlayerPrivileges(player->getPeerId());
3179 PlayerSAO *sao = player->getPlayerSAO();
3182 sao->updatePrivileges(
3183 getPlayerEffectivePrivs(name),
3188 void Server::reportInventoryFormspecModified(const std::string &name)
3190 RemotePlayer *player = m_env->getPlayer(name.c_str());
3193 SendPlayerInventoryFormspec(player->getPeerId());
3196 void Server::reportFormspecPrependModified(const std::string &name)
3198 RemotePlayer *player = m_env->getPlayer(name.c_str());
3201 SendPlayerFormspecPrepend(player->getPeerId());
3204 void Server::setIpBanned(const std::string &ip, const std::string &name)
3206 m_banmanager->add(ip, name);
3209 void Server::unsetIpBanned(const std::string &ip_or_name)
3211 m_banmanager->remove(ip_or_name);
3214 std::string Server::getBanDescription(const std::string &ip_or_name)
3216 return m_banmanager->getBanDescription(ip_or_name);
3219 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3221 // m_env will be NULL if the server is initializing
3225 if (m_admin_nick == name && !m_admin_nick.empty()) {
3226 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3229 RemotePlayer *player = m_env->getPlayer(name);
3234 if (player->getPeerId() == PEER_ID_INEXISTENT)
3237 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3240 bool Server::showFormspec(const char *playername, const std::string &formspec,
3241 const std::string &formname)
3243 // m_env will be NULL if the server is initializing
3247 RemotePlayer *player = m_env->getPlayer(playername);
3251 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3255 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3260 u32 id = player->addHud(form);
3262 SendHUDAdd(player->getPeerId(), id, form);
3267 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3271 HudElement* todel = player->removeHud(id);
3278 SendHUDRemove(player->getPeerId(), id);
3282 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3287 SendHUDChange(player->getPeerId(), id, stat, data);
3291 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3296 SendHUDSetFlags(player->getPeerId(), flags, mask);
3297 player->hud_flags &= ~mask;
3298 player->hud_flags |= flags;
3300 PlayerSAO* playersao = player->getPlayerSAO();
3305 m_script->player_event(playersao, "hud_changed");
3309 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3314 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3317 player->setHotbarItemcount(hotbar_itemcount);
3318 std::ostringstream os(std::ios::binary);
3319 writeS32(os, hotbar_itemcount);
3320 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3324 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3329 player->setHotbarImage(name);
3330 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3333 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3338 player->setHotbarSelectedImage(name);
3339 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3342 Address Server::getPeerAddress(session_t peer_id)
3344 // Note that this is only set after Init was received in Server::handleCommand_Init
3345 return getClient(peer_id, CS_Invalid)->getAddress();
3348 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3349 v2s32 animation_frames[4], f32 frame_speed)
3351 sanity_check(player);
3352 player->setLocalAnimations(animation_frames, frame_speed);
3353 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3356 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3358 sanity_check(player);
3359 player->eye_offset_first = first;
3360 player->eye_offset_third = third;
3361 SendEyeOffset(player->getPeerId(), first, third);
3364 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3366 sanity_check(player);
3367 player->setSky(params);
3368 SendSetSky(player->getPeerId(), params);
3371 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3373 sanity_check(player);
3374 player->setSun(params);
3375 SendSetSun(player->getPeerId(), params);
3378 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3380 sanity_check(player);
3381 player->setMoon(params);
3382 SendSetMoon(player->getPeerId(), params);
3385 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3387 sanity_check(player);
3388 player->setStars(params);
3389 SendSetStars(player->getPeerId(), params);
3392 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3394 sanity_check(player);
3395 player->setCloudParams(params);
3396 SendCloudParams(player->getPeerId(), params);
3399 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3402 sanity_check(player);
3403 player->overrideDayNightRatio(do_override, ratio);
3404 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3407 void Server::notifyPlayers(const std::wstring &msg)
3409 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3412 void Server::spawnParticle(const std::string &playername,
3413 const ParticleParameters &p)
3415 // m_env will be NULL if the server is initializing
3419 session_t peer_id = PEER_ID_INEXISTENT;
3421 if (!playername.empty()) {
3422 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3425 peer_id = player->getPeerId();
3426 proto_ver = player->protocol_version;
3429 SendSpawnParticle(peer_id, proto_ver, p);
3432 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3433 ServerActiveObject *attached, const std::string &playername)
3435 // m_env will be NULL if the server is initializing
3439 session_t peer_id = PEER_ID_INEXISTENT;
3441 if (!playername.empty()) {
3442 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3445 peer_id = player->getPeerId();
3446 proto_ver = player->protocol_version;
3449 u16 attached_id = attached ? attached->getId() : 0;
3452 if (attached_id == 0)
3453 id = m_env->addParticleSpawner(p.time);
3455 id = m_env->addParticleSpawner(p.time, attached_id);
3457 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3461 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3463 // m_env will be NULL if the server is initializing
3465 throw ServerError("Can't delete particle spawners during initialisation!");
3467 session_t peer_id = PEER_ID_INEXISTENT;
3468 if (!playername.empty()) {
3469 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3472 peer_id = player->getPeerId();
3475 m_env->deleteParticleSpawner(id);
3476 SendDeleteParticleSpawner(peer_id, id);
3479 bool Server::dynamicAddMedia(std::string filepath,
3480 const u32 token, const std::string &to_player, bool ephemeral)
3482 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3483 auto it = m_media.find(filename);
3484 if (it != m_media.end()) {
3485 // Allow the same path to be "added" again in certain conditions
3486 if (ephemeral || it->second.path != filepath) {
3487 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3488 << "\" already exists in media cache" << std::endl;
3493 // Load the file and add it to our media cache
3494 std::string filedata, raw_hash;
3495 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3500 // Create a copy of the file and swap out the path, this removes the
3501 // requirement that mods keep the file accessible at the original path.
3502 filepath = fs::CreateTempFile();
3503 bool ok = ([&] () -> bool {
3504 if (filepath.empty())
3506 std::ofstream os(filepath.c_str(), std::ios::binary);
3514 errorstream << "Server: failed to create a copy of media file "
3515 << "\"" << filename << "\"" << std::endl;
3516 m_media.erase(filename);
3519 verbosestream << "Server: \"" << filename << "\" temporarily copied to "
3520 << filepath << std::endl;
3522 m_media[filename].path = filepath;
3523 m_media[filename].no_announce = true;
3524 // stepPendingDynMediaCallbacks will clean this up later.
3525 } else if (!to_player.empty()) {
3526 m_media[filename].no_announce = true;
3529 // Push file to existing clients
3530 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3531 pkt << raw_hash << filename << (bool)ephemeral;
3533 NetworkPacket legacy_pkt = pkt;
3535 // Newer clients get asked to fetch the file (asynchronous)
3537 // Older clients have an awful hack that just throws the data at them
3538 legacy_pkt.putLongString(filedata);
3540 std::unordered_set<session_t> delivered, waiting;
3542 for (auto &pair : m_clients.getClientList()) {
3543 if (pair.second->getState() < CS_DefinitionsSent)
3545 const auto proto_ver = pair.second->net_proto_version;
3549 const session_t peer_id = pair.second->peer_id;
3550 if (!to_player.empty() && getPlayerName(peer_id) != to_player)
3553 if (proto_ver < 40) {
3554 delivered.emplace(peer_id);
3556 The network layer only guarantees ordered delivery inside a channel.
3557 Since the very next packet could be one that uses the media, we have
3558 to push the media over ALL channels to ensure it is processed before
3559 it is used. In practice this means channels 1 and 0.
3561 m_clients.send(peer_id, 1, &legacy_pkt, true);
3562 m_clients.send(peer_id, 0, &legacy_pkt, true);
3564 waiting.emplace(peer_id);
3565 Send(peer_id, &pkt);
3570 // Run callback for players that already had the file delivered (legacy-only)
3571 for (session_t peer_id : delivered) {
3572 if (auto player = m_env->getPlayer(peer_id))
3573 getScriptIface()->on_dynamic_media_added(token, player->getName());
3576 // Save all others in our pending state
3577 auto &state = m_pending_dyn_media[token];
3578 state.waiting_players = std::move(waiting);
3579 // regardless of success throw away the callback after a while
3580 state.expiry_timer = 60.0f;
3582 state.filename = filename;
3587 // actions: time-reversed list
3588 // Return value: success/failure
3589 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3590 std::list<std::string> *log)
3592 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3593 ServerMap *map = (ServerMap*)(&m_env->getMap());
3595 // Fail if no actions to handle
3596 if (actions.empty()) {
3598 log->push_back("Nothing to do.");
3605 for (const RollbackAction &action : actions) {
3607 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3610 std::ostringstream os;
3611 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3612 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3614 log->push_back(os.str());
3616 std::ostringstream os;
3617 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3618 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3620 log->push_back(os.str());
3624 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3625 <<" failed"<<std::endl;
3627 // Call it done if less than half failed
3628 return num_failed <= num_tried/2;
3631 // IGameDef interface
3633 IItemDefManager *Server::getItemDefManager()
3638 const NodeDefManager *Server::getNodeDefManager()
3643 ICraftDefManager *Server::getCraftDefManager()
3648 u16 Server::allocateUnknownNodeId(const std::string &name)
3650 return m_nodedef->allocateDummy(name);
3653 IWritableItemDefManager *Server::getWritableItemDefManager()
3658 NodeDefManager *Server::getWritableNodeDefManager()
3663 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3668 const std::vector<ModSpec> & Server::getMods() const
3670 return m_modmgr->getMods();
3673 const ModSpec *Server::getModSpec(const std::string &modname) const
3675 return m_modmgr->getModSpec(modname);
3678 void Server::getModNames(std::vector<std::string> &modlist)
3680 m_modmgr->getModNames(modlist);
3683 std::string Server::getBuiltinLuaPath()
3685 return porting::path_share + DIR_DELIM + "builtin";
3688 std::string Server::getModStoragePath() const
3690 return m_path_world + DIR_DELIM + "mod_storage";
3693 v3f Server::findSpawnPos()
3695 ServerMap &map = m_env->getServerMap();
3697 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3698 return nodeposf * BS;
3700 bool is_good = false;
3701 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3702 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3704 // Try to find a good place a few times
3705 for (s32 i = 0; i < 4000 && !is_good; i++) {
3706 s32 range = MYMIN(1 + i, range_max);
3707 // We're going to try to throw the player to this position
3708 v2s16 nodepos2d = v2s16(
3709 -range + (myrand() % (range * 2)),
3710 -range + (myrand() % (range * 2)));
3711 // Get spawn level at point
3712 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3713 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3714 // signify an unsuitable spawn position, or if outside limits.
3715 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3716 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3719 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3720 // Consecutive empty nodes
3723 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3724 // avoid obstructions in already-generated mapblocks.
3725 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3726 // no obstructions, but mapgen decorations are generated after spawn so
3727 // the player may end up inside one.
3728 for (s32 i = 0; i < 8; i++) {
3729 v3s16 blockpos = getNodeBlockPos(nodepos);
3730 map.emergeBlock(blockpos, true);
3731 content_t c = map.getNode(nodepos).getContent();
3733 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3734 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3735 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3737 if (air_count >= 2) {
3738 // Spawn in lower empty node
3740 nodeposf = intToFloat(nodepos, BS);
3741 // Don't spawn the player outside map boundaries
3742 if (objectpos_over_limit(nodeposf))
3743 // Exit this loop, positions above are probably over limit
3746 // Good position found, cause an exit from main loop
3760 // No suitable spawn point found, return fallback 0,0,0
3761 return v3f(0.0f, 0.0f, 0.0f);
3764 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3766 if (delay == 0.0f) {
3767 // No delay, shutdown immediately
3768 m_shutdown_state.is_requested = true;
3769 // only print to the infostream, a chat message saying
3770 // "Server Shutting Down" is sent when the server destructs.
3771 infostream << "*** Immediate Server shutdown requested." << std::endl;
3772 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3773 // Negative delay, cancel shutdown if requested
3774 m_shutdown_state.reset();
3775 std::wstringstream ws;
3777 ws << L"*** Server shutdown canceled.";
3779 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3780 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3781 // m_shutdown_* are already handled, skip.
3783 } else if (delay > 0.0f) {
3784 // Positive delay, tell the clients when the server will shut down
3785 std::wstringstream ws;
3787 ws << L"*** Server shutting down in "
3788 << duration_to_string(myround(delay)).c_str()
3791 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3792 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3795 m_shutdown_state.trigger(delay, msg, reconnect);
3798 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3801 Try to get an existing player
3803 RemotePlayer *player = m_env->getPlayer(name);
3805 // If player is already connected, cancel
3806 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3807 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3812 If player with the wanted peer_id already exists, cancel.
3814 if (m_env->getPlayer(peer_id)) {
3815 infostream<<"emergePlayer(): Player with wrong name but same"
3816 " peer_id already exists"<<std::endl;
3821 player = new RemotePlayer(name, idef());
3824 bool newplayer = false;
3827 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3829 // Complete init with server parts
3830 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3831 player->protocol_version = proto_version;
3835 m_script->on_newplayer(playersao);
3841 bool Server::registerModStorage(ModMetadata *storage)
3843 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3844 errorstream << "Unable to register same mod storage twice. Storage name: "
3845 << storage->getModName() << std::endl;
3849 m_mod_storages[storage->getModName()] = storage;
3853 void Server::unregisterModStorage(const std::string &name)
3855 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3856 if (it != m_mod_storages.end()) {
3857 // Save unconditionaly on unregistration
3858 it->second->save(getModStoragePath());
3859 m_mod_storages.erase(name);
3863 void dedicated_server_loop(Server &server, bool &kill)
3865 verbosestream<<"dedicated_server_loop()"<<std::endl;
3867 IntervalLimiter m_profiler_interval;
3869 static thread_local const float steplen =
3870 g_settings->getFloat("dedicated_server_step");
3871 static thread_local const float profiler_print_interval =
3872 g_settings->getFloat("profiler_print_interval");
3875 * The dedicated server loop only does time-keeping (in Server::step) and
3876 * provides a way to main.cpp to kill the server externally (bool &kill).
3880 // This is kind of a hack but can be done like this
3881 // because server.step() is very light
3882 sleep_ms((int)(steplen*1000.0));
3883 server.step(steplen);
3885 if (server.isShutdownRequested() || kill)
3891 if (profiler_print_interval != 0) {
3892 if(m_profiler_interval.step(steplen, profiler_print_interval))
3894 infostream<<"Profiler:"<<std::endl;
3895 g_profiler->print(infostream);
3896 g_profiler->clear();
3901 infostream << "Dedicated server quitting" << std::endl;
3903 if (g_settings->getBool("server_announce"))
3904 ServerList::sendAnnounce(ServerList::AA_DELETE,
3905 server.m_bind_addr.getPort());
3914 bool Server::joinModChannel(const std::string &channel)
3916 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3917 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3920 bool Server::leaveModChannel(const std::string &channel)
3922 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3925 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3927 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3930 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3934 ModChannel* Server::getModChannel(const std::string &channel)
3936 return m_modchannel_mgr->getModChannel(channel);
3939 void Server::broadcastModChannelMessage(const std::string &channel,
3940 const std::string &message, session_t from_peer)
3942 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3946 if (message.size() > STRING_MAX_LEN) {
3947 warningstream << "ModChannel message too long, dropping before sending "
3948 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3949 << channel << ")" << std::endl;
3954 if (from_peer != PEER_ID_SERVER) {
3955 sender = getPlayerName(from_peer);
3958 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3959 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3960 resp_pkt << channel << sender << message;
3961 for (session_t peer_id : peers) {
3963 if (peer_id == from_peer)
3966 Send(peer_id, &resp_pkt);
3969 if (from_peer != PEER_ID_SERVER) {
3970 m_script->on_modchannel_message(channel, sender, message);
3974 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3976 if (lang_code.empty())
3979 auto it = server_translations.find(lang_code);
3980 if (it != server_translations.end())
3981 return &it->second; // Already loaded
3983 // [] will create an entry
3984 auto *translations = &server_translations[lang_code];
3986 std::string suffix = "." + lang_code + ".tr";
3987 for (const auto &i : m_media) {
3988 if (str_ends_with(i.first, suffix)) {
3990 if (fs::ReadFile(i.second.path, data)) {
3991 translations->loadTranslation(data);
3996 return translations;