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"
69 #include "database/database-sqlite3.h"
70 #include "database/database-files.h"
71 #include "database/database-dummy.h"
72 #include "gameparams.h"
74 class ClientNotFoundException : public BaseException
77 ClientNotFoundException(const char *s):
82 class ServerThread : public Thread
86 ServerThread(Server *server):
97 void *ServerThread::run()
99 BEGIN_DEBUG_EXCEPTION_HANDLER
102 * The real business of the server happens on the ServerThread.
104 * AsyncRunStep() runs an actual server step as soon as enough time has
105 * passed (dedicated_server_loop keeps track of that).
106 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
107 * doesn't busy wait) and will process any remaining packets.
111 m_server->AsyncRunStep(true);
112 } catch (con::ConnectionBindFailed &e) {
113 m_server->setAsyncFatalError(e.what());
114 } catch (LuaError &e) {
115 m_server->setAsyncFatalError(e);
118 while (!stopRequested()) {
120 m_server->AsyncRunStep();
124 } catch (con::PeerNotFoundException &e) {
125 infostream<<"Server: PeerNotFoundException"<<std::endl;
126 } catch (ClientNotFoundException &e) {
127 } catch (con::ConnectionBindFailed &e) {
128 m_server->setAsyncFatalError(e.what());
129 } catch (LuaError &e) {
130 m_server->setAsyncFatalError(e);
134 END_DEBUG_EXCEPTION_HANDLER
139 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
141 if(pos_exists) *pos_exists = false;
146 if(pos_exists) *pos_exists = true;
151 ServerActiveObject *sao = env->getActiveObject(object);
154 if(pos_exists) *pos_exists = true;
155 return sao->getBasePosition(); }
160 void Server::ShutdownState::reset()
164 should_reconnect = false;
165 is_requested = false;
168 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
172 should_reconnect = reconnect;
175 void Server::ShutdownState::tick(float dtime, Server *server)
181 static const float shutdown_msg_times[] =
183 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
186 // Automated messages
187 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
188 for (float t : shutdown_msg_times) {
189 // If shutdown timer matches an automessage, shot it
190 if (m_timer > t && m_timer - dtime < t) {
191 std::wstring periodicMsg = getShutdownTimerMessage();
193 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
194 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
201 if (m_timer < 0.0f) {
207 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
209 std::wstringstream ws;
210 ws << L"*** Server shutting down in "
211 << duration_to_string(myround(m_timer)).c_str() << ".";
220 const std::string &path_world,
221 const SubgameSpec &gamespec,
222 bool simple_singleplayer_mode,
225 ChatInterface *iface,
226 std::string *on_shutdown_errmsg
228 m_bind_addr(bind_addr),
229 m_path_world(path_world),
230 m_gamespec(gamespec),
231 m_simple_singleplayer_mode(simple_singleplayer_mode),
232 m_dedicated(dedicated),
233 m_async_fatal_error(""),
234 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
237 m_bind_addr.isIPv6(),
239 m_itemdef(createItemDefManager()),
240 m_nodedef(createNodeDefManager()),
241 m_craftdef(createCraftDefManager()),
242 m_thread(new ServerThread(this)),
245 m_on_shutdown_errmsg(on_shutdown_errmsg),
246 m_modchannel_mgr(new ModChannelMgr())
248 if (m_path_world.empty())
249 throw ServerError("Supplied empty world path");
251 if (!gamespec.isValid())
252 throw ServerError("Supplied invalid gamespec");
255 m_metrics_backend = std::unique_ptr<MetricsBackend>(createPrometheusMetricsBackend());
257 m_metrics_backend = std::make_unique<MetricsBackend>();
260 m_uptime_counter = m_metrics_backend->addCounter("minetest_core_server_uptime", "Server uptime (in seconds)");
261 m_player_gauge = m_metrics_backend->addGauge("minetest_core_player_number", "Number of connected players");
263 m_timeofday_gauge = m_metrics_backend->addGauge(
264 "minetest_core_timeofday",
265 "Time of day value");
267 m_lag_gauge = m_metrics_backend->addGauge(
268 "minetest_core_latency",
269 "Latency value (in seconds)");
272 const std::string aom_types[] = {"reliable", "unreliable"};
273 for (u32 i = 0; i < ARRLEN(aom_types); i++) {
274 std::string help_str("Number of active object messages generated (");
275 help_str.append(aom_types[i]).append(")");
276 m_aom_buffer_counter[i] = m_metrics_backend->addCounter(
277 "minetest_core_aom_generated_count", help_str,
278 {{"type", aom_types[i]}});
281 m_packet_recv_counter = m_metrics_backend->addCounter(
282 "minetest_core_server_packet_recv",
283 "Processable packets received");
285 m_packet_recv_processed_counter = m_metrics_backend->addCounter(
286 "minetest_core_server_packet_recv_processed",
287 "Valid received packets processed");
289 m_map_edit_event_counter = m_metrics_backend->addCounter(
290 "minetest_core_map_edit_events",
291 "Number of map edit events");
293 m_lag_gauge->set(g_settings->getFloat("dedicated_server_step"));
299 // Send shutdown message
300 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
301 L"*** Server shutting down"));
304 MutexAutoLock envlock(m_env_mutex);
306 infostream << "Server: Saving players" << std::endl;
307 m_env->saveLoadedPlayers();
309 infostream << "Server: Kicking players" << std::endl;
310 std::string kick_msg;
311 bool reconnect = false;
312 if (isShutdownRequested()) {
313 reconnect = m_shutdown_state.should_reconnect;
314 kick_msg = m_shutdown_state.message;
316 if (kick_msg.empty()) {
317 kick_msg = g_settings->get("kick_msg_shutdown");
319 m_env->saveLoadedPlayers(true);
320 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
321 kick_msg, reconnect);
324 actionstream << "Server: Shutting down" << std::endl;
326 // Do this before stopping the server in case mapgen callbacks need to access
327 // server-controlled resources (like ModStorages). Also do them before
328 // shutdown callbacks since they may modify state that is finalized in a
331 m_emerge->stopThreads();
334 MutexAutoLock envlock(m_env_mutex);
336 // Execute script shutdown hooks
337 infostream << "Executing shutdown hooks" << std::endl;
339 m_script->on_shutdown();
340 } catch (ModError &e) {
341 errorstream << "ModError: " << e.what() << std::endl;
342 if (m_on_shutdown_errmsg) {
343 if (m_on_shutdown_errmsg->empty()) {
344 *m_on_shutdown_errmsg = std::string("ModError: ") + e.what();
346 *m_on_shutdown_errmsg += std::string("\nModError: ") + e.what();
351 infostream << "Server: Saving environment metadata" << std::endl;
361 // Write any changes before deletion.
362 if (m_mod_storage_database)
363 m_mod_storage_database->endSave();
365 // Delete things in the reverse order of creation
369 delete m_mod_storage_database;
375 // Deinitialize scripting
376 infostream << "Server: Deinitializing scripting" << std::endl;
378 delete m_startup_server_map; // if available
379 delete m_game_settings;
381 while (!m_unsent_map_edit_queue.empty()) {
382 delete m_unsent_map_edit_queue.front();
383 m_unsent_map_edit_queue.pop();
389 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
390 if (m_simple_singleplayer_mode)
391 infostream << " in simple singleplayer mode" << std::endl;
393 infostream << std::endl;
394 infostream << "- world: " << m_path_world << std::endl;
395 infostream << "- game: " << m_gamespec.path << std::endl;
397 m_game_settings = Settings::createLayer(SL_GAME);
399 // Create world if it doesn't exist
401 loadGameConfAndInitWorld(m_path_world,
402 fs::GetFilenameFromPath(m_path_world.c_str()),
404 } catch (const BaseException &e) {
405 throw ServerError(std::string("Failed to initialize world: ") + e.what());
408 // Create emerge manager
409 m_emerge = new EmergeManager(this, m_metrics_backend.get());
411 // Create ban manager
412 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
413 m_banmanager = new BanManager(ban_path);
415 // Create mod storage database and begin a save for later
416 m_mod_storage_database = openModStorageDatabase(m_path_world);
417 m_mod_storage_database->beginSave();
419 m_modmgr = std::make_unique<ServerModManager>(m_path_world);
420 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
421 // complain about mods with unsatisfied dependencies
422 if (!m_modmgr->isConsistent()) {
423 m_modmgr->printUnsatisfiedModsError();
427 MutexAutoLock envlock(m_env_mutex);
429 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
430 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge, m_metrics_backend.get());
431 m_startup_server_map = servermap;
433 // Initialize scripting
434 infostream << "Server: Initializing Lua" << std::endl;
436 m_script = new ServerScripting(this);
438 // Must be created before mod loading because we have some inventory creation
439 m_inventory_mgr = std::make_unique<ServerInventoryManager>();
441 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
443 m_modmgr->loadMods(m_script);
445 // Read Textures and calculate sha1 sums
448 // Apply item aliases in the node definition manager
449 m_nodedef->updateAliases(m_itemdef);
451 // Apply texture overrides from texturepack/override.txt
452 std::vector<std::string> paths;
453 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
454 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
455 for (const std::string &path : paths) {
456 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
457 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
458 m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
461 m_nodedef->setNodeRegistrationStatus(true);
463 // Perform pending node name resolutions
464 m_nodedef->runNodeResolveCallbacks();
466 // unmap node names in cross-references
467 m_nodedef->resolveCrossrefs();
469 // init the recipe hashes to speed up crafting
470 m_craftdef->initHashes(this);
472 // Initialize Environment
473 m_startup_server_map = nullptr; // Ownership moved to ServerEnvironment
474 m_env = new ServerEnvironment(servermap, m_script, this,
475 m_path_world, m_metrics_backend.get());
477 m_inventory_mgr->setEnv(m_env);
478 m_clients.setEnv(m_env);
480 if (!servermap->settings_mgr.makeMapgenParams())
481 FATAL_ERROR("Couldn't create any mapgen type");
483 // Initialize mapgens
484 m_emerge->initMapgens(servermap->getMapgenParams());
486 if (g_settings->getBool("enable_rollback_recording")) {
487 // Create rollback manager
488 m_rollback = new RollbackManager(m_path_world, this);
491 // Give environment reference to scripting api
492 m_script->initializeEnvironment(m_env);
494 // Do this after regular script init is done
495 m_script->initAsync();
497 // Register us to receive map edit events
498 servermap->addEventReceiver(this);
502 // Those settings can be overwritten in world.mt, they are
503 // intended to be cached after environment loading.
504 m_liquid_transform_every = g_settings->getFloat("liquid_update");
505 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
506 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
507 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
514 infostream << "Starting server on " << m_bind_addr.serializeString()
515 << "..." << std::endl;
517 // Stop thread if already running
520 // Initialize connection
521 m_con->SetTimeoutMs(30);
522 m_con->Serve(m_bind_addr);
527 // ASCII art for the win!
529 << " __. __. __. " << std::endl
530 << " _____ |__| ____ _____ / |_ _____ _____ / |_ " << std::endl
531 << " / \\| |/ \\ / __ \\ _\\/ __ \\/ __> _\\" << std::endl
532 << "| Y Y \\ | | \\ ___/| | | ___/\\___ \\| | " << std::endl
533 << "|__|_| / |___| /\\______> | \\______>_____/| | " << std::endl
534 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
535 actionstream << "World at [" << m_path_world << "]" << std::endl;
536 actionstream << "Server for gameid=\"" << m_gamespec.id
537 << "\" listening on ";
538 m_bind_addr.print(actionstream);
539 actionstream << "." << std::endl;
544 infostream<<"Server: Stopping and waiting threads"<<std::endl;
546 // Stop threads (set run=false first so both start stopping)
550 infostream<<"Server: Threads stopped"<<std::endl;
553 void Server::step(float dtime)
559 MutexAutoLock lock(m_step_dtime_mutex);
560 m_step_dtime += dtime;
562 // Throw if fatal error occurred in thread
563 std::string async_err = m_async_fatal_error.get();
564 if (!async_err.empty()) {
565 if (!m_simple_singleplayer_mode) {
566 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
567 g_settings->get("kick_msg_crash"),
568 g_settings->getBool("ask_reconnect_on_crash"));
570 throw ServerError("AsyncErr: " + async_err);
574 void Server::AsyncRunStep(bool initial_step)
579 MutexAutoLock lock1(m_step_dtime_mutex);
580 dtime = m_step_dtime;
584 // Send blocks to clients
588 if((dtime < 0.001) && !initial_step)
591 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
594 MutexAutoLock lock1(m_step_dtime_mutex);
595 m_step_dtime -= dtime;
601 m_uptime_counter->increment(dtime);
606 Update time of day and overall game time
608 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
611 Send to clients at constant intervals
614 m_time_of_day_send_timer -= dtime;
615 if (m_time_of_day_send_timer < 0.0) {
616 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
617 u16 time = m_env->getTimeOfDay();
618 float time_speed = g_settings->getFloat("time_speed");
619 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
621 m_timeofday_gauge->set(time);
625 MutexAutoLock lock(m_env_mutex);
626 // Figure out and report maximum lag to environment
627 float max_lag = m_env->getMaxLagEstimate();
628 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
630 if(dtime > 0.1 && dtime > max_lag * 2.0)
631 infostream<<"Server: Maximum lag peaked to "<<dtime
635 m_env->reportMaxLagEstimate(max_lag);
641 static const float map_timer_and_unload_dtime = 2.92;
642 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
644 MutexAutoLock lock(m_env_mutex);
645 // Run Map's timers and unload unused data
646 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
647 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
648 g_settings->getFloat("server_unload_unused_data_timeout"),
653 Listen to the admin chat, if available
656 if (!m_admin_chat->command_queue.empty()) {
657 MutexAutoLock lock(m_env_mutex);
658 while (!m_admin_chat->command_queue.empty()) {
659 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
660 handleChatInterfaceEvent(evt);
664 m_admin_chat->outgoing_queue.push_back(
665 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
672 /* Transform liquids */
673 m_liquid_transform_timer += dtime;
674 if(m_liquid_transform_timer >= m_liquid_transform_every)
676 m_liquid_transform_timer -= m_liquid_transform_every;
678 MutexAutoLock lock(m_env_mutex);
680 ScopeProfiler sp(g_profiler, "Server: liquid transform");
682 std::map<v3s16, MapBlock*> modified_blocks;
683 m_env->getServerMap().transformLiquids(modified_blocks, m_env);
686 Set the modified blocks unsent for all the clients
688 if (!modified_blocks.empty()) {
689 SetBlocksNotSent(modified_blocks);
692 m_clients.step(dtime);
694 // increase/decrease lag gauge gradually
695 if (m_lag_gauge->get() > dtime) {
696 m_lag_gauge->decrement(dtime/100);
698 m_lag_gauge->increment(dtime/100);
702 float &counter = m_step_pending_dyn_media_timer;
704 if (counter >= 5.0f) {
705 stepPendingDynMediaCallbacks(counter);
712 // send masterserver announce
714 float &counter = m_masterserver_timer;
715 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
716 g_settings->getBool("server_announce")) {
717 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
718 ServerList::AA_START,
719 m_bind_addr.getPort(),
720 m_clients.getPlayerNames(),
721 m_uptime_counter->get(),
722 m_env->getGameTime(),
725 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
735 Check added and deleted active objects
738 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
739 MutexAutoLock envlock(m_env_mutex);
742 ClientInterface::AutoLock clientlock(m_clients);
743 const RemoteClientMap &clients = m_clients.getClientList();
744 ScopeProfiler sp(g_profiler, "Server: update objects within range");
746 m_player_gauge->set(clients.size());
747 for (const auto &client_it : clients) {
748 RemoteClient *client = client_it.second;
750 if (client->getState() < CS_DefinitionsSent)
753 // This can happen if the client times out somehow
754 if (!m_env->getPlayer(client->peer_id))
757 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
761 SendActiveObjectRemoveAdd(client, playersao);
765 // Write changes to the mod storage
766 m_mod_storage_save_timer -= dtime;
767 if (m_mod_storage_save_timer <= 0.0f) {
768 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
769 m_mod_storage_database->endSave();
770 m_mod_storage_database->beginSave();
778 MutexAutoLock envlock(m_env_mutex);
779 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
782 // Value = data sent by object
783 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
785 // Get active object messages from environment
786 ActiveObjectMessage aom(0);
787 u32 count_reliable = 0, count_unreliable = 0;
789 if (!m_env->getActiveObjectMessage(&aom))
796 std::vector<ActiveObjectMessage>* message_list = nullptr;
797 auto n = buffered_messages.find(aom.id);
798 if (n == buffered_messages.end()) {
799 message_list = new std::vector<ActiveObjectMessage>;
800 buffered_messages[aom.id] = message_list;
802 message_list = n->second;
804 message_list->push_back(std::move(aom));
807 m_aom_buffer_counter[0]->increment(count_reliable);
808 m_aom_buffer_counter[1]->increment(count_unreliable);
811 ClientInterface::AutoLock clientlock(m_clients);
812 const RemoteClientMap &clients = m_clients.getClientList();
813 // Route data to every client
814 std::string reliable_data, unreliable_data;
815 for (const auto &client_it : clients) {
816 reliable_data.clear();
817 unreliable_data.clear();
818 RemoteClient *client = client_it.second;
819 PlayerSAO *player = getPlayerSAO(client->peer_id);
820 // Go through all objects in message buffer
821 for (const auto &buffered_message : buffered_messages) {
822 // If object does not exist or is not known by client, skip it
823 u16 id = buffered_message.first;
824 ServerActiveObject *sao = m_env->getActiveObject(id);
825 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
828 // Get message list of object
829 std::vector<ActiveObjectMessage>* list = buffered_message.second;
830 // Go through every message
831 for (const ActiveObjectMessage &aom : *list) {
832 // Send position updates to players who do not see the attachment
833 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
834 if (sao->getId() == player->getId())
837 // Do not send position updates for attached players
838 // as long the parent is known to the client
839 ServerActiveObject *parent = sao->getParent();
840 if (parent && client->m_known_objects.find(parent->getId()) !=
841 client->m_known_objects.end())
845 // Add full new data to appropriate buffer
846 std::string &buffer = aom.reliable ? reliable_data : unreliable_data;
848 writeU16((u8*) idbuf, aom.id);
851 buffer.append(idbuf, sizeof(idbuf));
852 buffer.append(serializeString16(aom.datastring));
856 reliable_data and unreliable_data are now ready.
859 if (!reliable_data.empty()) {
860 SendActiveObjectMessages(client->peer_id, reliable_data);
863 if (!unreliable_data.empty()) {
864 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
869 // Clear buffered_messages
870 for (auto &buffered_message : buffered_messages) {
871 delete buffered_message.second;
876 Send queued-for-sending map edit events.
879 // We will be accessing the environment
880 MutexAutoLock lock(m_env_mutex);
882 // Single change sending is disabled if queue size is big
883 bool disable_single_change_sending = false;
884 if(m_unsent_map_edit_queue.size() >= 4)
885 disable_single_change_sending = true;
887 const auto event_count = m_unsent_map_edit_queue.size();
888 m_map_edit_event_counter->increment(event_count);
890 // We'll log the amount of each
893 std::list<v3s16> node_meta_updates;
895 while (!m_unsent_map_edit_queue.empty()) {
896 MapEditEvent* event = m_unsent_map_edit_queue.front();
897 m_unsent_map_edit_queue.pop();
899 // Players far away from the change are stored here.
900 // Instead of sending the changes, MapBlocks are set not sent
902 std::unordered_set<u16> far_players;
904 switch (event->type) {
907 prof.add("MEET_ADDNODE", 1);
908 sendAddNode(event->p, event->n, &far_players,
909 disable_single_change_sending ? 5 : 30,
910 event->type == MEET_ADDNODE);
912 case MEET_REMOVENODE:
913 prof.add("MEET_REMOVENODE", 1);
914 sendRemoveNode(event->p, &far_players,
915 disable_single_change_sending ? 5 : 30);
917 case MEET_BLOCK_NODE_METADATA_CHANGED: {
918 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
919 if (!event->is_private_change) {
920 // Don't send the change yet. Collect them to eliminate dupes.
921 node_meta_updates.remove(event->p);
922 node_meta_updates.push_back(event->p);
925 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
926 getNodeBlockPos(event->p))) {
927 block->raiseModified(MOD_STATE_WRITE_NEEDED,
928 MOD_REASON_REPORT_META_CHANGE);
933 prof.add("MEET_OTHER", 1);
934 for (const v3s16 &modified_block : event->modified_blocks) {
935 m_clients.markBlockposAsNotSent(modified_block);
939 prof.add("unknown", 1);
940 warningstream << "Server: Unknown MapEditEvent "
941 << ((u32)event->type) << std::endl;
946 Set blocks not sent to far players
948 if (!far_players.empty()) {
949 // Convert list format to that wanted by SetBlocksNotSent
950 std::map<v3s16, MapBlock*> modified_blocks2;
951 for (const v3s16 &modified_block : event->modified_blocks) {
952 modified_blocks2[modified_block] =
953 m_env->getMap().getBlockNoCreateNoEx(modified_block);
956 // Set blocks not sent
957 for (const u16 far_player : far_players) {
958 if (RemoteClient *client = getClient(far_player))
959 client->SetBlocksNotSent(modified_blocks2);
966 if (event_count >= 5) {
967 infostream << "Server: MapEditEvents:" << std::endl;
968 prof.print(infostream);
969 } else if (event_count != 0) {
970 verbosestream << "Server: MapEditEvents:" << std::endl;
971 prof.print(verbosestream);
974 // Send all metadata updates
975 if (node_meta_updates.size())
976 sendMetadataChanged(node_meta_updates);
980 Trigger emerge thread
981 Doing this every 2s is left over from old code, unclear if this is still needed.
984 float &counter = m_emergethread_trigger_timer;
986 if (counter <= 0.0f) {
989 m_emerge->startThreads();
993 // Save map, players and auth stuff
995 float &counter = m_savemap_timer;
997 static thread_local const float save_interval =
998 g_settings->getFloat("server_map_save_interval");
999 if (counter >= save_interval) {
1001 MutexAutoLock lock(m_env_mutex);
1003 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
1006 if (m_banmanager->isModified()) {
1007 m_banmanager->save();
1010 // Save changed parts of map
1011 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1014 m_env->saveLoadedPlayers();
1016 // Save environment metadata
1021 m_shutdown_state.tick(dtime, this);
1024 void Server::Receive()
1034 In the first iteration *wait* for a packet, afterwards process
1035 all packets that are immediately available (no waiting).
1038 m_con->Receive(&pkt);
1041 if (!m_con->TryReceive(&pkt))
1045 peer_id = pkt.getPeerId();
1046 m_packet_recv_counter->increment();
1048 m_packet_recv_processed_counter->increment();
1049 } catch (const con::InvalidIncomingDataException &e) {
1050 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1051 << e.what() << std::endl;
1052 } catch (const SerializationError &e) {
1053 infostream << "Server::Receive(): SerializationError: what()="
1054 << e.what() << std::endl;
1055 } catch (const ClientStateError &e) {
1056 errorstream << "ProcessData: peer=" << peer_id << " what()="
1057 << e.what() << std::endl;
1058 DenyAccess(peer_id, SERVER_ACCESSDENIED_UNEXPECTED_DATA);
1059 } catch (const con::PeerNotFoundException &e) {
1061 } catch (const con::NoIncomingDataException &e) {
1067 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1069 std::string playername;
1070 PlayerSAO *playersao = NULL;
1072 ClientInterface::AutoLock clientlock(m_clients);
1073 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1075 playername = client->getName();
1076 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1080 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1082 // If failed, cancel
1083 if (!playersao || !player) {
1084 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1085 actionstream << "Server: Failed to emerge player \"" << playername
1086 << "\" (player allocated to an another client)" << std::endl;
1087 DenyAccess(peer_id, SERVER_ACCESSDENIED_ALREADY_CONNECTED);
1089 errorstream << "Server: " << playername << ": Failed to emerge player"
1091 DenyAccess(peer_id, SERVER_ACCESSDENIED_SERVER_FAIL);
1097 Send complete position information
1099 SendMovePlayer(peer_id);
1102 SendPlayerPrivileges(peer_id);
1104 // Send inventory formspec
1105 SendPlayerInventoryFormspec(peer_id);
1108 SendInventory(playersao, false);
1111 SendPlayerHP(playersao);
1113 // Send death screen
1114 if (playersao->isDead())
1115 SendDeathscreen(peer_id, false, v3f(0,0,0));
1118 SendPlayerBreath(playersao);
1121 Update player list and print action
1124 NetworkPacket notice_pkt(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
1125 notice_pkt << (u8) PLAYER_LIST_ADD << (u16) 1 << std::string(player->getName());
1126 m_clients.sendToAll(¬ice_pkt);
1129 std::string ip_str = getPeerAddress(player->getPeerId()).serializeString();
1130 const auto &names = m_clients.getPlayerNames();
1132 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1133 for (const std::string &name : names)
1134 actionstream << name << " ";
1135 actionstream << player->getName() << std::endl;
1140 inline void Server::handleCommand(NetworkPacket *pkt)
1142 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1143 (this->*opHandle.handler)(pkt);
1146 void Server::ProcessData(NetworkPacket *pkt)
1148 // Environment is locked first.
1149 MutexAutoLock envlock(m_env_mutex);
1151 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1152 u32 peer_id = pkt->getPeerId();
1155 Address address = getPeerAddress(peer_id);
1156 std::string addr_s = address.serializeString();
1158 // FIXME: Isn't it a bit excessive to check this for every packet?
1159 if (m_banmanager->isIpBanned(addr_s)) {
1160 std::string ban_name = m_banmanager->getBanName(addr_s);
1161 infostream << "Server: A banned client tried to connect from "
1162 << addr_s << "; banned name was " << ban_name << std::endl;
1163 DenyAccess(peer_id, SERVER_ACCESSDENIED_CUSTOM_STRING,
1164 "Your IP is banned. Banned name was " + ban_name);
1167 } catch (con::PeerNotFoundException &e) {
1169 * no peer for this packet found
1170 * most common reason is peer timeout, e.g. peer didn't
1171 * respond for some time, your server was overloaded or
1174 infostream << "Server::ProcessData(): Canceling: peer "
1175 << peer_id << " not found" << std::endl;
1180 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1182 // Command must be handled into ToServerCommandHandler
1183 if (command >= TOSERVER_NUM_MSG_TYPES) {
1184 infostream << "Server: Ignoring unknown command "
1185 << command << std::endl;
1189 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1194 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1196 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1197 errorstream << "Server::ProcessData(): Cancelling: Peer"
1198 " serialization format invalid or not initialized."
1199 " Skipping incoming command=" << command << std::endl;
1203 /* Handle commands related to client startup */
1204 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1209 if (m_clients.getClientState(peer_id) < CS_Active) {
1210 if (command == TOSERVER_PLAYERPOS) return;
1212 errorstream << "Got packet command: " << command << " for peer id "
1213 << peer_id << " but client isn't active yet. Dropping packet "
1219 } catch (SendFailedException &e) {
1220 errorstream << "Server::ProcessData(): SendFailedException: "
1221 << "what=" << e.what()
1223 } catch (PacketError &e) {
1224 actionstream << "Server::ProcessData(): PacketError: "
1225 << "what=" << e.what()
1230 void Server::setTimeOfDay(u32 time)
1232 m_env->setTimeOfDay(time);
1233 m_time_of_day_send_timer = 0;
1236 void Server::onMapEditEvent(const MapEditEvent &event)
1238 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1241 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1244 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1246 std::vector<session_t> clients = m_clients.getClientIDs();
1247 ClientInterface::AutoLock clientlock(m_clients);
1248 // Set the modified blocks unsent for all the clients
1249 for (const session_t client_id : clients) {
1250 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1251 client->SetBlocksNotSent(block);
1255 void Server::peerAdded(con::Peer *peer)
1257 verbosestream<<"Server::peerAdded(): peer->id="
1258 <<peer->id<<std::endl;
1260 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1263 void Server::deletingPeer(con::Peer *peer, bool timeout)
1265 verbosestream<<"Server::deletingPeer(): peer->id="
1266 <<peer->id<<", timeout="<<timeout<<std::endl;
1268 m_clients.event(peer->id, CSE_Disconnect);
1269 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1272 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1274 *retval = m_con->getPeerStat(peer_id,type);
1275 return *retval != -1;
1278 bool Server::getClientInfo(session_t peer_id, ClientInfo &ret)
1280 ClientInterface::AutoLock clientlock(m_clients);
1281 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1286 ret.state = client->getState();
1287 ret.addr = client->getAddress();
1288 ret.uptime = client->uptime();
1289 ret.ser_vers = client->serialization_version;
1290 ret.prot_vers = client->net_proto_version;
1292 ret.major = client->getMajor();
1293 ret.minor = client->getMinor();
1294 ret.patch = client->getPatch();
1295 ret.vers_string = client->getFullVer();
1297 ret.lang_code = client->getLangCode();
1302 void Server::handlePeerChanges()
1304 while(!m_peer_change_queue.empty())
1306 con::PeerChange c = m_peer_change_queue.front();
1307 m_peer_change_queue.pop();
1309 verbosestream<<"Server: Handling peer change: "
1310 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1315 case con::PEER_ADDED:
1316 m_clients.CreateClient(c.peer_id);
1319 case con::PEER_REMOVED:
1320 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1324 FATAL_ERROR("Invalid peer change event received!");
1330 void Server::printToConsoleOnly(const std::string &text)
1333 m_admin_chat->outgoing_queue.push_back(
1334 new ChatEventChat("", utf8_to_wide(text)));
1336 std::cout << text << std::endl;
1340 void Server::Send(NetworkPacket *pkt)
1342 Send(pkt->getPeerId(), pkt);
1345 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1347 m_clients.send(peer_id,
1348 clientCommandFactoryTable[pkt->getCommand()].channel,
1350 clientCommandFactoryTable[pkt->getCommand()].reliable);
1353 void Server::SendMovement(session_t peer_id)
1355 std::ostringstream os(std::ios_base::binary);
1357 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1359 pkt << g_settings->getFloat("movement_acceleration_default");
1360 pkt << g_settings->getFloat("movement_acceleration_air");
1361 pkt << g_settings->getFloat("movement_acceleration_fast");
1362 pkt << g_settings->getFloat("movement_speed_walk");
1363 pkt << g_settings->getFloat("movement_speed_crouch");
1364 pkt << g_settings->getFloat("movement_speed_fast");
1365 pkt << g_settings->getFloat("movement_speed_climb");
1366 pkt << g_settings->getFloat("movement_speed_jump");
1367 pkt << g_settings->getFloat("movement_liquid_fluidity");
1368 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1369 pkt << g_settings->getFloat("movement_liquid_sink");
1370 pkt << g_settings->getFloat("movement_gravity");
1375 void Server::HandlePlayerHPChange(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1377 m_script->player_event(playersao, "health_changed");
1378 SendPlayerHP(playersao);
1380 // Send to other clients
1381 playersao->sendPunchCommand();
1383 if (playersao->isDead())
1384 HandlePlayerDeath(playersao, reason);
1387 void Server::SendPlayerHP(PlayerSAO *playersao)
1389 SendHP(playersao->getPeerID(), playersao->getHP());
1392 void Server::SendHP(session_t peer_id, u16 hp)
1394 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1399 void Server::SendBreath(session_t peer_id, u16 breath)
1401 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1402 pkt << (u16) breath;
1406 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1407 const std::string &custom_reason, bool reconnect)
1409 assert(reason < SERVER_ACCESSDENIED_MAX);
1411 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1413 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1414 pkt << custom_reason;
1415 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1416 reason == SERVER_ACCESSDENIED_CRASH)
1417 pkt << custom_reason << (u8)reconnect;
1421 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1422 v3f camera_point_target)
1424 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1425 pkt << set_camera_point_target << camera_point_target;
1429 void Server::SendItemDef(session_t peer_id,
1430 IItemDefManager *itemdef, u16 protocol_version)
1432 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1436 u32 length of the next item
1437 zlib-compressed serialized ItemDefManager
1439 std::ostringstream tmp_os(std::ios::binary);
1440 itemdef->serialize(tmp_os, protocol_version);
1441 std::ostringstream tmp_os2(std::ios::binary);
1442 compressZlib(tmp_os.str(), tmp_os2);
1443 pkt.putLongString(tmp_os2.str());
1446 verbosestream << "Server: Sending item definitions to id(" << peer_id
1447 << "): size=" << pkt.getSize() << std::endl;
1452 void Server::SendNodeDef(session_t peer_id,
1453 const NodeDefManager *nodedef, u16 protocol_version)
1455 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1459 u32 length of the next item
1460 zlib-compressed serialized NodeDefManager
1462 std::ostringstream tmp_os(std::ios::binary);
1463 nodedef->serialize(tmp_os, protocol_version);
1464 std::ostringstream tmp_os2(std::ios::binary);
1465 compressZlib(tmp_os.str(), tmp_os2);
1467 pkt.putLongString(tmp_os2.str());
1470 verbosestream << "Server: Sending node definitions to id(" << peer_id
1471 << "): size=" << pkt.getSize() << std::endl;
1477 Non-static send methods
1480 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1482 RemotePlayer *player = sao->getPlayer();
1484 // Do not send new format to old clients
1485 incremental &= player->protocol_version >= 38;
1487 UpdateCrafting(player);
1493 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1495 std::ostringstream os(std::ios::binary);
1496 sao->getInventory()->serialize(os, incremental);
1497 sao->getInventory()->setModified(false);
1498 player->setModified(true);
1500 const std::string &s = os.str();
1501 pkt.putRawString(s.c_str(), s.size());
1505 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1507 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1509 u8 type = message.type;
1510 pkt << version << type << message.sender << message.message
1511 << static_cast<u64>(message.timestamp);
1513 if (peer_id != PEER_ID_INEXISTENT) {
1514 RemotePlayer *player = m_env->getPlayer(peer_id);
1520 m_clients.sendToAll(&pkt);
1524 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1525 const std::string &formname)
1527 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1528 if (formspec.empty()){
1529 //the client should close the formspec
1530 //but make sure there wasn't another one open in meantime
1531 const auto it = m_formspec_state_data.find(peer_id);
1532 if (it != m_formspec_state_data.end() && it->second == formname) {
1533 m_formspec_state_data.erase(peer_id);
1535 pkt.putLongString("");
1537 m_formspec_state_data[peer_id] = formname;
1538 pkt.putLongString(formspec);
1545 // Spawns a particle on peer with peer_id
1546 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1547 const ParticleParameters &p)
1549 static thread_local const float radius =
1550 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1552 if (peer_id == PEER_ID_INEXISTENT) {
1553 std::vector<session_t> clients = m_clients.getClientIDs();
1554 const v3f pos = p.pos * BS;
1555 const float radius_sq = radius * radius;
1557 for (const session_t client_id : clients) {
1558 RemotePlayer *player = m_env->getPlayer(client_id);
1562 PlayerSAO *sao = player->getPlayerSAO();
1566 // Do not send to distant clients
1567 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1570 SendSpawnParticle(client_id, player->protocol_version, p);
1574 assert(protocol_version != 0);
1576 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1579 // NetworkPacket and iostreams are incompatible...
1580 std::ostringstream oss(std::ios_base::binary);
1581 p.serialize(oss, protocol_version);
1582 pkt.putRawString(oss.str());
1588 // Adds a ParticleSpawner on peer with peer_id
1589 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1590 const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1592 static thread_local const float radius =
1593 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1595 if (peer_id == PEER_ID_INEXISTENT) {
1596 std::vector<session_t> clients = m_clients.getClientIDs();
1597 const v3f pos = (p.minpos + p.maxpos) / 2.0f * BS;
1598 const float radius_sq = radius * radius;
1599 /* Don't send short-lived spawners to distant players.
1600 * This could be replaced with proper tracking at some point. */
1601 const bool distance_check = !attached_id && p.time <= 1.0f;
1603 for (const session_t client_id : clients) {
1604 RemotePlayer *player = m_env->getPlayer(client_id);
1608 if (distance_check) {
1609 PlayerSAO *sao = player->getPlayerSAO();
1612 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1616 SendAddParticleSpawner(client_id, player->protocol_version,
1617 p, attached_id, id);
1621 assert(protocol_version != 0);
1623 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1625 pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
1626 << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
1627 << p.minsize << p.maxsize << p.collisiondetection;
1629 pkt.putLongString(p.texture);
1631 pkt << id << p.vertical << p.collision_removal << attached_id;
1633 std::ostringstream os(std::ios_base::binary);
1634 p.animation.serialize(os, protocol_version);
1635 pkt.putRawString(os.str());
1637 pkt << p.glow << p.object_collision;
1638 pkt << p.node.param0 << p.node.param2 << p.node_tile;
1643 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1645 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1649 if (peer_id != PEER_ID_INEXISTENT)
1652 m_clients.sendToAll(&pkt);
1656 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1658 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1660 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1661 << form->text << form->number << form->item << form->dir
1662 << form->align << form->offset << form->world_pos << form->size
1663 << form->z_index << form->text2 << form->style;
1668 void Server::SendHUDRemove(session_t peer_id, u32 id)
1670 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1675 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1677 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1678 pkt << id << (u8) stat;
1682 case HUD_STAT_SCALE:
1683 case HUD_STAT_ALIGN:
1684 case HUD_STAT_OFFSET:
1685 pkt << *(v2f *) value;
1689 case HUD_STAT_TEXT2:
1690 pkt << *(std::string *) value;
1692 case HUD_STAT_WORLD_POS:
1693 pkt << *(v3f *) value;
1696 pkt << *(v2s32 *) value;
1698 default: // all other types
1699 pkt << *(u32 *) value;
1706 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1708 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1710 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1712 pkt << flags << mask;
1717 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1719 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1720 pkt << param << value;
1724 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1726 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1728 // Handle prior clients here
1729 if (m_clients.getProtocolVersion(peer_id) < 39) {
1730 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1732 for (const std::string& texture : params.textures)
1735 pkt << params.clouds;
1736 } else { // Handle current clients and future clients
1737 pkt << params.bgcolor << params.type
1738 << params.clouds << params.fog_sun_tint
1739 << params.fog_moon_tint << params.fog_tint_type;
1741 if (params.type == "skybox") {
1742 pkt << (u16) params.textures.size();
1743 for (const std::string &texture : params.textures)
1745 } else if (params.type == "regular") {
1746 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1747 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1748 << params.sky_color.night_sky << params.sky_color.night_horizon
1749 << params.sky_color.indoors;
1756 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1758 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1759 pkt << params.visible << params.texture
1760 << params.tonemap << params.sunrise
1761 << params.sunrise_visible << params.scale;
1765 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1767 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1769 pkt << params.visible << params.texture
1770 << params.tonemap << params.scale;
1774 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1776 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1778 pkt << params.visible << params.count
1779 << params.starcolor << params.scale;
1784 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1786 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1787 pkt << params.density << params.color_bright << params.color_ambient
1788 << params.height << params.thickness << params.speed;
1792 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1795 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1798 pkt << do_override << (u16) (ratio * 65535);
1803 void Server::SendSetLighting(session_t peer_id, const Lighting &lighting)
1805 NetworkPacket pkt(TOCLIENT_SET_LIGHTING,
1808 pkt << lighting.shadow_intensity;
1813 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1815 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1816 pkt << time << time_speed;
1818 if (peer_id == PEER_ID_INEXISTENT) {
1819 m_clients.sendToAll(&pkt);
1826 void Server::SendPlayerBreath(PlayerSAO *sao)
1830 m_script->player_event(sao, "breath_changed");
1831 SendBreath(sao->getPeerID(), sao->getBreath());
1834 void Server::SendMovePlayer(session_t peer_id)
1836 RemotePlayer *player = m_env->getPlayer(peer_id);
1838 PlayerSAO *sao = player->getPlayerSAO();
1841 // Send attachment updates instantly to the client prior updating position
1842 sao->sendOutdatedData();
1844 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1845 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1848 v3f pos = sao->getBasePosition();
1849 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1850 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1851 << " pitch=" << sao->getLookPitch()
1852 << " yaw=" << sao->getRotation().Y
1859 void Server::SendPlayerFov(session_t peer_id)
1861 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1863 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1864 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1869 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1870 f32 animation_speed)
1872 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1875 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1876 << animation_frames[3] << animation_speed;
1881 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1883 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1884 pkt << first << third;
1888 void Server::SendPlayerPrivileges(session_t peer_id)
1890 RemotePlayer *player = m_env->getPlayer(peer_id);
1892 if(player->getPeerId() == PEER_ID_INEXISTENT)
1895 std::set<std::string> privs;
1896 m_script->getAuth(player->getName(), NULL, &privs);
1898 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1899 pkt << (u16) privs.size();
1901 for (const std::string &priv : privs) {
1908 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1910 RemotePlayer *player = m_env->getPlayer(peer_id);
1912 if (player->getPeerId() == PEER_ID_INEXISTENT)
1915 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1916 pkt.putLongString(player->inventory_formspec);
1921 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1923 RemotePlayer *player = m_env->getPlayer(peer_id);
1925 if (player->getPeerId() == PEER_ID_INEXISTENT)
1928 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1929 pkt << player->formspec_prepend;
1933 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1935 // Radius inside which objects are active
1936 static thread_local const s16 radius =
1937 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1939 // Radius inside which players are active
1940 static thread_local const bool is_transfer_limited =
1941 g_settings->exists("unlimited_player_transfer_distance") &&
1942 !g_settings->getBool("unlimited_player_transfer_distance");
1944 static thread_local const s16 player_transfer_dist =
1945 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1947 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1948 radius : player_transfer_dist;
1950 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1954 std::queue<u16> removed_objects, added_objects;
1955 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1956 client->m_known_objects, removed_objects);
1957 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1958 client->m_known_objects, added_objects);
1960 int removed_count = removed_objects.size();
1961 int added_count = added_objects.size();
1963 if (removed_objects.empty() && added_objects.empty())
1969 // Handle removed objects
1970 writeU16((u8*)buf, removed_objects.size());
1971 data.append(buf, 2);
1972 while (!removed_objects.empty()) {
1974 u16 id = removed_objects.front();
1975 ServerActiveObject* obj = m_env->getActiveObject(id);
1977 // Add to data buffer for sending
1978 writeU16((u8*)buf, id);
1979 data.append(buf, 2);
1981 // Remove from known objects
1982 client->m_known_objects.erase(id);
1984 if (obj && obj->m_known_by_count > 0)
1985 obj->m_known_by_count--;
1987 removed_objects.pop();
1990 // Handle added objects
1991 writeU16((u8*)buf, added_objects.size());
1992 data.append(buf, 2);
1993 while (!added_objects.empty()) {
1995 u16 id = added_objects.front();
1996 ServerActiveObject *obj = m_env->getActiveObject(id);
1997 added_objects.pop();
2000 warningstream << FUNCTION_NAME << ": NULL object id="
2001 << (int)id << std::endl;
2006 u8 type = obj->getSendType();
2008 // Add to data buffer for sending
2009 writeU16((u8*)buf, id);
2010 data.append(buf, 2);
2011 writeU8((u8*)buf, type);
2012 data.append(buf, 1);
2014 data.append(serializeString32(
2015 obj->getClientInitializationData(client->net_proto_version)));
2017 // Add to known objects
2018 client->m_known_objects.insert(id);
2020 obj->m_known_by_count++;
2023 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2024 pkt.putRawString(data.c_str(), data.size());
2027 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2028 << removed_count << " removed, " << added_count << " added, "
2029 << "packet size is " << pkt.getSize() << std::endl;
2032 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2035 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2036 datas.size(), peer_id);
2038 pkt.putRawString(datas.c_str(), datas.size());
2040 m_clients.send(pkt.getPeerId(),
2041 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2045 void Server::SendCSMRestrictionFlags(session_t peer_id)
2047 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2048 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2049 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2053 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2055 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2060 inline s32 Server::nextSoundId()
2062 s32 ret = m_next_sound_id;
2063 if (m_next_sound_id == INT32_MAX)
2064 m_next_sound_id = 0; // signed overflow is undefined
2070 s32 Server::playSound(const SimpleSoundSpec &spec,
2071 const ServerSoundParams ¶ms, bool ephemeral)
2073 // Find out initial position of sound
2074 bool pos_exists = false;
2075 v3f pos = params.getPos(m_env, &pos_exists);
2076 // If position is not found while it should be, cancel sound
2077 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2080 // Filter destination clients
2081 std::vector<session_t> dst_clients;
2082 if (!params.to_player.empty()) {
2083 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2085 infostream<<"Server::playSound: Player \""<<params.to_player
2086 <<"\" not found"<<std::endl;
2089 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2090 infostream<<"Server::playSound: Player \""<<params.to_player
2091 <<"\" not connected"<<std::endl;
2094 dst_clients.push_back(player->getPeerId());
2096 std::vector<session_t> clients = m_clients.getClientIDs();
2098 for (const session_t client_id : clients) {
2099 RemotePlayer *player = m_env->getPlayer(client_id);
2102 if (!params.exclude_player.empty() &&
2103 params.exclude_player == player->getName())
2106 PlayerSAO *sao = player->getPlayerSAO();
2111 if(sao->getBasePosition().getDistanceFrom(pos) >
2112 params.max_hear_distance)
2115 dst_clients.push_back(client_id);
2119 if(dst_clients.empty())
2124 ServerPlayingSound *psound = nullptr;
2126 id = -1; // old clients will still use this, so pick a reserved ID
2129 // The sound will exist as a reference in m_playing_sounds
2130 m_playing_sounds[id] = ServerPlayingSound();
2131 psound = &m_playing_sounds[id];
2132 psound->params = params;
2133 psound->spec = spec;
2136 float gain = params.gain * spec.gain;
2137 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2138 pkt << id << spec.name << gain
2139 << (u8) params.type << pos << params.object
2140 << params.loop << params.fade << params.pitch
2143 bool as_reliable = !ephemeral;
2145 for (const u16 dst_client : dst_clients) {
2147 psound->clients.insert(dst_client);
2148 m_clients.send(dst_client, 0, &pkt, as_reliable);
2152 void Server::stopSound(s32 handle)
2154 // Get sound reference
2155 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2156 m_playing_sounds.find(handle);
2157 if (i == m_playing_sounds.end())
2159 ServerPlayingSound &psound = i->second;
2161 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2164 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2165 si != psound.clients.end(); ++si) {
2167 m_clients.send(*si, 0, &pkt, true);
2169 // Remove sound reference
2170 m_playing_sounds.erase(i);
2173 void Server::fadeSound(s32 handle, float step, float gain)
2175 // Get sound reference
2176 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2177 m_playing_sounds.find(handle);
2178 if (i == m_playing_sounds.end())
2181 ServerPlayingSound &psound = i->second;
2182 psound.params.gain = gain;
2184 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2185 pkt << handle << step << gain;
2187 // Backwards compability
2188 bool play_sound = gain > 0;
2189 ServerPlayingSound compat_psound = psound;
2190 compat_psound.clients.clear();
2192 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2193 compat_pkt << handle;
2195 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2196 it != psound.clients.end();) {
2197 if (m_clients.getProtocolVersion(*it) >= 32) {
2199 m_clients.send(*it, 0, &pkt, true);
2202 compat_psound.clients.insert(*it);
2204 m_clients.send(*it, 0, &compat_pkt, true);
2205 psound.clients.erase(it++);
2209 // Remove sound reference
2210 if (!play_sound || psound.clients.empty())
2211 m_playing_sounds.erase(i);
2213 if (play_sound && !compat_psound.clients.empty()) {
2214 // Play new sound volume on older clients
2215 playSound(compat_psound.spec, compat_psound.params);
2219 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2222 float maxd = far_d_nodes * BS;
2223 v3f p_f = intToFloat(p, BS);
2224 v3s16 block_pos = getNodeBlockPos(p);
2226 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2229 std::vector<session_t> clients = m_clients.getClientIDs();
2230 ClientInterface::AutoLock clientlock(m_clients);
2232 for (session_t client_id : clients) {
2233 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2237 RemotePlayer *player = m_env->getPlayer(client_id);
2238 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2240 // If player is far away, only set modified blocks not sent
2241 if (!client->isBlockSent(block_pos) || (sao &&
2242 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2244 far_players->emplace(client_id);
2246 client->SetBlockNotSent(block_pos);
2251 m_clients.send(client_id, 0, &pkt, true);
2255 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2256 float far_d_nodes, bool remove_metadata)
2258 float maxd = far_d_nodes * BS;
2259 v3f p_f = intToFloat(p, BS);
2260 v3s16 block_pos = getNodeBlockPos(p);
2262 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2263 pkt << p << n.param0 << n.param1 << n.param2
2264 << (u8) (remove_metadata ? 0 : 1);
2266 std::vector<session_t> clients = m_clients.getClientIDs();
2267 ClientInterface::AutoLock clientlock(m_clients);
2269 for (session_t client_id : clients) {
2270 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2274 RemotePlayer *player = m_env->getPlayer(client_id);
2275 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2277 // If player is far away, only set modified blocks not sent
2278 if (!client->isBlockSent(block_pos) || (sao &&
2279 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2281 far_players->emplace(client_id);
2283 client->SetBlockNotSent(block_pos);
2288 m_clients.send(client_id, 0, &pkt, true);
2292 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2294 float maxd = far_d_nodes * BS;
2295 NodeMetadataList meta_updates_list(false);
2296 std::vector<session_t> clients = m_clients.getClientIDs();
2298 ClientInterface::AutoLock clientlock(m_clients);
2300 for (session_t i : clients) {
2301 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2305 ServerActiveObject *player = m_env->getActiveObject(i);
2306 v3f player_pos = player ? player->getBasePosition() : v3f();
2308 for (const v3s16 &pos : meta_updates) {
2309 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2314 v3s16 block_pos = getNodeBlockPos(pos);
2315 if (!client->isBlockSent(block_pos) || (player &&
2316 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2317 client->SetBlockNotSent(block_pos);
2321 // Add the change to send list
2322 meta_updates_list.set(pos, meta);
2324 if (meta_updates_list.size() == 0)
2327 // Send the meta changes
2328 std::ostringstream os(std::ios::binary);
2329 meta_updates_list.serialize(os, client->serialization_version, false, true, true);
2330 std::ostringstream oss(std::ios::binary);
2331 compressZlib(os.str(), oss);
2333 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2334 pkt.putLongString(oss.str());
2335 m_clients.send(i, 0, &pkt, true);
2337 meta_updates_list.clear();
2341 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2342 u16 net_proto_version, SerializedBlockCache *cache)
2344 thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
2345 std::string s, *sptr = nullptr;
2348 auto it = cache->find({block->getPos(), ver});
2349 if (it != cache->end())
2353 // Serialize the block in the right format
2355 std::ostringstream os(std::ios_base::binary);
2356 block->serialize(os, ver, false, net_compression_level);
2357 block->serializeNetworkSpecific(os);
2362 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + sptr->size(), peer_id);
2363 pkt << block->getPos();
2364 pkt.putRawString(*sptr);
2367 // Store away in cache
2368 if (cache && sptr == &s)
2369 (*cache)[{block->getPos(), ver}] = std::move(s);
2372 void Server::SendBlocks(float dtime)
2374 MutexAutoLock envlock(m_env_mutex);
2375 //TODO check if one big lock could be faster then multiple small ones
2377 std::vector<PrioritySortedBlockTransfer> queue;
2379 u32 total_sending = 0, unique_clients = 0;
2382 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2384 std::vector<session_t> clients = m_clients.getClientIDs();
2386 ClientInterface::AutoLock clientlock(m_clients);
2387 for (const session_t client_id : clients) {
2388 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2393 total_sending += client->getSendingCount();
2394 const auto old_count = queue.size();
2395 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2396 unique_clients += queue.size() > old_count ? 1 : 0;
2401 // Lowest priority number comes first.
2402 // Lowest is most important.
2403 std::sort(queue.begin(), queue.end());
2405 ClientInterface::AutoLock clientlock(m_clients);
2407 // Maximal total count calculation
2408 // The per-client block sends is halved with the maximal online users
2409 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2410 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2412 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2413 Map &map = m_env->getMap();
2415 SerializedBlockCache cache, *cache_ptr = nullptr;
2416 if (unique_clients > 1) {
2417 // caching is pointless with a single client
2421 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2422 if (total_sending >= max_blocks_to_send)
2425 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2429 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2434 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2435 client->net_proto_version, cache_ptr);
2437 client->SentBlock(block_to_send.pos);
2442 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2444 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2448 ClientInterface::AutoLock clientlock(m_clients);
2449 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2450 if (!client || client->isBlockSent(blockpos))
2452 SendBlockNoLock(peer_id, block, client->serialization_version,
2453 client->net_proto_version);
2458 bool Server::addMediaFile(const std::string &filename,
2459 const std::string &filepath, std::string *filedata_to,
2460 std::string *digest_to)
2462 // If name contains illegal characters, ignore the file
2463 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2464 infostream << "Server: ignoring illegal file name: \""
2465 << filename << "\"" << std::endl;
2468 // If name is not in a supported format, ignore it
2469 const char *supported_ext[] = {
2470 ".png", ".jpg", ".bmp", ".tga",
2472 ".x", ".b3d", ".obj",
2473 // Custom translation file format
2477 if (removeStringEnd(filename, supported_ext).empty()) {
2478 infostream << "Server: ignoring unsupported file extension: \""
2479 << filename << "\"" << std::endl;
2482 // Ok, attempt to load the file and add to cache
2485 std::string filedata;
2486 if (!fs::ReadFile(filepath, filedata)) {
2487 errorstream << "Server::addMediaFile(): Failed to open \""
2488 << filename << "\" for reading" << std::endl;
2492 if (filedata.empty()) {
2493 errorstream << "Server::addMediaFile(): Empty file \""
2494 << filepath << "\"" << std::endl;
2499 sha1.addBytes(filedata.c_str(), filedata.length());
2501 unsigned char *digest = sha1.getDigest();
2502 std::string sha1_base64 = base64_encode(digest, 20);
2503 std::string sha1_hex = hex_encode((char*) digest, 20);
2505 *digest_to = std::string((char*) digest, 20);
2509 m_media[filename] = MediaInfo(filepath, sha1_base64);
2510 verbosestream << "Server: " << sha1_hex << " is " << filename
2514 *filedata_to = std::move(filedata);
2518 void Server::fillMediaCache()
2520 infostream << "Server: Calculating media file checksums" << std::endl;
2522 // Collect all media file paths
2523 std::vector<std::string> paths;
2525 // ordered in descending priority
2526 paths.push_back(getBuiltinLuaPath() + DIR_DELIM + "locale");
2527 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2528 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2529 m_modmgr->getModsMediaPaths(paths);
2531 // Collect media file information from paths into cache
2532 for (const std::string &mediapath : paths) {
2533 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2534 for (const fs::DirListNode &dln : dirlist) {
2535 if (dln.dir) // Ignore dirs (already in paths)
2538 const std::string &filename = dln.name;
2539 if (m_media.find(filename) != m_media.end()) // Do not override
2542 std::string filepath = mediapath;
2543 filepath.append(DIR_DELIM).append(filename);
2544 addMediaFile(filename, filepath);
2548 infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2551 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2554 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2557 std::string lang_suffix;
2558 lang_suffix.append(".").append(lang_code).append(".tr");
2559 for (const auto &i : m_media) {
2560 if (i.second.no_announce)
2562 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2569 for (const auto &i : m_media) {
2570 if (i.second.no_announce)
2572 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2574 pkt << i.first << i.second.sha1_digest;
2577 pkt << g_settings->get("remote_media");
2580 verbosestream << "Server: Announcing files to id(" << peer_id
2581 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2584 struct SendableMedia
2590 SendableMedia(const std::string &name, const std::string &path,
2591 std::string &&data):
2592 name(name), path(path), data(std::move(data))
2596 void Server::sendRequestedMedia(session_t peer_id,
2597 const std::vector<std::string> &tosend)
2599 verbosestream<<"Server::sendRequestedMedia(): "
2600 <<"Sending files to client"<<std::endl;
2604 // Put 5kB in one bunch (this is not accurate)
2605 u32 bytes_per_bunch = 5000;
2607 std::vector< std::vector<SendableMedia> > file_bunches;
2608 file_bunches.emplace_back();
2610 u32 file_size_bunch_total = 0;
2612 for (const std::string &name : tosend) {
2613 if (m_media.find(name) == m_media.end()) {
2614 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2615 <<"unknown file \""<<(name)<<"\""<<std::endl;
2619 const auto &m = m_media[name];
2623 if (!fs::ReadFile(m.path, data)) {
2624 errorstream << "Server::sendRequestedMedia(): Failed to read \""
2625 << name << "\"" << std::endl;
2628 file_size_bunch_total += data.size();
2631 file_bunches.back().emplace_back(name, m.path, std::move(data));
2633 // Start next bunch if got enough data
2634 if(file_size_bunch_total >= bytes_per_bunch) {
2635 file_bunches.emplace_back();
2636 file_size_bunch_total = 0;
2641 /* Create and send packets */
2643 u16 num_bunches = file_bunches.size();
2644 for (u16 i = 0; i < num_bunches; i++) {
2647 u16 total number of texture bunches
2648 u16 index of this bunch
2649 u32 number of files in this bunch
2658 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2659 pkt << num_bunches << i << (u32) file_bunches[i].size();
2661 for (const SendableMedia &j : file_bunches[i]) {
2663 pkt.putLongString(j.data);
2666 verbosestream << "Server::sendRequestedMedia(): bunch "
2667 << i << "/" << num_bunches
2668 << " files=" << file_bunches[i].size()
2669 << " size=" << pkt.getSize() << std::endl;
2674 void Server::stepPendingDynMediaCallbacks(float dtime)
2676 MutexAutoLock lock(m_env_mutex);
2678 for (auto it = m_pending_dyn_media.begin(); it != m_pending_dyn_media.end();) {
2679 it->second.expiry_timer -= dtime;
2680 bool del = it->second.waiting_players.empty() || it->second.expiry_timer < 0;
2687 const auto &name = it->second.filename;
2688 if (!name.empty()) {
2689 assert(m_media.count(name));
2690 // if no_announce isn't set we're definitely deleting the wrong file!
2691 sanity_check(m_media[name].no_announce);
2693 fs::DeleteSingleFileOrEmptyDirectory(m_media[name].path);
2694 m_media.erase(name);
2696 getScriptIface()->freeDynamicMediaCallback(it->first);
2697 it = m_pending_dyn_media.erase(it);
2701 void Server::SendMinimapModes(session_t peer_id,
2702 std::vector<MinimapMode> &modes, size_t wanted_mode)
2704 RemotePlayer *player = m_env->getPlayer(peer_id);
2706 if (player->getPeerId() == PEER_ID_INEXISTENT)
2709 NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2710 pkt << (u16)modes.size() << (u16)wanted_mode;
2712 for (auto &mode : modes)
2713 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2718 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2720 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2724 pkt << false; // Remove inventory
2726 pkt << true; // Update inventory
2728 // Serialization & NetworkPacket isn't a love story
2729 std::ostringstream os(std::ios_base::binary);
2730 inventory->serialize(os);
2731 inventory->setModified(false);
2733 const std::string &os_str = os.str();
2734 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2735 pkt.putRawString(os_str);
2738 if (peer_id == PEER_ID_INEXISTENT)
2739 m_clients.sendToAll(&pkt);
2744 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2746 // Lookup player name, to filter detached inventories just after
2747 std::string peer_name;
2748 if (peer_id != PEER_ID_INEXISTENT) {
2749 peer_name = getClient(peer_id, CS_Created)->getName();
2752 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2753 sendDetachedInventory(inv, name, peer_id);
2756 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2763 void Server::HandlePlayerDeath(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
2765 infostream << "Server::DiePlayer(): Player "
2766 << playersao->getPlayer()->getName()
2767 << " dies" << std::endl;
2769 playersao->clearParentAttachment();
2771 // Trigger scripted stuff
2772 m_script->on_dieplayer(playersao, reason);
2774 SendDeathscreen(playersao->getPeerID(), false, v3f(0,0,0));
2777 void Server::RespawnPlayer(session_t peer_id)
2779 PlayerSAO *playersao = getPlayerSAO(peer_id);
2782 infostream << "Server::RespawnPlayer(): Player "
2783 << playersao->getPlayer()->getName()
2784 << " respawns" << std::endl;
2786 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2787 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2788 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2790 bool repositioned = m_script->on_respawnplayer(playersao);
2791 if (!repositioned) {
2792 // setPos will send the new position to client
2793 playersao->setPos(findSpawnPos());
2798 void Server::DenySudoAccess(session_t peer_id)
2800 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2805 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2806 const std::string &custom_reason, bool reconnect)
2808 SendAccessDenied(peer_id, reason, custom_reason, reconnect);
2809 m_clients.event(peer_id, CSE_SetDenied);
2810 DisconnectPeer(peer_id);
2813 void Server::DisconnectPeer(session_t peer_id)
2815 m_modchannel_mgr->leaveAllChannels(peer_id);
2816 m_con->DisconnectPeer(peer_id);
2819 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2822 RemoteClient* client = getClient(peer_id, CS_Invalid);
2824 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2826 // Right now, the auth mechs don't change between login and sudo mode.
2827 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2828 client->allowed_sudo_mechs = sudo_auth_mechs;
2830 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2831 << g_settings->getFloat("dedicated_server_step")
2835 m_clients.event(peer_id, CSE_AuthAccept);
2837 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2839 // We only support SRP right now
2840 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2842 resp_pkt << sudo_auth_mechs;
2844 m_clients.event(peer_id, CSE_SudoSuccess);
2848 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2850 std::wstring message;
2853 Clear references to playing sounds
2855 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2856 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2857 ServerPlayingSound &psound = i->second;
2858 psound.clients.erase(peer_id);
2859 if (psound.clients.empty())
2860 m_playing_sounds.erase(i++);
2865 // clear formspec info so the next client can't abuse the current state
2866 m_formspec_state_data.erase(peer_id);
2868 RemotePlayer *player = m_env->getPlayer(peer_id);
2870 /* Run scripts and remove from environment */
2872 PlayerSAO *playersao = player->getPlayerSAO();
2875 playersao->clearChildAttachments();
2876 playersao->clearParentAttachment();
2878 // inform connected clients
2879 const std::string &player_name = player->getName();
2880 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2881 // (u16) 1 + std::string represents a vector serialization representation
2882 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2883 m_clients.sendToAll(¬ice);
2885 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2887 playersao->disconnected();
2894 if (player && reason != CDR_DENY) {
2895 std::ostringstream os(std::ios_base::binary);
2896 std::vector<session_t> clients = m_clients.getClientIDs();
2898 for (const session_t client_id : clients) {
2900 RemotePlayer *player = m_env->getPlayer(client_id);
2904 // Get name of player
2905 os << player->getName() << " ";
2908 std::string name = player->getName();
2909 actionstream << name << " "
2910 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2911 << " List of players: " << os.str() << std::endl;
2913 m_admin_chat->outgoing_queue.push_back(
2914 new ChatEventNick(CET_NICK_REMOVE, name));
2918 MutexAutoLock env_lock(m_env_mutex);
2919 m_clients.DeleteClient(peer_id);
2923 // Send leave chat message to all remaining clients
2924 if (!message.empty()) {
2925 SendChatMessage(PEER_ID_INEXISTENT,
2926 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2930 void Server::UpdateCrafting(RemotePlayer *player)
2932 InventoryList *clist = player->inventory.getList("craft");
2933 if (!clist || clist->getSize() == 0)
2936 if (!clist->checkModified())
2939 // Get a preview for crafting
2941 InventoryLocation loc;
2942 loc.setPlayer(player->getName());
2943 std::vector<ItemStack> output_replacements;
2944 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2945 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2948 InventoryList *plist = player->inventory.getList("craftpreview");
2949 if (plist && plist->getSize() >= 1) {
2950 // Put the new preview in
2951 plist->changeItem(0, preview);
2955 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2957 if (evt->type == CET_NICK_ADD) {
2958 // The terminal informed us of its nick choice
2959 m_admin_nick = ((ChatEventNick *)evt)->nick;
2960 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2961 errorstream << "You haven't set up an account." << std::endl
2962 << "Please log in using the client as '"
2963 << m_admin_nick << "' with a secure password." << std::endl
2964 << "Until then, you can't execute admin tasks via the console," << std::endl
2965 << "and everybody can claim the user account instead of you," << std::endl
2966 << "giving them full control over this server." << std::endl;
2969 assert(evt->type == CET_CHAT);
2970 handleAdminChat((ChatEventChat *)evt);
2974 std::wstring Server::handleChat(const std::string &name,
2975 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2977 // If something goes wrong, this player is to blame
2978 RollbackScopeActor rollback_scope(m_rollback,
2979 std::string("player:") + name);
2981 if (g_settings->getBool("strip_color_codes"))
2982 wmessage = unescape_enriched(wmessage);
2985 switch (player->canSendChatMessage()) {
2986 case RPLAYER_CHATRESULT_FLOODING: {
2987 std::wstringstream ws;
2988 ws << L"You cannot send more messages. You are limited to "
2989 << g_settings->getFloat("chat_message_limit_per_10sec")
2990 << L" messages per 10 seconds.";
2993 case RPLAYER_CHATRESULT_KICK:
2994 DenyAccess(player->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING,
2995 "You have been kicked due to message flooding.");
2997 case RPLAYER_CHATRESULT_OK:
3000 FATAL_ERROR("Unhandled chat filtering result found.");
3004 if (m_max_chatmessage_length > 0
3005 && wmessage.length() > m_max_chatmessage_length) {
3006 return L"Your message exceed the maximum chat message limit set on the server. "
3007 L"It was refused. Send a shorter message";
3010 auto message = trim(wide_to_utf8(wmessage));
3011 if (message.empty())
3014 if (message.find_first_of("\n\r") != std::wstring::npos) {
3015 return L"Newlines are not permitted in chat messages";
3018 // Run script hook, exit if script ate the chat message
3019 if (m_script->on_chat_message(name, message))
3024 // Whether to send line to the player that sent the message, or to all players
3025 bool broadcast_line = true;
3027 if (check_shout_priv && !checkPriv(name, "shout")) {
3028 line += L"-!- You don't have permission to shout.";
3029 broadcast_line = false;
3032 Workaround for fixing chat on Android. Lua doesn't handle
3033 the Cyrillic alphabet and some characters on older Android devices
3036 line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
3038 line += utf8_to_wide(m_script->formatChatMessage(name,
3039 wide_to_utf8(wmessage)));
3044 Tell calling method to send the message to sender
3046 if (!broadcast_line)
3050 Send the message to others
3052 actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
3054 ChatMessage chatmsg(line);
3056 std::vector<session_t> clients = m_clients.getClientIDs();
3057 for (u16 cid : clients)
3058 SendChatMessage(cid, chatmsg);
3063 void Server::handleAdminChat(const ChatEventChat *evt)
3065 std::string name = evt->nick;
3066 std::wstring wmessage = evt->evt_msg;
3068 std::wstring answer = handleChat(name, wmessage);
3070 // If asked to send answer to sender
3071 if (!answer.empty()) {
3072 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3076 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3078 RemoteClient *client = getClientNoEx(peer_id,state_min);
3080 throw ClientNotFoundException("Client not found");
3084 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3086 return m_clients.getClientNoEx(peer_id, state_min);
3089 std::string Server::getPlayerName(session_t peer_id)
3091 RemotePlayer *player = m_env->getPlayer(peer_id);
3093 return "[id="+itos(peer_id)+"]";
3094 return player->getName();
3097 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3099 RemotePlayer *player = m_env->getPlayer(peer_id);
3102 return player->getPlayerSAO();
3105 std::string Server::getStatusString()
3107 std::ostringstream os(std::ios_base::binary);
3110 os << "version: " << g_version_string;
3112 os << " | game: " << (m_gamespec.name.empty() ? m_gamespec.id : m_gamespec.name);
3114 os << " | uptime: " << duration_to_string((int) m_uptime_counter->get());
3116 os << " | max lag: " << std::setprecision(3);
3117 os << (m_env ? m_env->getMaxLagEstimate() : 0) << "s";
3119 // Information about clients
3121 os << " | clients: ";
3123 std::vector<session_t> clients = m_clients.getClientIDs();
3124 for (session_t client_id : clients) {
3125 RemotePlayer *player = m_env->getPlayer(client_id);
3127 // Get name of player
3128 const char *name = player ? player->getName() : "<unknown>";
3130 // Add name to information string
3139 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3140 os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
3142 if (!g_settings->get("motd").empty())
3143 os << std::endl << "# Server: " << g_settings->get("motd");
3148 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3150 std::set<std::string> privs;
3151 m_script->getAuth(name, NULL, &privs);
3155 bool Server::checkPriv(const std::string &name, const std::string &priv)
3157 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3158 return (privs.count(priv) != 0);
3161 void Server::reportPrivsModified(const std::string &name)
3164 std::vector<session_t> clients = m_clients.getClientIDs();
3165 for (const session_t client_id : clients) {
3166 RemotePlayer *player = m_env->getPlayer(client_id);
3167 reportPrivsModified(player->getName());
3170 RemotePlayer *player = m_env->getPlayer(name.c_str());
3173 SendPlayerPrivileges(player->getPeerId());
3174 PlayerSAO *sao = player->getPlayerSAO();
3177 sao->updatePrivileges(
3178 getPlayerEffectivePrivs(name),
3183 void Server::reportInventoryFormspecModified(const std::string &name)
3185 RemotePlayer *player = m_env->getPlayer(name.c_str());
3188 SendPlayerInventoryFormspec(player->getPeerId());
3191 void Server::reportFormspecPrependModified(const std::string &name)
3193 RemotePlayer *player = m_env->getPlayer(name.c_str());
3196 SendPlayerFormspecPrepend(player->getPeerId());
3199 void Server::setIpBanned(const std::string &ip, const std::string &name)
3201 m_banmanager->add(ip, name);
3204 void Server::unsetIpBanned(const std::string &ip_or_name)
3206 m_banmanager->remove(ip_or_name);
3209 std::string Server::getBanDescription(const std::string &ip_or_name)
3211 return m_banmanager->getBanDescription(ip_or_name);
3214 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3216 // m_env will be NULL if the server is initializing
3220 if (m_admin_nick == name && !m_admin_nick.empty()) {
3221 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3224 RemotePlayer *player = m_env->getPlayer(name);
3229 if (player->getPeerId() == PEER_ID_INEXISTENT)
3232 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3235 bool Server::showFormspec(const char *playername, const std::string &formspec,
3236 const std::string &formname)
3238 // m_env will be NULL if the server is initializing
3242 RemotePlayer *player = m_env->getPlayer(playername);
3246 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3250 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3255 u32 id = player->addHud(form);
3257 SendHUDAdd(player->getPeerId(), id, form);
3262 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3266 HudElement* todel = player->removeHud(id);
3273 SendHUDRemove(player->getPeerId(), id);
3277 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3282 SendHUDChange(player->getPeerId(), id, stat, data);
3286 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3291 u32 new_hud_flags = (player->hud_flags & ~mask) | flags;
3292 if (new_hud_flags == player->hud_flags) // no change
3295 SendHUDSetFlags(player->getPeerId(), flags, mask);
3296 player->hud_flags = new_hud_flags;
3298 PlayerSAO* playersao = player->getPlayerSAO();
3303 m_script->player_event(playersao, "hud_changed");
3307 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3312 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3315 player->setHotbarItemcount(hotbar_itemcount);
3316 std::ostringstream os(std::ios::binary);
3317 writeS32(os, hotbar_itemcount);
3318 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3322 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3327 player->setHotbarImage(name);
3328 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3331 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3336 player->setHotbarSelectedImage(name);
3337 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3340 Address Server::getPeerAddress(session_t peer_id)
3342 // Note that this is only set after Init was received in Server::handleCommand_Init
3343 return getClient(peer_id, CS_Invalid)->getAddress();
3346 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3347 v2s32 animation_frames[4], f32 frame_speed)
3349 sanity_check(player);
3350 player->setLocalAnimations(animation_frames, frame_speed);
3351 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3354 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3356 sanity_check(player);
3357 player->eye_offset_first = first;
3358 player->eye_offset_third = third;
3359 SendEyeOffset(player->getPeerId(), first, third);
3362 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3364 sanity_check(player);
3365 player->setSky(params);
3366 SendSetSky(player->getPeerId(), params);
3369 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3371 sanity_check(player);
3372 player->setSun(params);
3373 SendSetSun(player->getPeerId(), params);
3376 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3378 sanity_check(player);
3379 player->setMoon(params);
3380 SendSetMoon(player->getPeerId(), params);
3383 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3385 sanity_check(player);
3386 player->setStars(params);
3387 SendSetStars(player->getPeerId(), params);
3390 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3392 sanity_check(player);
3393 player->setCloudParams(params);
3394 SendCloudParams(player->getPeerId(), params);
3397 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3400 sanity_check(player);
3401 player->overrideDayNightRatio(do_override, ratio);
3402 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3405 void Server::setLighting(RemotePlayer *player, const Lighting &lighting)
3407 sanity_check(player);
3408 player->setLighting(lighting);
3409 SendSetLighting(player->getPeerId(), lighting);
3412 void Server::notifyPlayers(const std::wstring &msg)
3414 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3417 void Server::spawnParticle(const std::string &playername,
3418 const ParticleParameters &p)
3420 // m_env will be NULL if the server is initializing
3424 session_t peer_id = PEER_ID_INEXISTENT;
3426 if (!playername.empty()) {
3427 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3430 peer_id = player->getPeerId();
3431 proto_ver = player->protocol_version;
3434 SendSpawnParticle(peer_id, proto_ver, p);
3437 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3438 ServerActiveObject *attached, const std::string &playername)
3440 // m_env will be NULL if the server is initializing
3444 session_t peer_id = PEER_ID_INEXISTENT;
3446 if (!playername.empty()) {
3447 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3450 peer_id = player->getPeerId();
3451 proto_ver = player->protocol_version;
3454 u16 attached_id = attached ? attached->getId() : 0;
3457 if (attached_id == 0)
3458 id = m_env->addParticleSpawner(p.time);
3460 id = m_env->addParticleSpawner(p.time, attached_id);
3462 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3466 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3468 // m_env will be NULL if the server is initializing
3470 throw ServerError("Can't delete particle spawners during initialisation!");
3472 session_t peer_id = PEER_ID_INEXISTENT;
3473 if (!playername.empty()) {
3474 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3477 peer_id = player->getPeerId();
3480 m_env->deleteParticleSpawner(id);
3481 SendDeleteParticleSpawner(peer_id, id);
3484 bool Server::dynamicAddMedia(std::string filepath,
3485 const u32 token, const std::string &to_player, bool ephemeral)
3487 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3488 auto it = m_media.find(filename);
3489 if (it != m_media.end()) {
3490 // Allow the same path to be "added" again in certain conditions
3491 if (ephemeral || it->second.path != filepath) {
3492 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3493 << "\" already exists in media cache" << std::endl;
3498 // Load the file and add it to our media cache
3499 std::string filedata, raw_hash;
3500 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3505 // Create a copy of the file and swap out the path, this removes the
3506 // requirement that mods keep the file accessible at the original path.
3507 filepath = fs::CreateTempFile();
3508 bool ok = ([&] () -> bool {
3509 if (filepath.empty())
3511 std::ofstream os(filepath.c_str(), std::ios::binary);
3519 errorstream << "Server: failed to create a copy of media file "
3520 << "\"" << filename << "\"" << std::endl;
3521 m_media.erase(filename);
3524 verbosestream << "Server: \"" << filename << "\" temporarily copied to "
3525 << filepath << std::endl;
3527 m_media[filename].path = filepath;
3528 m_media[filename].no_announce = true;
3529 // stepPendingDynMediaCallbacks will clean this up later.
3530 } else if (!to_player.empty()) {
3531 m_media[filename].no_announce = true;
3534 // Push file to existing clients
3535 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3536 pkt << raw_hash << filename << (bool)ephemeral;
3538 NetworkPacket legacy_pkt = pkt;
3540 // Newer clients get asked to fetch the file (asynchronous)
3542 // Older clients have an awful hack that just throws the data at them
3543 legacy_pkt.putLongString(filedata);
3545 std::unordered_set<session_t> delivered, waiting;
3547 ClientInterface::AutoLock clientlock(m_clients);
3548 for (auto &pair : m_clients.getClientList()) {
3549 if (pair.second->getState() == CS_DefinitionsSent && !ephemeral) {
3551 If a client is in the DefinitionsSent state it is too late to
3552 transfer the file via sendMediaAnnouncement() but at the same
3553 time the client cannot accept a media push yet.
3554 Short of artificially delaying the joining process there is no
3555 way for the server to resolve this so we (currently) opt not to.
3557 warningstream << "The media \"" << filename << "\" (dynamic) could "
3558 "not be delivered to " << pair.second->getName()
3559 << " due to a race condition." << std::endl;
3562 if (pair.second->getState() < CS_Active)
3565 const auto proto_ver = pair.second->net_proto_version;
3569 const session_t peer_id = pair.second->peer_id;
3570 if (!to_player.empty() && getPlayerName(peer_id) != to_player)
3573 if (proto_ver < 40) {
3574 delivered.emplace(peer_id);
3576 The network layer only guarantees ordered delivery inside a channel.
3577 Since the very next packet could be one that uses the media, we have
3578 to push the media over ALL channels to ensure it is processed before
3579 it is used. In practice this means channels 1 and 0.
3581 m_clients.send(peer_id, 1, &legacy_pkt, true);
3582 m_clients.send(peer_id, 0, &legacy_pkt, true);
3584 waiting.emplace(peer_id);
3585 Send(peer_id, &pkt);
3590 // Run callback for players that already had the file delivered (legacy-only)
3591 for (session_t peer_id : delivered) {
3592 if (auto player = m_env->getPlayer(peer_id))
3593 getScriptIface()->on_dynamic_media_added(token, player->getName());
3596 // Save all others in our pending state
3597 auto &state = m_pending_dyn_media[token];
3598 state.waiting_players = std::move(waiting);
3599 // regardless of success throw away the callback after a while
3600 state.expiry_timer = 60.0f;
3602 state.filename = filename;
3607 // actions: time-reversed list
3608 // Return value: success/failure
3609 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3610 std::list<std::string> *log)
3612 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3613 ServerMap *map = (ServerMap*)(&m_env->getMap());
3615 // Fail if no actions to handle
3616 if (actions.empty()) {
3618 log->push_back("Nothing to do.");
3625 for (const RollbackAction &action : actions) {
3627 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3630 std::ostringstream os;
3631 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3632 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3634 log->push_back(os.str());
3636 std::ostringstream os;
3637 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3638 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3640 log->push_back(os.str());
3644 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3645 <<" failed"<<std::endl;
3647 // Call it done if less than half failed
3648 return num_failed <= num_tried/2;
3651 // IGameDef interface
3653 IItemDefManager *Server::getItemDefManager()
3658 const NodeDefManager *Server::getNodeDefManager()
3663 ICraftDefManager *Server::getCraftDefManager()
3668 u16 Server::allocateUnknownNodeId(const std::string &name)
3670 return m_nodedef->allocateDummy(name);
3673 IWritableItemDefManager *Server::getWritableItemDefManager()
3678 NodeDefManager *Server::getWritableNodeDefManager()
3683 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3688 const std::vector<ModSpec> & Server::getMods() const
3690 return m_modmgr->getMods();
3693 const ModSpec *Server::getModSpec(const std::string &modname) const
3695 return m_modmgr->getModSpec(modname);
3698 std::string Server::getBuiltinLuaPath()
3700 return porting::path_share + DIR_DELIM + "builtin";
3703 v3f Server::findSpawnPos()
3705 ServerMap &map = m_env->getServerMap();
3707 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3708 return nodeposf * BS;
3710 bool is_good = false;
3711 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3712 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3714 // Try to find a good place a few times
3715 for (s32 i = 0; i < 4000 && !is_good; i++) {
3716 s32 range = MYMIN(1 + i, range_max);
3717 // We're going to try to throw the player to this position
3718 v2s16 nodepos2d = v2s16(
3719 -range + (myrand() % (range * 2)),
3720 -range + (myrand() % (range * 2)));
3721 // Get spawn level at point
3722 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3723 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3724 // signify an unsuitable spawn position, or if outside limits.
3725 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3726 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3729 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3730 // Consecutive empty nodes
3733 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3734 // avoid obstructions in already-generated mapblocks.
3735 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3736 // no obstructions, but mapgen decorations are generated after spawn so
3737 // the player may end up inside one.
3738 for (s32 i = 0; i < 8; i++) {
3739 v3s16 blockpos = getNodeBlockPos(nodepos);
3740 map.emergeBlock(blockpos, true);
3741 content_t c = map.getNode(nodepos).getContent();
3743 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3744 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3745 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3747 if (air_count >= 2) {
3748 // Spawn in lower empty node
3750 nodeposf = intToFloat(nodepos, BS);
3751 // Don't spawn the player outside map boundaries
3752 if (objectpos_over_limit(nodeposf))
3753 // Exit this loop, positions above are probably over limit
3756 // Good position found, cause an exit from main loop
3770 // No suitable spawn point found, return fallback 0,0,0
3771 return v3f(0.0f, 0.0f, 0.0f);
3774 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3776 if (delay == 0.0f) {
3777 // No delay, shutdown immediately
3778 m_shutdown_state.is_requested = true;
3779 // only print to the infostream, a chat message saying
3780 // "Server Shutting Down" is sent when the server destructs.
3781 infostream << "*** Immediate Server shutdown requested." << std::endl;
3782 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3783 // Negative delay, cancel shutdown if requested
3784 m_shutdown_state.reset();
3785 std::wstringstream ws;
3787 ws << L"*** Server shutdown canceled.";
3789 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3790 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3791 // m_shutdown_* are already handled, skip.
3793 } else if (delay > 0.0f) {
3794 // Positive delay, tell the clients when the server will shut down
3795 std::wstringstream ws;
3797 ws << L"*** Server shutting down in "
3798 << duration_to_string(myround(delay)).c_str()
3801 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3802 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3805 m_shutdown_state.trigger(delay, msg, reconnect);
3808 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3811 Try to get an existing player
3813 RemotePlayer *player = m_env->getPlayer(name);
3815 // If player is already connected, cancel
3816 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3817 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3822 If player with the wanted peer_id already exists, cancel.
3824 if (m_env->getPlayer(peer_id)) {
3825 infostream<<"emergePlayer(): Player with wrong name but same"
3826 " peer_id already exists"<<std::endl;
3831 player = new RemotePlayer(name, idef());
3834 bool newplayer = false;
3837 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3839 // Complete init with server parts
3840 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3841 player->protocol_version = proto_version;
3845 m_script->on_newplayer(playersao);
3851 bool Server::registerModStorage(ModMetadata *storage)
3853 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3854 errorstream << "Unable to register same mod storage twice. Storage name: "
3855 << storage->getModName() << std::endl;
3859 m_mod_storages[storage->getModName()] = storage;
3863 void Server::unregisterModStorage(const std::string &name)
3865 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3866 if (it != m_mod_storages.end())
3867 m_mod_storages.erase(name);
3870 void dedicated_server_loop(Server &server, bool &kill)
3872 verbosestream<<"dedicated_server_loop()"<<std::endl;
3874 IntervalLimiter m_profiler_interval;
3876 static thread_local const float steplen =
3877 g_settings->getFloat("dedicated_server_step");
3878 static thread_local const float profiler_print_interval =
3879 g_settings->getFloat("profiler_print_interval");
3882 * The dedicated server loop only does time-keeping (in Server::step) and
3883 * provides a way to main.cpp to kill the server externally (bool &kill).
3887 // This is kind of a hack but can be done like this
3888 // because server.step() is very light
3889 sleep_ms((int)(steplen*1000.0));
3890 server.step(steplen);
3892 if (server.isShutdownRequested() || kill)
3898 if (profiler_print_interval != 0) {
3899 if(m_profiler_interval.step(steplen, profiler_print_interval))
3901 infostream<<"Profiler:"<<std::endl;
3902 g_profiler->print(infostream);
3903 g_profiler->clear();
3908 infostream << "Dedicated server quitting" << std::endl;
3910 if (g_settings->getBool("server_announce"))
3911 ServerList::sendAnnounce(ServerList::AA_DELETE,
3912 server.m_bind_addr.getPort());
3921 bool Server::joinModChannel(const std::string &channel)
3923 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3924 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3927 bool Server::leaveModChannel(const std::string &channel)
3929 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3932 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3934 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3937 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3941 ModChannel* Server::getModChannel(const std::string &channel)
3943 return m_modchannel_mgr->getModChannel(channel);
3946 void Server::broadcastModChannelMessage(const std::string &channel,
3947 const std::string &message, session_t from_peer)
3949 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3953 if (message.size() > STRING_MAX_LEN) {
3954 warningstream << "ModChannel message too long, dropping before sending "
3955 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3956 << channel << ")" << std::endl;
3961 if (from_peer != PEER_ID_SERVER) {
3962 sender = getPlayerName(from_peer);
3965 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3966 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3967 resp_pkt << channel << sender << message;
3968 for (session_t peer_id : peers) {
3970 if (peer_id == from_peer)
3973 Send(peer_id, &resp_pkt);
3976 if (from_peer != PEER_ID_SERVER) {
3977 m_script->on_modchannel_message(channel, sender, message);
3981 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3983 if (lang_code.empty())
3986 auto it = server_translations.find(lang_code);
3987 if (it != server_translations.end())
3988 return &it->second; // Already loaded
3990 // [] will create an entry
3991 auto *translations = &server_translations[lang_code];
3993 std::string suffix = "." + lang_code + ".tr";
3994 for (const auto &i : m_media) {
3995 if (str_ends_with(i.first, suffix)) {
3997 if (fs::ReadFile(i.second.path, data)) {
3998 translations->loadTranslation(data);
4003 return translations;
4006 ModMetadataDatabase *Server::openModStorageDatabase(const std::string &world_path)
4008 std::string world_mt_path = world_path + DIR_DELIM + "world.mt";
4010 if (!world_mt.readConfigFile(world_mt_path.c_str()))
4011 throw BaseException("Cannot read world.mt!");
4013 std::string backend = world_mt.exists("mod_storage_backend") ?
4014 world_mt.get("mod_storage_backend") : "files";
4015 if (backend == "files")
4016 warningstream << "/!\\ You are using the old mod storage files backend. "
4017 << "This backend is deprecated and may be removed in a future release /!\\"
4018 << std::endl << "Switching to SQLite3 is advised, "
4019 << "please read http://wiki.minetest.net/Database_backends." << std::endl;
4021 return openModStorageDatabase(backend, world_path, world_mt);
4024 ModMetadataDatabase *Server::openModStorageDatabase(const std::string &backend,
4025 const std::string &world_path, const Settings &world_mt)
4027 if (backend == "sqlite3")
4028 return new ModMetadataDatabaseSQLite3(world_path);
4030 if (backend == "files")
4031 return new ModMetadataDatabaseFiles(world_path);
4033 if (backend == "dummy")
4034 return new Database_Dummy();
4036 throw BaseException("Mod storage database backend " + backend + " not supported");
4039 bool Server::migrateModStorageDatabase(const GameParams &game_params, const Settings &cmd_args)
4041 std::string migrate_to = cmd_args.get("migrate-mod-storage");
4043 std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt";
4044 if (!world_mt.readConfigFile(world_mt_path.c_str())) {
4045 errorstream << "Cannot read world.mt!" << std::endl;
4049 std::string backend = world_mt.exists("mod_storage_backend") ?
4050 world_mt.get("mod_storage_backend") : "files";
4051 if (backend == migrate_to) {
4052 errorstream << "Cannot migrate: new backend is same"
4053 << " as the old one" << std::endl;
4057 ModMetadataDatabase *srcdb = nullptr;
4058 ModMetadataDatabase *dstdb = nullptr;
4060 bool succeeded = false;
4063 srcdb = Server::openModStorageDatabase(backend, game_params.world_path, world_mt);
4064 dstdb = Server::openModStorageDatabase(migrate_to, game_params.world_path, world_mt);
4068 std::vector<std::string> mod_list;
4069 srcdb->listMods(&mod_list);
4070 for (const std::string &modname : mod_list) {
4072 srcdb->getModEntries(modname, &meta);
4073 for (const auto &pair : meta) {
4074 dstdb->setModEntry(modname, pair.first, pair.second);
4082 actionstream << "Successfully migrated the metadata of "
4083 << mod_list.size() << " mods" << std::endl;
4084 world_mt.set("mod_storage_backend", migrate_to);
4085 if (!world_mt.updateConfigFile(world_mt_path.c_str()))
4086 errorstream << "Failed to update world.mt!" << std::endl;
4088 actionstream << "world.mt updated" << std::endl;
4090 } catch (BaseException &e) {
4091 errorstream << "An error occurred during migration: " << e.what() << std::endl;
4097 if (succeeded && backend == "files") {
4099 const std::string storage_path = game_params.world_path + DIR_DELIM + "mod_storage";
4100 const std::string backup_path = game_params.world_path + DIR_DELIM + "mod_storage.bak";
4101 if (!fs::Rename(storage_path, backup_path))
4102 warningstream << "After migration, " << storage_path
4103 << " could not be renamed to " << backup_path << std::endl;