3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "server/serveractiveobject.h"
41 #include "scripting_server.h"
46 #include "mapgen/mapgen.h"
47 #include "mapgen/mg_biome.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content/mods.h"
51 #include "modchannels.h"
52 #include "serverlist.h"
53 #include "util/string.h"
55 #include "util/serialize.h"
56 #include "util/thread.h"
57 #include "defaultsettings.h"
58 #include "server/mods.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
62 #include "database/database.h"
63 #include "chatmessage.h"
64 #include "chat_interface.h"
65 #include "remoteplayer.h"
66 #include "server/player_sao.h"
67 #include "server/serverinventorymgr.h"
68 #include "translation.h"
70 class ClientNotFoundException : public BaseException
73 ClientNotFoundException(const char *s):
78 class ServerThread : public Thread
82 ServerThread(Server *server):
93 void *ServerThread::run()
95 BEGIN_DEBUG_EXCEPTION_HANDLER
98 * The real business of the server happens on the ServerThread.
100 * AsyncRunStep() runs an actual server step as soon as enough time has
101 * passed (dedicated_server_loop keeps track of that).
102 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
103 * doesn't busy wait) and will process any remaining packets.
107 m_server->AsyncRunStep(true);
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError(e);
114 while (!stopRequested()) {
116 m_server->AsyncRunStep();
120 } catch (con::PeerNotFoundException &e) {
121 infostream<<"Server: PeerNotFoundException"<<std::endl;
122 } catch (ClientNotFoundException &e) {
123 } catch (con::ConnectionBindFailed &e) {
124 m_server->setAsyncFatalError(e.what());
125 } catch (LuaError &e) {
126 m_server->setAsyncFatalError(e);
130 END_DEBUG_EXCEPTION_HANDLER
135 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
137 if(pos_exists) *pos_exists = false;
142 if(pos_exists) *pos_exists = true;
147 ServerActiveObject *sao = env->getActiveObject(object);
150 if(pos_exists) *pos_exists = true;
151 return sao->getBasePosition(); }
156 void Server::ShutdownState::reset()
160 should_reconnect = false;
161 is_requested = false;
164 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
168 should_reconnect = reconnect;
171 void Server::ShutdownState::tick(float dtime, Server *server)
177 static const float shutdown_msg_times[] =
179 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
182 // Automated messages
183 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
184 for (float t : shutdown_msg_times) {
185 // If shutdown timer matches an automessage, shot it
186 if (m_timer > t && m_timer - dtime < t) {
187 std::wstring periodicMsg = getShutdownTimerMessage();
189 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
190 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
197 if (m_timer < 0.0f) {
203 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
205 std::wstringstream ws;
206 ws << L"*** Server shutting down in "
207 << duration_to_string(myround(m_timer)).c_str() << ".";
216 const std::string &path_world,
217 const SubgameSpec &gamespec,
218 bool simple_singleplayer_mode,
221 ChatInterface *iface,
222 std::string *on_shutdown_errmsg
224 m_bind_addr(bind_addr),
225 m_path_world(path_world),
226 m_gamespec(gamespec),
227 m_simple_singleplayer_mode(simple_singleplayer_mode),
228 m_dedicated(dedicated),
229 m_async_fatal_error(""),
230 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
233 m_bind_addr.isIPv6(),
235 m_itemdef(createItemDefManager()),
236 m_nodedef(createNodeDefManager()),
237 m_craftdef(createCraftDefManager()),
238 m_thread(new ServerThread(this)),
241 m_on_shutdown_errmsg(on_shutdown_errmsg),
242 m_modchannel_mgr(new ModChannelMgr())
244 if (m_path_world.empty())
245 throw ServerError("Supplied empty world path");
247 if (!gamespec.isValid())
248 throw ServerError("Supplied invalid gamespec");
251 m_metrics_backend = std::unique_ptr<MetricsBackend>(createPrometheusMetricsBackend());
253 m_metrics_backend = std::unique_ptr<MetricsBackend>(new MetricsBackend());
256 m_uptime_counter = m_metrics_backend->addCounter("minetest_core_server_uptime", "Server uptime (in seconds)");
257 m_player_gauge = m_metrics_backend->addGauge("minetest_core_player_number", "Number of connected players");
259 m_timeofday_gauge = m_metrics_backend->addGauge(
260 "minetest_core_timeofday",
261 "Time of day value");
263 m_lag_gauge = m_metrics_backend->addGauge(
264 "minetest_core_latency",
265 "Latency value (in seconds)");
267 m_aom_buffer_counter = m_metrics_backend->addCounter(
268 "minetest_core_aom_generated_count",
269 "Number of active object messages generated");
271 m_packet_recv_counter = m_metrics_backend->addCounter(
272 "minetest_core_server_packet_recv",
273 "Processable packets received");
275 m_packet_recv_processed_counter = m_metrics_backend->addCounter(
276 "minetest_core_server_packet_recv_processed",
277 "Valid received packets processed");
279 m_lag_gauge->set(g_settings->getFloat("dedicated_server_step"));
285 // Send shutdown message
286 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
287 L"*** Server shutting down"));
290 MutexAutoLock envlock(m_env_mutex);
292 infostream << "Server: Saving players" << std::endl;
293 m_env->saveLoadedPlayers();
295 infostream << "Server: Kicking players" << std::endl;
296 std::string kick_msg;
297 bool reconnect = false;
298 if (isShutdownRequested()) {
299 reconnect = m_shutdown_state.should_reconnect;
300 kick_msg = m_shutdown_state.message;
302 if (kick_msg.empty()) {
303 kick_msg = g_settings->get("kick_msg_shutdown");
305 m_env->saveLoadedPlayers(true);
306 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
307 kick_msg, reconnect);
310 actionstream << "Server: Shutting down" << std::endl;
312 // Do this before stopping the server in case mapgen callbacks need to access
313 // server-controlled resources (like ModStorages). Also do them before
314 // shutdown callbacks since they may modify state that is finalized in a
317 m_emerge->stopThreads();
320 MutexAutoLock envlock(m_env_mutex);
322 // Execute script shutdown hooks
323 infostream << "Executing shutdown hooks" << std::endl;
325 m_script->on_shutdown();
326 } catch (ModError &e) {
327 errorstream << "ModError: " << e.what() << std::endl;
328 if (m_on_shutdown_errmsg) {
329 if (m_on_shutdown_errmsg->empty()) {
330 *m_on_shutdown_errmsg = std::string("ModError: ") + e.what();
332 *m_on_shutdown_errmsg += std::string("\nModError: ") + e.what();
337 infostream << "Server: Saving environment metadata" << std::endl;
347 // Delete things in the reverse order of creation
356 // Deinitialize scripting
357 infostream << "Server: Deinitializing scripting" << std::endl;
359 delete m_startup_server_map; // if available
360 delete m_game_settings;
362 while (!m_unsent_map_edit_queue.empty()) {
363 delete m_unsent_map_edit_queue.front();
364 m_unsent_map_edit_queue.pop();
370 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
371 if (m_simple_singleplayer_mode)
372 infostream << " in simple singleplayer mode" << std::endl;
374 infostream << std::endl;
375 infostream << "- world: " << m_path_world << std::endl;
376 infostream << "- game: " << m_gamespec.path << std::endl;
378 m_game_settings = Settings::createLayer(SL_GAME);
380 // Create world if it doesn't exist
382 loadGameConfAndInitWorld(m_path_world,
383 fs::GetFilenameFromPath(m_path_world.c_str()),
385 } catch (const BaseException &e) {
386 throw ServerError(std::string("Failed to initialize world: ") + e.what());
389 // Create emerge manager
390 m_emerge = new EmergeManager(this);
392 // Create ban manager
393 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
394 m_banmanager = new BanManager(ban_path);
396 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
397 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
398 // complain about mods with unsatisfied dependencies
399 if (!m_modmgr->isConsistent()) {
400 m_modmgr->printUnsatisfiedModsError();
404 MutexAutoLock envlock(m_env_mutex);
406 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
407 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge, m_metrics_backend.get());
408 m_startup_server_map = servermap;
410 // Initialize scripting
411 infostream << "Server: Initializing Lua" << std::endl;
413 m_script = new ServerScripting(this);
415 // Must be created before mod loading because we have some inventory creation
416 m_inventory_mgr = std::unique_ptr<ServerInventoryManager>(new ServerInventoryManager());
418 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
420 m_modmgr->loadMods(m_script);
422 // Read Textures and calculate sha1 sums
425 // Apply item aliases in the node definition manager
426 m_nodedef->updateAliases(m_itemdef);
428 // Apply texture overrides from texturepack/override.txt
429 std::vector<std::string> paths;
430 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
431 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
432 for (const std::string &path : paths) {
433 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
434 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
435 m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
438 m_nodedef->setNodeRegistrationStatus(true);
440 // Perform pending node name resolutions
441 m_nodedef->runNodeResolveCallbacks();
443 // unmap node names in cross-references
444 m_nodedef->resolveCrossrefs();
446 // init the recipe hashes to speed up crafting
447 m_craftdef->initHashes(this);
449 // Initialize Environment
450 m_startup_server_map = nullptr; // Ownership moved to ServerEnvironment
451 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
453 m_inventory_mgr->setEnv(m_env);
454 m_clients.setEnv(m_env);
456 if (!servermap->settings_mgr.makeMapgenParams())
457 FATAL_ERROR("Couldn't create any mapgen type");
459 // Initialize mapgens
460 m_emerge->initMapgens(servermap->getMapgenParams());
462 if (g_settings->getBool("enable_rollback_recording")) {
463 // Create rollback manager
464 m_rollback = new RollbackManager(m_path_world, this);
467 // Give environment reference to scripting api
468 m_script->initializeEnvironment(m_env);
470 // Register us to receive map edit events
471 servermap->addEventReceiver(this);
475 // Those settings can be overwritten in world.mt, they are
476 // intended to be cached after environment loading.
477 m_liquid_transform_every = g_settings->getFloat("liquid_update");
478 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
479 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
480 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
487 infostream << "Starting server on " << m_bind_addr.serializeString()
488 << "..." << std::endl;
490 // Stop thread if already running
493 // Initialize connection
494 m_con->SetTimeoutMs(30);
495 m_con->Serve(m_bind_addr);
500 // ASCII art for the win!
502 << " .__ __ __ " << std::endl
503 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
504 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
505 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
506 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
507 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
508 actionstream << "World at [" << m_path_world << "]" << std::endl;
509 actionstream << "Server for gameid=\"" << m_gamespec.id
510 << "\" listening on " << m_bind_addr.serializeString() << ":"
511 << m_bind_addr.getPort() << "." << std::endl;
516 infostream<<"Server: Stopping and waiting threads"<<std::endl;
518 // Stop threads (set run=false first so both start stopping)
522 infostream<<"Server: Threads stopped"<<std::endl;
525 void Server::step(float dtime)
531 MutexAutoLock lock(m_step_dtime_mutex);
532 m_step_dtime += dtime;
534 // Throw if fatal error occurred in thread
535 std::string async_err = m_async_fatal_error.get();
536 if (!async_err.empty()) {
537 if (!m_simple_singleplayer_mode) {
538 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
539 g_settings->get("kick_msg_crash"),
540 g_settings->getBool("ask_reconnect_on_crash"));
542 throw ServerError("AsyncErr: " + async_err);
546 void Server::AsyncRunStep(bool initial_step)
551 MutexAutoLock lock1(m_step_dtime_mutex);
552 dtime = m_step_dtime;
556 // Send blocks to clients
560 if((dtime < 0.001) && !initial_step)
563 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
566 MutexAutoLock lock1(m_step_dtime_mutex);
567 m_step_dtime -= dtime;
573 m_uptime_counter->increment(dtime);
578 Update time of day and overall game time
580 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
583 Send to clients at constant intervals
586 m_time_of_day_send_timer -= dtime;
587 if (m_time_of_day_send_timer < 0.0) {
588 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
589 u16 time = m_env->getTimeOfDay();
590 float time_speed = g_settings->getFloat("time_speed");
591 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
593 m_timeofday_gauge->set(time);
597 MutexAutoLock lock(m_env_mutex);
598 // Figure out and report maximum lag to environment
599 float max_lag = m_env->getMaxLagEstimate();
600 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
602 if(dtime > 0.1 && dtime > max_lag * 2.0)
603 infostream<<"Server: Maximum lag peaked to "<<dtime
607 m_env->reportMaxLagEstimate(max_lag);
612 static const float map_timer_and_unload_dtime = 2.92;
613 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
615 MutexAutoLock lock(m_env_mutex);
616 // Run Map's timers and unload unused data
617 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
618 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
619 g_settings->getFloat("server_unload_unused_data_timeout"),
624 Listen to the admin chat, if available
627 if (!m_admin_chat->command_queue.empty()) {
628 MutexAutoLock lock(m_env_mutex);
629 while (!m_admin_chat->command_queue.empty()) {
630 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
631 handleChatInterfaceEvent(evt);
635 m_admin_chat->outgoing_queue.push_back(
636 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
643 /* Transform liquids */
644 m_liquid_transform_timer += dtime;
645 if(m_liquid_transform_timer >= m_liquid_transform_every)
647 m_liquid_transform_timer -= m_liquid_transform_every;
649 MutexAutoLock lock(m_env_mutex);
651 ScopeProfiler sp(g_profiler, "Server: liquid transform");
653 std::map<v3s16, MapBlock*> modified_blocks;
654 m_env->getMap().transformLiquids(modified_blocks, m_env);
657 Set the modified blocks unsent for all the clients
659 if (!modified_blocks.empty()) {
660 SetBlocksNotSent(modified_blocks);
663 m_clients.step(dtime);
665 // increase/decrease lag gauge gradually
666 if (m_lag_gauge->get() > dtime) {
667 m_lag_gauge->decrement(dtime/100);
669 m_lag_gauge->increment(dtime/100);
673 float &counter = m_step_pending_dyn_media_timer;
675 if (counter >= 5.0f) {
676 stepPendingDynMediaCallbacks(counter);
683 // send masterserver announce
685 float &counter = m_masterserver_timer;
686 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
687 g_settings->getBool("server_announce")) {
688 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
689 ServerList::AA_START,
690 m_bind_addr.getPort(),
691 m_clients.getPlayerNames(),
692 m_uptime_counter->get(),
693 m_env->getGameTime(),
696 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
706 Check added and deleted active objects
709 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
710 MutexAutoLock envlock(m_env_mutex);
713 const RemoteClientMap &clients = m_clients.getClientList();
714 ScopeProfiler sp(g_profiler, "Server: update objects within range");
716 m_player_gauge->set(clients.size());
717 for (const auto &client_it : clients) {
718 RemoteClient *client = client_it.second;
720 if (client->getState() < CS_DefinitionsSent)
723 // This can happen if the client times out somehow
724 if (!m_env->getPlayer(client->peer_id))
727 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
731 SendActiveObjectRemoveAdd(client, playersao);
735 // Save mod storages if modified
736 m_mod_storage_save_timer -= dtime;
737 if (m_mod_storage_save_timer <= 0.0f) {
738 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
740 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
741 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
742 if (it->second->isModified()) {
743 it->second->save(getModStoragePath());
748 infostream << "Saved " << n << " modified mod storages." << std::endl;
756 MutexAutoLock envlock(m_env_mutex);
757 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
760 // Value = data sent by object
761 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
763 // Get active object messages from environment
764 ActiveObjectMessage aom(0);
767 if (!m_env->getActiveObjectMessage(&aom))
770 std::vector<ActiveObjectMessage>* message_list = nullptr;
771 auto n = buffered_messages.find(aom.id);
772 if (n == buffered_messages.end()) {
773 message_list = new std::vector<ActiveObjectMessage>;
774 buffered_messages[aom.id] = message_list;
776 message_list = n->second;
778 message_list->push_back(std::move(aom));
782 m_aom_buffer_counter->increment(aom_count);
785 const RemoteClientMap &clients = m_clients.getClientList();
786 // Route data to every client
787 std::string reliable_data, unreliable_data;
788 for (const auto &client_it : clients) {
789 reliable_data.clear();
790 unreliable_data.clear();
791 RemoteClient *client = client_it.second;
792 PlayerSAO *player = getPlayerSAO(client->peer_id);
793 // Go through all objects in message buffer
794 for (const auto &buffered_message : buffered_messages) {
795 // If object does not exist or is not known by client, skip it
796 u16 id = buffered_message.first;
797 ServerActiveObject *sao = m_env->getActiveObject(id);
798 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
801 // Get message list of object
802 std::vector<ActiveObjectMessage>* list = buffered_message.second;
803 // Go through every message
804 for (const ActiveObjectMessage &aom : *list) {
805 // Send position updates to players who do not see the attachment
806 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
807 if (sao->getId() == player->getId())
810 // Do not send position updates for attached players
811 // as long the parent is known to the client
812 ServerActiveObject *parent = sao->getParent();
813 if (parent && client->m_known_objects.find(parent->getId()) !=
814 client->m_known_objects.end())
818 // Add full new data to appropriate buffer
819 std::string &buffer = aom.reliable ? reliable_data : unreliable_data;
821 writeU16((u8*) idbuf, aom.id);
824 buffer.append(idbuf, sizeof(idbuf));
825 buffer.append(serializeString16(aom.datastring));
829 reliable_data and unreliable_data are now ready.
832 if (!reliable_data.empty()) {
833 SendActiveObjectMessages(client->peer_id, reliable_data);
836 if (!unreliable_data.empty()) {
837 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
842 // Clear buffered_messages
843 for (auto &buffered_message : buffered_messages) {
844 delete buffered_message.second;
849 Send queued-for-sending map edit events.
852 // We will be accessing the environment
853 MutexAutoLock lock(m_env_mutex);
855 // Don't send too many at a time
858 // Single change sending is disabled if queue size is not small
859 bool disable_single_change_sending = false;
860 if(m_unsent_map_edit_queue.size() >= 4)
861 disable_single_change_sending = true;
863 int event_count = m_unsent_map_edit_queue.size();
865 // We'll log the amount of each
868 std::list<v3s16> node_meta_updates;
870 while (!m_unsent_map_edit_queue.empty()) {
871 MapEditEvent* event = m_unsent_map_edit_queue.front();
872 m_unsent_map_edit_queue.pop();
874 // Players far away from the change are stored here.
875 // Instead of sending the changes, MapBlocks are set not sent
877 std::unordered_set<u16> far_players;
879 switch (event->type) {
882 prof.add("MEET_ADDNODE", 1);
883 sendAddNode(event->p, event->n, &far_players,
884 disable_single_change_sending ? 5 : 30,
885 event->type == MEET_ADDNODE);
887 case MEET_REMOVENODE:
888 prof.add("MEET_REMOVENODE", 1);
889 sendRemoveNode(event->p, &far_players,
890 disable_single_change_sending ? 5 : 30);
892 case MEET_BLOCK_NODE_METADATA_CHANGED: {
893 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
894 if (!event->is_private_change) {
895 // Don't send the change yet. Collect them to eliminate dupes.
896 node_meta_updates.remove(event->p);
897 node_meta_updates.push_back(event->p);
900 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
901 getNodeBlockPos(event->p))) {
902 block->raiseModified(MOD_STATE_WRITE_NEEDED,
903 MOD_REASON_REPORT_META_CHANGE);
908 prof.add("MEET_OTHER", 1);
909 for (const v3s16 &modified_block : event->modified_blocks) {
910 m_clients.markBlockposAsNotSent(modified_block);
914 prof.add("unknown", 1);
915 warningstream << "Server: Unknown MapEditEvent "
916 << ((u32)event->type) << std::endl;
921 Set blocks not sent to far players
923 if (!far_players.empty()) {
924 // Convert list format to that wanted by SetBlocksNotSent
925 std::map<v3s16, MapBlock*> modified_blocks2;
926 for (const v3s16 &modified_block : event->modified_blocks) {
927 modified_blocks2[modified_block] =
928 m_env->getMap().getBlockNoCreateNoEx(modified_block);
931 // Set blocks not sent
932 for (const u16 far_player : far_players) {
933 if (RemoteClient *client = getClient(far_player))
934 client->SetBlocksNotSent(modified_blocks2);
941 if (event_count >= 5) {
942 infostream << "Server: MapEditEvents:" << std::endl;
943 prof.print(infostream);
944 } else if (event_count != 0) {
945 verbosestream << "Server: MapEditEvents:" << std::endl;
946 prof.print(verbosestream);
949 // Send all metadata updates
950 if (node_meta_updates.size())
951 sendMetadataChanged(node_meta_updates);
955 Trigger emerge thread
956 Doing this every 2s is left over from old code, unclear if this is still needed.
959 float &counter = m_emergethread_trigger_timer;
961 if (counter <= 0.0f) {
964 m_emerge->startThreads();
968 // Save map, players and auth stuff
970 float &counter = m_savemap_timer;
972 static thread_local const float save_interval =
973 g_settings->getFloat("server_map_save_interval");
974 if (counter >= save_interval) {
976 MutexAutoLock lock(m_env_mutex);
978 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
981 if (m_banmanager->isModified()) {
982 m_banmanager->save();
985 // Save changed parts of map
986 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
989 m_env->saveLoadedPlayers();
991 // Save environment metadata
996 m_shutdown_state.tick(dtime, this);
999 void Server::Receive()
1009 In the first iteration *wait* for a packet, afterwards process
1010 all packets that are immediately available (no waiting).
1013 m_con->Receive(&pkt);
1016 if (!m_con->TryReceive(&pkt))
1020 peer_id = pkt.getPeerId();
1021 m_packet_recv_counter->increment();
1023 m_packet_recv_processed_counter->increment();
1024 } catch (const con::InvalidIncomingDataException &e) {
1025 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1026 << e.what() << std::endl;
1027 } catch (const SerializationError &e) {
1028 infostream << "Server::Receive(): SerializationError: what()="
1029 << e.what() << std::endl;
1030 } catch (const ClientStateError &e) {
1031 errorstream << "ProcessData: peer=" << peer_id << " what()="
1032 << e.what() << std::endl;
1033 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1034 L"Try reconnecting or updating your client");
1035 } catch (const con::PeerNotFoundException &e) {
1037 } catch (const con::NoIncomingDataException &e) {
1043 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1045 std::string playername;
1046 PlayerSAO *playersao = NULL;
1049 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1051 playername = client->getName();
1052 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1054 } catch (std::exception &e) {
1060 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1062 // If failed, cancel
1063 if (!playersao || !player) {
1064 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1065 actionstream << "Server: Failed to emerge player \"" << playername
1066 << "\" (player allocated to an another client)" << std::endl;
1067 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1068 L"name. If your client closed unexpectedly, try again in "
1071 errorstream << "Server: " << playername << ": Failed to emerge player"
1073 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1079 Send complete position information
1081 SendMovePlayer(peer_id);
1084 SendPlayerPrivileges(peer_id);
1086 // Send inventory formspec
1087 SendPlayerInventoryFormspec(peer_id);
1090 SendInventory(playersao, false);
1092 // Send HP or death screen
1093 if (playersao->isDead())
1094 SendDeathscreen(peer_id, false, v3f(0,0,0));
1096 SendPlayerHP(peer_id);
1099 SendPlayerBreath(playersao);
1105 Address addr = getPeerAddress(player->getPeerId());
1106 std::string ip_str = addr.serializeString();
1107 const std::vector<std::string> &names = m_clients.getPlayerNames();
1109 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1111 for (const std::string &name : names) {
1112 actionstream << name << " ";
1115 actionstream << player->getName() <<std::endl;
1120 inline void Server::handleCommand(NetworkPacket *pkt)
1122 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1123 (this->*opHandle.handler)(pkt);
1126 void Server::ProcessData(NetworkPacket *pkt)
1128 // Environment is locked first.
1129 MutexAutoLock envlock(m_env_mutex);
1131 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1132 u32 peer_id = pkt->getPeerId();
1135 Address address = getPeerAddress(peer_id);
1136 std::string addr_s = address.serializeString();
1138 if(m_banmanager->isIpBanned(addr_s)) {
1139 std::string ban_name = m_banmanager->getBanName(addr_s);
1140 infostream << "Server: A banned client tried to connect from "
1141 << addr_s << "; banned name was "
1142 << ban_name << std::endl;
1143 // This actually doesn't seem to transfer to the client
1144 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1145 + utf8_to_wide(ban_name));
1149 catch(con::PeerNotFoundException &e) {
1151 * no peer for this packet found
1152 * most common reason is peer timeout, e.g. peer didn't
1153 * respond for some time, your server was overloaded or
1156 infostream << "Server::ProcessData(): Canceling: peer "
1157 << peer_id << " not found" << std::endl;
1162 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1164 // Command must be handled into ToServerCommandHandler
1165 if (command >= TOSERVER_NUM_MSG_TYPES) {
1166 infostream << "Server: Ignoring unknown command "
1167 << command << std::endl;
1171 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1176 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1178 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1179 errorstream << "Server::ProcessData(): Cancelling: Peer"
1180 " serialization format invalid or not initialized."
1181 " Skipping incoming command=" << command << std::endl;
1185 /* Handle commands related to client startup */
1186 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1191 if (m_clients.getClientState(peer_id) < CS_Active) {
1192 if (command == TOSERVER_PLAYERPOS) return;
1194 errorstream << "Got packet command: " << command << " for peer id "
1195 << peer_id << " but client isn't active yet. Dropping packet "
1201 } catch (SendFailedException &e) {
1202 errorstream << "Server::ProcessData(): SendFailedException: "
1203 << "what=" << e.what()
1205 } catch (PacketError &e) {
1206 actionstream << "Server::ProcessData(): PacketError: "
1207 << "what=" << e.what()
1212 void Server::setTimeOfDay(u32 time)
1214 m_env->setTimeOfDay(time);
1215 m_time_of_day_send_timer = 0;
1218 void Server::onMapEditEvent(const MapEditEvent &event)
1220 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1223 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1226 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1228 std::vector<session_t> clients = m_clients.getClientIDs();
1230 // Set the modified blocks unsent for all the clients
1231 for (const session_t client_id : clients) {
1232 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1233 client->SetBlocksNotSent(block);
1238 void Server::peerAdded(con::Peer *peer)
1240 verbosestream<<"Server::peerAdded(): peer->id="
1241 <<peer->id<<std::endl;
1243 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1246 void Server::deletingPeer(con::Peer *peer, bool timeout)
1248 verbosestream<<"Server::deletingPeer(): peer->id="
1249 <<peer->id<<", timeout="<<timeout<<std::endl;
1251 m_clients.event(peer->id, CSE_Disconnect);
1252 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1255 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1257 *retval = m_con->getPeerStat(peer_id,type);
1258 return *retval != -1;
1261 bool Server::getClientInfo(session_t peer_id, ClientInfo &ret)
1264 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1271 ret.state = client->getState();
1272 ret.addr = client->getAddress();
1273 ret.uptime = client->uptime();
1274 ret.ser_vers = client->serialization_version;
1275 ret.prot_vers = client->net_proto_version;
1277 ret.major = client->getMajor();
1278 ret.minor = client->getMinor();
1279 ret.patch = client->getPatch();
1280 ret.vers_string = client->getFullVer();
1282 ret.lang_code = client->getLangCode();
1289 void Server::handlePeerChanges()
1291 while(!m_peer_change_queue.empty())
1293 con::PeerChange c = m_peer_change_queue.front();
1294 m_peer_change_queue.pop();
1296 verbosestream<<"Server: Handling peer change: "
1297 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1302 case con::PEER_ADDED:
1303 m_clients.CreateClient(c.peer_id);
1306 case con::PEER_REMOVED:
1307 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1311 FATAL_ERROR("Invalid peer change event received!");
1317 void Server::printToConsoleOnly(const std::string &text)
1320 m_admin_chat->outgoing_queue.push_back(
1321 new ChatEventChat("", utf8_to_wide(text)));
1323 std::cout << text << std::endl;
1327 void Server::Send(NetworkPacket *pkt)
1329 Send(pkt->getPeerId(), pkt);
1332 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1334 m_clients.send(peer_id,
1335 clientCommandFactoryTable[pkt->getCommand()].channel,
1337 clientCommandFactoryTable[pkt->getCommand()].reliable);
1340 void Server::SendMovement(session_t peer_id)
1342 std::ostringstream os(std::ios_base::binary);
1344 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1346 pkt << g_settings->getFloat("movement_acceleration_default");
1347 pkt << g_settings->getFloat("movement_acceleration_air");
1348 pkt << g_settings->getFloat("movement_acceleration_fast");
1349 pkt << g_settings->getFloat("movement_speed_walk");
1350 pkt << g_settings->getFloat("movement_speed_crouch");
1351 pkt << g_settings->getFloat("movement_speed_fast");
1352 pkt << g_settings->getFloat("movement_speed_climb");
1353 pkt << g_settings->getFloat("movement_speed_jump");
1354 pkt << g_settings->getFloat("movement_liquid_fluidity");
1355 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1356 pkt << g_settings->getFloat("movement_liquid_sink");
1357 pkt << g_settings->getFloat("movement_gravity");
1362 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1364 if (playersao->isImmortal())
1367 session_t peer_id = playersao->getPeerID();
1368 bool is_alive = !playersao->isDead();
1371 SendPlayerHP(peer_id);
1373 DiePlayer(peer_id, reason);
1376 void Server::SendHP(session_t peer_id, u16 hp)
1378 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1383 void Server::SendBreath(session_t peer_id, u16 breath)
1385 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1386 pkt << (u16) breath;
1390 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1391 const std::string &custom_reason, bool reconnect)
1393 assert(reason < SERVER_ACCESSDENIED_MAX);
1395 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1397 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1398 pkt << custom_reason;
1399 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1400 reason == SERVER_ACCESSDENIED_CRASH)
1401 pkt << custom_reason << (u8)reconnect;
1405 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1407 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1412 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1413 v3f camera_point_target)
1415 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1416 pkt << set_camera_point_target << camera_point_target;
1420 void Server::SendItemDef(session_t peer_id,
1421 IItemDefManager *itemdef, u16 protocol_version)
1423 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1427 u32 length of the next item
1428 zlib-compressed serialized ItemDefManager
1430 std::ostringstream tmp_os(std::ios::binary);
1431 itemdef->serialize(tmp_os, protocol_version);
1432 std::ostringstream tmp_os2(std::ios::binary);
1433 compressZlib(tmp_os.str(), tmp_os2);
1434 pkt.putLongString(tmp_os2.str());
1437 verbosestream << "Server: Sending item definitions to id(" << peer_id
1438 << "): size=" << pkt.getSize() << std::endl;
1443 void Server::SendNodeDef(session_t peer_id,
1444 const NodeDefManager *nodedef, u16 protocol_version)
1446 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1450 u32 length of the next item
1451 zlib-compressed serialized NodeDefManager
1453 std::ostringstream tmp_os(std::ios::binary);
1454 nodedef->serialize(tmp_os, protocol_version);
1455 std::ostringstream tmp_os2(std::ios::binary);
1456 compressZlib(tmp_os.str(), tmp_os2);
1458 pkt.putLongString(tmp_os2.str());
1461 verbosestream << "Server: Sending node definitions to id(" << peer_id
1462 << "): size=" << pkt.getSize() << std::endl;
1468 Non-static send methods
1471 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1473 RemotePlayer *player = sao->getPlayer();
1475 // Do not send new format to old clients
1476 incremental &= player->protocol_version >= 38;
1478 UpdateCrafting(player);
1484 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1486 std::ostringstream os(std::ios::binary);
1487 sao->getInventory()->serialize(os, incremental);
1488 sao->getInventory()->setModified(false);
1489 player->setModified(true);
1491 const std::string &s = os.str();
1492 pkt.putRawString(s.c_str(), s.size());
1496 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1498 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1500 u8 type = message.type;
1501 pkt << version << type << message.sender << message.message
1502 << static_cast<u64>(message.timestamp);
1504 if (peer_id != PEER_ID_INEXISTENT) {
1505 RemotePlayer *player = m_env->getPlayer(peer_id);
1511 m_clients.sendToAll(&pkt);
1515 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1516 const std::string &formname)
1518 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1519 if (formspec.empty()){
1520 //the client should close the formspec
1521 //but make sure there wasn't another one open in meantime
1522 const auto it = m_formspec_state_data.find(peer_id);
1523 if (it != m_formspec_state_data.end() && it->second == formname) {
1524 m_formspec_state_data.erase(peer_id);
1526 pkt.putLongString("");
1528 m_formspec_state_data[peer_id] = formname;
1529 pkt.putLongString(formspec);
1536 // Spawns a particle on peer with peer_id
1537 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1538 const ParticleParameters &p)
1540 static thread_local const float radius =
1541 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1543 if (peer_id == PEER_ID_INEXISTENT) {
1544 std::vector<session_t> clients = m_clients.getClientIDs();
1545 const v3f pos = p.pos * BS;
1546 const float radius_sq = radius * radius;
1548 for (const session_t client_id : clients) {
1549 RemotePlayer *player = m_env->getPlayer(client_id);
1553 PlayerSAO *sao = player->getPlayerSAO();
1557 // Do not send to distant clients
1558 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1561 SendSpawnParticle(client_id, player->protocol_version, p);
1565 assert(protocol_version != 0);
1567 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1570 // NetworkPacket and iostreams are incompatible...
1571 std::ostringstream oss(std::ios_base::binary);
1572 p.serialize(oss, protocol_version);
1573 pkt.putRawString(oss.str());
1579 // Adds a ParticleSpawner on peer with peer_id
1580 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1581 const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1583 static thread_local const float radius =
1584 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1586 if (peer_id == PEER_ID_INEXISTENT) {
1587 std::vector<session_t> clients = m_clients.getClientIDs();
1588 const v3f pos = (p.minpos + p.maxpos) / 2.0f * BS;
1589 const float radius_sq = radius * radius;
1590 /* Don't send short-lived spawners to distant players.
1591 * This could be replaced with proper tracking at some point. */
1592 const bool distance_check = !attached_id && p.time <= 1.0f;
1594 for (const session_t client_id : clients) {
1595 RemotePlayer *player = m_env->getPlayer(client_id);
1599 if (distance_check) {
1600 PlayerSAO *sao = player->getPlayerSAO();
1603 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1607 SendAddParticleSpawner(client_id, player->protocol_version,
1608 p, attached_id, id);
1612 assert(protocol_version != 0);
1614 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1616 pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
1617 << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
1618 << p.minsize << p.maxsize << p.collisiondetection;
1620 pkt.putLongString(p.texture);
1622 pkt << id << p.vertical << p.collision_removal << attached_id;
1624 std::ostringstream os(std::ios_base::binary);
1625 p.animation.serialize(os, protocol_version);
1626 pkt.putRawString(os.str());
1628 pkt << p.glow << p.object_collision;
1629 pkt << p.node.param0 << p.node.param2 << p.node_tile;
1634 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1636 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1640 if (peer_id != PEER_ID_INEXISTENT)
1643 m_clients.sendToAll(&pkt);
1647 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1649 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1651 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1652 << form->text << form->number << form->item << form->dir
1653 << form->align << form->offset << form->world_pos << form->size
1654 << form->z_index << form->text2 << form->style;
1659 void Server::SendHUDRemove(session_t peer_id, u32 id)
1661 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1666 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1668 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1669 pkt << id << (u8) stat;
1673 case HUD_STAT_SCALE:
1674 case HUD_STAT_ALIGN:
1675 case HUD_STAT_OFFSET:
1676 pkt << *(v2f *) value;
1680 case HUD_STAT_TEXT2:
1681 pkt << *(std::string *) value;
1683 case HUD_STAT_WORLD_POS:
1684 pkt << *(v3f *) value;
1687 pkt << *(v2s32 *) value;
1689 default: // all other types
1690 pkt << *(u32 *) value;
1697 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1699 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1701 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1703 pkt << flags << mask;
1708 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1710 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1711 pkt << param << value;
1715 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1717 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1719 // Handle prior clients here
1720 if (m_clients.getProtocolVersion(peer_id) < 39) {
1721 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1723 for (const std::string& texture : params.textures)
1726 pkt << params.clouds;
1727 } else { // Handle current clients and future clients
1728 pkt << params.bgcolor << params.type
1729 << params.clouds << params.fog_sun_tint
1730 << params.fog_moon_tint << params.fog_tint_type;
1732 if (params.type == "skybox") {
1733 pkt << (u16) params.textures.size();
1734 for (const std::string &texture : params.textures)
1736 } else if (params.type == "regular") {
1737 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1738 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1739 << params.sky_color.night_sky << params.sky_color.night_horizon
1740 << params.sky_color.indoors;
1747 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1749 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1750 pkt << params.visible << params.texture
1751 << params.tonemap << params.sunrise
1752 << params.sunrise_visible << params.scale;
1756 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1758 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1760 pkt << params.visible << params.texture
1761 << params.tonemap << params.scale;
1765 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1767 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1769 pkt << params.visible << params.count
1770 << params.starcolor << params.scale;
1775 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1777 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1778 pkt << params.density << params.color_bright << params.color_ambient
1779 << params.height << params.thickness << params.speed;
1783 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1786 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1789 pkt << do_override << (u16) (ratio * 65535);
1794 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1796 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1797 pkt << time << time_speed;
1799 if (peer_id == PEER_ID_INEXISTENT) {
1800 m_clients.sendToAll(&pkt);
1807 void Server::SendPlayerHP(session_t peer_id)
1809 PlayerSAO *playersao = getPlayerSAO(peer_id);
1812 SendHP(peer_id, playersao->getHP());
1813 m_script->player_event(playersao,"health_changed");
1815 // Send to other clients
1816 playersao->sendPunchCommand();
1819 void Server::SendPlayerBreath(PlayerSAO *sao)
1823 m_script->player_event(sao, "breath_changed");
1824 SendBreath(sao->getPeerID(), sao->getBreath());
1827 void Server::SendMovePlayer(session_t peer_id)
1829 RemotePlayer *player = m_env->getPlayer(peer_id);
1831 PlayerSAO *sao = player->getPlayerSAO();
1834 // Send attachment updates instantly to the client prior updating position
1835 sao->sendOutdatedData();
1837 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1838 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1841 v3f pos = sao->getBasePosition();
1842 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1843 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1844 << " pitch=" << sao->getLookPitch()
1845 << " yaw=" << sao->getRotation().Y
1852 void Server::SendPlayerFov(session_t peer_id)
1854 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1856 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1857 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1862 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1863 f32 animation_speed)
1865 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1868 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1869 << animation_frames[3] << animation_speed;
1874 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1876 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1877 pkt << first << third;
1881 void Server::SendPlayerPrivileges(session_t peer_id)
1883 RemotePlayer *player = m_env->getPlayer(peer_id);
1885 if(player->getPeerId() == PEER_ID_INEXISTENT)
1888 std::set<std::string> privs;
1889 m_script->getAuth(player->getName(), NULL, &privs);
1891 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1892 pkt << (u16) privs.size();
1894 for (const std::string &priv : privs) {
1901 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1903 RemotePlayer *player = m_env->getPlayer(peer_id);
1905 if (player->getPeerId() == PEER_ID_INEXISTENT)
1908 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1909 pkt.putLongString(player->inventory_formspec);
1914 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1916 RemotePlayer *player = m_env->getPlayer(peer_id);
1918 if (player->getPeerId() == PEER_ID_INEXISTENT)
1921 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1922 pkt << player->formspec_prepend;
1926 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1928 // Radius inside which objects are active
1929 static thread_local const s16 radius =
1930 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1932 // Radius inside which players are active
1933 static thread_local const bool is_transfer_limited =
1934 g_settings->exists("unlimited_player_transfer_distance") &&
1935 !g_settings->getBool("unlimited_player_transfer_distance");
1937 static thread_local const s16 player_transfer_dist =
1938 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1940 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1941 radius : player_transfer_dist;
1943 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1947 std::queue<u16> removed_objects, added_objects;
1948 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1949 client->m_known_objects, removed_objects);
1950 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1951 client->m_known_objects, added_objects);
1953 int removed_count = removed_objects.size();
1954 int added_count = added_objects.size();
1956 if (removed_objects.empty() && added_objects.empty())
1962 // Handle removed objects
1963 writeU16((u8*)buf, removed_objects.size());
1964 data.append(buf, 2);
1965 while (!removed_objects.empty()) {
1967 u16 id = removed_objects.front();
1968 ServerActiveObject* obj = m_env->getActiveObject(id);
1970 // Add to data buffer for sending
1971 writeU16((u8*)buf, id);
1972 data.append(buf, 2);
1974 // Remove from known objects
1975 client->m_known_objects.erase(id);
1977 if (obj && obj->m_known_by_count > 0)
1978 obj->m_known_by_count--;
1980 removed_objects.pop();
1983 // Handle added objects
1984 writeU16((u8*)buf, added_objects.size());
1985 data.append(buf, 2);
1986 while (!added_objects.empty()) {
1988 u16 id = added_objects.front();
1989 ServerActiveObject *obj = m_env->getActiveObject(id);
1990 added_objects.pop();
1993 warningstream << FUNCTION_NAME << ": NULL object id="
1994 << (int)id << std::endl;
1999 u8 type = obj->getSendType();
2001 // Add to data buffer for sending
2002 writeU16((u8*)buf, id);
2003 data.append(buf, 2);
2004 writeU8((u8*)buf, type);
2005 data.append(buf, 1);
2007 data.append(serializeString32(
2008 obj->getClientInitializationData(client->net_proto_version)));
2010 // Add to known objects
2011 client->m_known_objects.insert(id);
2013 obj->m_known_by_count++;
2016 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2017 pkt.putRawString(data.c_str(), data.size());
2020 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2021 << removed_count << " removed, " << added_count << " added, "
2022 << "packet size is " << pkt.getSize() << std::endl;
2025 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2028 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2029 datas.size(), peer_id);
2031 pkt.putRawString(datas.c_str(), datas.size());
2033 m_clients.send(pkt.getPeerId(),
2034 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2038 void Server::SendCSMRestrictionFlags(session_t peer_id)
2040 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2041 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2042 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2046 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2048 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2053 inline s32 Server::nextSoundId()
2055 s32 ret = m_next_sound_id;
2056 if (m_next_sound_id == INT32_MAX)
2057 m_next_sound_id = 0; // signed overflow is undefined
2063 s32 Server::playSound(const SimpleSoundSpec &spec,
2064 const ServerSoundParams ¶ms, bool ephemeral)
2066 // Find out initial position of sound
2067 bool pos_exists = false;
2068 v3f pos = params.getPos(m_env, &pos_exists);
2069 // If position is not found while it should be, cancel sound
2070 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2073 // Filter destination clients
2074 std::vector<session_t> dst_clients;
2075 if (!params.to_player.empty()) {
2076 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2078 infostream<<"Server::playSound: Player \""<<params.to_player
2079 <<"\" not found"<<std::endl;
2082 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2083 infostream<<"Server::playSound: Player \""<<params.to_player
2084 <<"\" not connected"<<std::endl;
2087 dst_clients.push_back(player->getPeerId());
2089 std::vector<session_t> clients = m_clients.getClientIDs();
2091 for (const session_t client_id : clients) {
2092 RemotePlayer *player = m_env->getPlayer(client_id);
2095 if (!params.exclude_player.empty() &&
2096 params.exclude_player == player->getName())
2099 PlayerSAO *sao = player->getPlayerSAO();
2104 if(sao->getBasePosition().getDistanceFrom(pos) >
2105 params.max_hear_distance)
2108 dst_clients.push_back(client_id);
2112 if(dst_clients.empty())
2117 ServerPlayingSound *psound = nullptr;
2119 id = -1; // old clients will still use this, so pick a reserved ID
2122 // The sound will exist as a reference in m_playing_sounds
2123 m_playing_sounds[id] = ServerPlayingSound();
2124 psound = &m_playing_sounds[id];
2125 psound->params = params;
2126 psound->spec = spec;
2129 float gain = params.gain * spec.gain;
2130 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2131 pkt << id << spec.name << gain
2132 << (u8) params.type << pos << params.object
2133 << params.loop << params.fade << params.pitch
2136 bool as_reliable = !ephemeral;
2138 for (const u16 dst_client : dst_clients) {
2140 psound->clients.insert(dst_client);
2141 m_clients.send(dst_client, 0, &pkt, as_reliable);
2145 void Server::stopSound(s32 handle)
2147 // Get sound reference
2148 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2149 m_playing_sounds.find(handle);
2150 if (i == m_playing_sounds.end())
2152 ServerPlayingSound &psound = i->second;
2154 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2157 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2158 si != psound.clients.end(); ++si) {
2160 m_clients.send(*si, 0, &pkt, true);
2162 // Remove sound reference
2163 m_playing_sounds.erase(i);
2166 void Server::fadeSound(s32 handle, float step, float gain)
2168 // Get sound reference
2169 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2170 m_playing_sounds.find(handle);
2171 if (i == m_playing_sounds.end())
2174 ServerPlayingSound &psound = i->second;
2175 psound.params.gain = gain;
2177 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2178 pkt << handle << step << gain;
2180 // Backwards compability
2181 bool play_sound = gain > 0;
2182 ServerPlayingSound compat_psound = psound;
2183 compat_psound.clients.clear();
2185 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2186 compat_pkt << handle;
2188 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2189 it != psound.clients.end();) {
2190 if (m_clients.getProtocolVersion(*it) >= 32) {
2192 m_clients.send(*it, 0, &pkt, true);
2195 compat_psound.clients.insert(*it);
2197 m_clients.send(*it, 0, &compat_pkt, true);
2198 psound.clients.erase(it++);
2202 // Remove sound reference
2203 if (!play_sound || psound.clients.empty())
2204 m_playing_sounds.erase(i);
2206 if (play_sound && !compat_psound.clients.empty()) {
2207 // Play new sound volume on older clients
2208 playSound(compat_psound.spec, compat_psound.params);
2212 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2215 float maxd = far_d_nodes * BS;
2216 v3f p_f = intToFloat(p, BS);
2217 v3s16 block_pos = getNodeBlockPos(p);
2219 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2222 std::vector<session_t> clients = m_clients.getClientIDs();
2225 for (session_t client_id : clients) {
2226 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2230 RemotePlayer *player = m_env->getPlayer(client_id);
2231 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2233 // If player is far away, only set modified blocks not sent
2234 if (!client->isBlockSent(block_pos) || (sao &&
2235 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2237 far_players->emplace(client_id);
2239 client->SetBlockNotSent(block_pos);
2244 m_clients.send(client_id, 0, &pkt, true);
2250 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2251 float far_d_nodes, bool remove_metadata)
2253 float maxd = far_d_nodes * BS;
2254 v3f p_f = intToFloat(p, BS);
2255 v3s16 block_pos = getNodeBlockPos(p);
2257 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2258 pkt << p << n.param0 << n.param1 << n.param2
2259 << (u8) (remove_metadata ? 0 : 1);
2261 std::vector<session_t> clients = m_clients.getClientIDs();
2264 for (session_t client_id : clients) {
2265 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2269 RemotePlayer *player = m_env->getPlayer(client_id);
2270 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2272 // If player is far away, only set modified blocks not sent
2273 if (!client->isBlockSent(block_pos) || (sao &&
2274 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2276 far_players->emplace(client_id);
2278 client->SetBlockNotSent(block_pos);
2283 m_clients.send(client_id, 0, &pkt, true);
2289 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2291 float maxd = far_d_nodes * BS;
2292 NodeMetadataList meta_updates_list(false);
2293 std::vector<session_t> clients = m_clients.getClientIDs();
2297 for (session_t i : clients) {
2298 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2302 ServerActiveObject *player = m_env->getActiveObject(i);
2303 v3f player_pos = player ? player->getBasePosition() : v3f();
2305 for (const v3s16 &pos : meta_updates) {
2306 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2311 v3s16 block_pos = getNodeBlockPos(pos);
2312 if (!client->isBlockSent(block_pos) || (player &&
2313 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2314 client->SetBlockNotSent(block_pos);
2318 // Add the change to send list
2319 meta_updates_list.set(pos, meta);
2321 if (meta_updates_list.size() == 0)
2324 // Send the meta changes
2325 std::ostringstream os(std::ios::binary);
2326 meta_updates_list.serialize(os, client->serialization_version, false, true, true);
2327 std::ostringstream oss(std::ios::binary);
2328 compressZlib(os.str(), oss);
2330 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2331 pkt.putLongString(oss.str());
2332 m_clients.send(i, 0, &pkt, true);
2334 meta_updates_list.clear();
2340 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2341 u16 net_proto_version)
2344 Create a packet with the block in the right format
2346 thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
2347 std::ostringstream os(std::ios_base::binary);
2348 block->serialize(os, ver, false, net_compression_level);
2349 block->serializeNetworkSpecific(os);
2350 std::string s = os.str();
2352 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + s.size(), peer_id);
2354 pkt << block->getPos();
2355 pkt.putRawString(s.c_str(), s.size());
2359 void Server::SendBlocks(float dtime)
2361 MutexAutoLock envlock(m_env_mutex);
2362 //TODO check if one big lock could be faster then multiple small ones
2364 std::vector<PrioritySortedBlockTransfer> queue;
2366 u32 total_sending = 0;
2369 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2371 std::vector<session_t> clients = m_clients.getClientIDs();
2374 for (const session_t client_id : clients) {
2375 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2380 total_sending += client->getSendingCount();
2381 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2387 // Lowest priority number comes first.
2388 // Lowest is most important.
2389 std::sort(queue.begin(), queue.end());
2393 // Maximal total count calculation
2394 // The per-client block sends is halved with the maximal online users
2395 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2396 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2398 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2399 Map &map = m_env->getMap();
2401 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2402 if (total_sending >= max_blocks_to_send)
2405 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2409 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2414 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2415 client->net_proto_version);
2417 client->SentBlock(block_to_send.pos);
2423 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2425 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2430 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2431 if (!client || client->isBlockSent(blockpos)) {
2435 SendBlockNoLock(peer_id, block, client->serialization_version,
2436 client->net_proto_version);
2442 bool Server::addMediaFile(const std::string &filename,
2443 const std::string &filepath, std::string *filedata_to,
2444 std::string *digest_to)
2446 // If name contains illegal characters, ignore the file
2447 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2448 infostream << "Server: ignoring illegal file name: \""
2449 << filename << "\"" << std::endl;
2452 // If name is not in a supported format, ignore it
2453 const char *supported_ext[] = {
2454 ".png", ".jpg", ".bmp", ".tga",
2456 ".x", ".b3d", ".obj",
2457 // Custom translation file format
2461 if (removeStringEnd(filename, supported_ext).empty()) {
2462 infostream << "Server: ignoring unsupported file extension: \""
2463 << filename << "\"" << std::endl;
2466 // Ok, attempt to load the file and add to cache
2469 std::string filedata;
2470 if (!fs::ReadFile(filepath, filedata)) {
2471 errorstream << "Server::addMediaFile(): Failed to open \""
2472 << filename << "\" for reading" << std::endl;
2476 if (filedata.empty()) {
2477 errorstream << "Server::addMediaFile(): Empty file \""
2478 << filepath << "\"" << std::endl;
2483 sha1.addBytes(filedata.c_str(), filedata.length());
2485 unsigned char *digest = sha1.getDigest();
2486 std::string sha1_base64 = base64_encode(digest, 20);
2487 std::string sha1_hex = hex_encode((char*) digest, 20);
2489 *digest_to = std::string((char*) digest, 20);
2493 m_media[filename] = MediaInfo(filepath, sha1_base64);
2494 verbosestream << "Server: " << sha1_hex << " is " << filename
2498 *filedata_to = std::move(filedata);
2502 void Server::fillMediaCache()
2504 infostream << "Server: Calculating media file checksums" << std::endl;
2506 // Collect all media file paths
2507 std::vector<std::string> paths;
2509 // ordered in descending priority
2510 paths.push_back(getBuiltinLuaPath() + DIR_DELIM + "locale");
2511 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2512 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2513 m_modmgr->getModsMediaPaths(paths);
2515 // Collect media file information from paths into cache
2516 for (const std::string &mediapath : paths) {
2517 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2518 for (const fs::DirListNode &dln : dirlist) {
2519 if (dln.dir) // Ignore dirs (already in paths)
2522 const std::string &filename = dln.name;
2523 if (m_media.find(filename) != m_media.end()) // Do not override
2526 std::string filepath = mediapath;
2527 filepath.append(DIR_DELIM).append(filename);
2528 addMediaFile(filename, filepath);
2532 infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2535 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2538 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2541 std::string lang_suffix;
2542 lang_suffix.append(".").append(lang_code).append(".tr");
2543 for (const auto &i : m_media) {
2544 if (i.second.no_announce)
2546 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2553 for (const auto &i : m_media) {
2554 if (i.second.no_announce)
2556 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2558 pkt << i.first << i.second.sha1_digest;
2561 pkt << g_settings->get("remote_media");
2564 verbosestream << "Server: Announcing files to id(" << peer_id
2565 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2568 struct SendableMedia
2574 SendableMedia(const std::string &name, const std::string &path,
2575 std::string &&data):
2576 name(name), path(path), data(std::move(data))
2580 void Server::sendRequestedMedia(session_t peer_id,
2581 const std::vector<std::string> &tosend)
2583 verbosestream<<"Server::sendRequestedMedia(): "
2584 <<"Sending files to client"<<std::endl;
2588 // Put 5kB in one bunch (this is not accurate)
2589 u32 bytes_per_bunch = 5000;
2591 std::vector< std::vector<SendableMedia> > file_bunches;
2592 file_bunches.emplace_back();
2594 u32 file_size_bunch_total = 0;
2596 for (const std::string &name : tosend) {
2597 if (m_media.find(name) == m_media.end()) {
2598 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2599 <<"unknown file \""<<(name)<<"\""<<std::endl;
2603 const auto &m = m_media[name];
2607 if (!fs::ReadFile(m.path, data)) {
2608 errorstream << "Server::sendRequestedMedia(): Failed to read \""
2609 << name << "\"" << std::endl;
2612 file_size_bunch_total += data.size();
2615 file_bunches.back().emplace_back(name, m.path, std::move(data));
2617 // Start next bunch if got enough data
2618 if(file_size_bunch_total >= bytes_per_bunch) {
2619 file_bunches.emplace_back();
2620 file_size_bunch_total = 0;
2625 /* Create and send packets */
2627 u16 num_bunches = file_bunches.size();
2628 for (u16 i = 0; i < num_bunches; i++) {
2631 u16 total number of texture bunches
2632 u16 index of this bunch
2633 u32 number of files in this bunch
2642 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2643 pkt << num_bunches << i << (u32) file_bunches[i].size();
2645 for (const SendableMedia &j : file_bunches[i]) {
2647 pkt.putLongString(j.data);
2650 verbosestream << "Server::sendRequestedMedia(): bunch "
2651 << i << "/" << num_bunches
2652 << " files=" << file_bunches[i].size()
2653 << " size=" << pkt.getSize() << std::endl;
2658 void Server::stepPendingDynMediaCallbacks(float dtime)
2660 MutexAutoLock lock(m_env_mutex);
2662 for (auto it = m_pending_dyn_media.begin(); it != m_pending_dyn_media.end();) {
2663 it->second.expiry_timer -= dtime;
2664 bool del = it->second.waiting_players.empty() || it->second.expiry_timer < 0;
2671 const auto &name = it->second.filename;
2672 if (!name.empty()) {
2673 assert(m_media.count(name));
2674 // if no_announce isn't set we're definitely deleting the wrong file!
2675 sanity_check(m_media[name].no_announce);
2677 fs::DeleteSingleFileOrEmptyDirectory(m_media[name].path);
2678 m_media.erase(name);
2680 getScriptIface()->freeDynamicMediaCallback(it->first);
2681 it = m_pending_dyn_media.erase(it);
2685 void Server::SendMinimapModes(session_t peer_id,
2686 std::vector<MinimapMode> &modes, size_t wanted_mode)
2688 RemotePlayer *player = m_env->getPlayer(peer_id);
2690 if (player->getPeerId() == PEER_ID_INEXISTENT)
2693 NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2694 pkt << (u16)modes.size() << (u16)wanted_mode;
2696 for (auto &mode : modes)
2697 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2702 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2704 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2708 pkt << false; // Remove inventory
2710 pkt << true; // Update inventory
2712 // Serialization & NetworkPacket isn't a love story
2713 std::ostringstream os(std::ios_base::binary);
2714 inventory->serialize(os);
2715 inventory->setModified(false);
2717 const std::string &os_str = os.str();
2718 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2719 pkt.putRawString(os_str);
2722 if (peer_id == PEER_ID_INEXISTENT)
2723 m_clients.sendToAll(&pkt);
2728 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2730 // Lookup player name, to filter detached inventories just after
2731 std::string peer_name;
2732 if (peer_id != PEER_ID_INEXISTENT) {
2733 peer_name = getClient(peer_id, CS_Created)->getName();
2736 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2737 sendDetachedInventory(inv, name, peer_id);
2740 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2747 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2749 PlayerSAO *playersao = getPlayerSAO(peer_id);
2752 infostream << "Server::DiePlayer(): Player "
2753 << playersao->getPlayer()->getName()
2754 << " dies" << std::endl;
2756 playersao->setHP(0, reason);
2757 playersao->clearParentAttachment();
2759 // Trigger scripted stuff
2760 m_script->on_dieplayer(playersao, reason);
2762 SendPlayerHP(peer_id);
2763 SendDeathscreen(peer_id, false, v3f(0,0,0));
2766 void Server::RespawnPlayer(session_t peer_id)
2768 PlayerSAO *playersao = getPlayerSAO(peer_id);
2771 infostream << "Server::RespawnPlayer(): Player "
2772 << playersao->getPlayer()->getName()
2773 << " respawns" << std::endl;
2775 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2776 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2777 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2779 bool repositioned = m_script->on_respawnplayer(playersao);
2780 if (!repositioned) {
2781 // setPos will send the new position to client
2782 playersao->setPos(findSpawnPos());
2785 SendPlayerHP(peer_id);
2789 void Server::DenySudoAccess(session_t peer_id)
2791 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2796 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2797 const std::string &str_reason, bool reconnect)
2799 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2801 m_clients.event(peer_id, CSE_SetDenied);
2802 DisconnectPeer(peer_id);
2806 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2807 const std::string &custom_reason)
2809 SendAccessDenied(peer_id, reason, custom_reason);
2810 m_clients.event(peer_id, CSE_SetDenied);
2811 DisconnectPeer(peer_id);
2814 // 13/03/15: remove this function when protocol version 25 will become
2815 // the minimum version for MT users, maybe in 1 year
2816 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2818 SendAccessDenied_Legacy(peer_id, reason);
2819 m_clients.event(peer_id, CSE_SetDenied);
2820 DisconnectPeer(peer_id);
2823 void Server::DisconnectPeer(session_t peer_id)
2825 m_modchannel_mgr->leaveAllChannels(peer_id);
2826 m_con->DisconnectPeer(peer_id);
2829 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2832 RemoteClient* client = getClient(peer_id, CS_Invalid);
2834 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2836 // Right now, the auth mechs don't change between login and sudo mode.
2837 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2838 client->allowed_sudo_mechs = sudo_auth_mechs;
2840 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2841 << g_settings->getFloat("dedicated_server_step")
2845 m_clients.event(peer_id, CSE_AuthAccept);
2847 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2849 // We only support SRP right now
2850 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2852 resp_pkt << sudo_auth_mechs;
2854 m_clients.event(peer_id, CSE_SudoSuccess);
2858 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2860 std::wstring message;
2863 Clear references to playing sounds
2865 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2866 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2867 ServerPlayingSound &psound = i->second;
2868 psound.clients.erase(peer_id);
2869 if (psound.clients.empty())
2870 m_playing_sounds.erase(i++);
2875 // clear formspec info so the next client can't abuse the current state
2876 m_formspec_state_data.erase(peer_id);
2878 RemotePlayer *player = m_env->getPlayer(peer_id);
2880 /* Run scripts and remove from environment */
2882 PlayerSAO *playersao = player->getPlayerSAO();
2885 playersao->clearChildAttachments();
2886 playersao->clearParentAttachment();
2888 // inform connected clients
2889 const std::string &player_name = player->getName();
2890 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2891 // (u16) 1 + std::string represents a vector serialization representation
2892 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2893 m_clients.sendToAll(¬ice);
2895 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2897 playersao->disconnected();
2904 if (player && reason != CDR_DENY) {
2905 std::ostringstream os(std::ios_base::binary);
2906 std::vector<session_t> clients = m_clients.getClientIDs();
2908 for (const session_t client_id : clients) {
2910 RemotePlayer *player = m_env->getPlayer(client_id);
2914 // Get name of player
2915 os << player->getName() << " ";
2918 std::string name = player->getName();
2919 actionstream << name << " "
2920 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2921 << " List of players: " << os.str() << std::endl;
2923 m_admin_chat->outgoing_queue.push_back(
2924 new ChatEventNick(CET_NICK_REMOVE, name));
2928 MutexAutoLock env_lock(m_env_mutex);
2929 m_clients.DeleteClient(peer_id);
2933 // Send leave chat message to all remaining clients
2934 if (!message.empty()) {
2935 SendChatMessage(PEER_ID_INEXISTENT,
2936 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2940 void Server::UpdateCrafting(RemotePlayer *player)
2942 InventoryList *clist = player->inventory.getList("craft");
2943 if (!clist || clist->getSize() == 0)
2946 if (!clist->checkModified())
2949 // Get a preview for crafting
2951 InventoryLocation loc;
2952 loc.setPlayer(player->getName());
2953 std::vector<ItemStack> output_replacements;
2954 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2955 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2958 InventoryList *plist = player->inventory.getList("craftpreview");
2959 if (plist && plist->getSize() >= 1) {
2960 // Put the new preview in
2961 plist->changeItem(0, preview);
2965 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2967 if (evt->type == CET_NICK_ADD) {
2968 // The terminal informed us of its nick choice
2969 m_admin_nick = ((ChatEventNick *)evt)->nick;
2970 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2971 errorstream << "You haven't set up an account." << std::endl
2972 << "Please log in using the client as '"
2973 << m_admin_nick << "' with a secure password." << std::endl
2974 << "Until then, you can't execute admin tasks via the console," << std::endl
2975 << "and everybody can claim the user account instead of you," << std::endl
2976 << "giving them full control over this server." << std::endl;
2979 assert(evt->type == CET_CHAT);
2980 handleAdminChat((ChatEventChat *)evt);
2984 std::wstring Server::handleChat(const std::string &name,
2985 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2987 // If something goes wrong, this player is to blame
2988 RollbackScopeActor rollback_scope(m_rollback,
2989 std::string("player:") + name);
2991 if (g_settings->getBool("strip_color_codes"))
2992 wmessage = unescape_enriched(wmessage);
2995 switch (player->canSendChatMessage()) {
2996 case RPLAYER_CHATRESULT_FLOODING: {
2997 std::wstringstream ws;
2998 ws << L"You cannot send more messages. You are limited to "
2999 << g_settings->getFloat("chat_message_limit_per_10sec")
3000 << L" messages per 10 seconds.";
3003 case RPLAYER_CHATRESULT_KICK:
3004 DenyAccess_Legacy(player->getPeerId(),
3005 L"You have been kicked due to message flooding.");
3007 case RPLAYER_CHATRESULT_OK:
3010 FATAL_ERROR("Unhandled chat filtering result found.");
3014 if (m_max_chatmessage_length > 0
3015 && wmessage.length() > m_max_chatmessage_length) {
3016 return L"Your message exceed the maximum chat message limit set on the server. "
3017 L"It was refused. Send a shorter message";
3020 auto message = trim(wide_to_utf8(wmessage));
3021 if (message.empty())
3024 if (message.find_first_of("\n\r") != std::wstring::npos) {
3025 return L"Newlines are not permitted in chat messages";
3028 // Run script hook, exit if script ate the chat message
3029 if (m_script->on_chat_message(name, message))
3034 // Whether to send line to the player that sent the message, or to all players
3035 bool broadcast_line = true;
3037 if (check_shout_priv && !checkPriv(name, "shout")) {
3038 line += L"-!- You don't have permission to shout.";
3039 broadcast_line = false;
3042 Workaround for fixing chat on Android. Lua doesn't handle
3043 the Cyrillic alphabet and some characters on older Android devices
3046 line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
3048 line += utf8_to_wide(m_script->formatChatMessage(name,
3049 wide_to_utf8(wmessage)));
3054 Tell calling method to send the message to sender
3056 if (!broadcast_line)
3060 Send the message to others
3062 actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
3064 ChatMessage chatmsg(line);
3066 std::vector<session_t> clients = m_clients.getClientIDs();
3067 for (u16 cid : clients)
3068 SendChatMessage(cid, chatmsg);
3073 void Server::handleAdminChat(const ChatEventChat *evt)
3075 std::string name = evt->nick;
3076 std::wstring wmessage = evt->evt_msg;
3078 std::wstring answer = handleChat(name, wmessage);
3080 // If asked to send answer to sender
3081 if (!answer.empty()) {
3082 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3086 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3088 RemoteClient *client = getClientNoEx(peer_id,state_min);
3090 throw ClientNotFoundException("Client not found");
3094 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3096 return m_clients.getClientNoEx(peer_id, state_min);
3099 std::string Server::getPlayerName(session_t peer_id)
3101 RemotePlayer *player = m_env->getPlayer(peer_id);
3103 return "[id="+itos(peer_id)+"]";
3104 return player->getName();
3107 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3109 RemotePlayer *player = m_env->getPlayer(peer_id);
3112 return player->getPlayerSAO();
3115 std::string Server::getStatusString()
3117 std::ostringstream os(std::ios_base::binary);
3120 os << "version: " << g_version_string;
3122 os << " | uptime: " << duration_to_string((int) m_uptime_counter->get());
3124 os << " | max lag: " << std::setprecision(3);
3125 os << (m_env ? m_env->getMaxLagEstimate() : 0) << "s";
3127 // Information about clients
3129 os << " | clients: ";
3131 std::vector<session_t> clients = m_clients.getClientIDs();
3132 for (session_t client_id : clients) {
3133 RemotePlayer *player = m_env->getPlayer(client_id);
3135 // Get name of player
3136 const char *name = player ? player->getName() : "<unknown>";
3138 // Add name to information string
3147 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3148 os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
3150 if (!g_settings->get("motd").empty())
3151 os << std::endl << "# Server: " << g_settings->get("motd");
3156 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3158 std::set<std::string> privs;
3159 m_script->getAuth(name, NULL, &privs);
3163 bool Server::checkPriv(const std::string &name, const std::string &priv)
3165 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3166 return (privs.count(priv) != 0);
3169 void Server::reportPrivsModified(const std::string &name)
3172 std::vector<session_t> clients = m_clients.getClientIDs();
3173 for (const session_t client_id : clients) {
3174 RemotePlayer *player = m_env->getPlayer(client_id);
3175 reportPrivsModified(player->getName());
3178 RemotePlayer *player = m_env->getPlayer(name.c_str());
3181 SendPlayerPrivileges(player->getPeerId());
3182 PlayerSAO *sao = player->getPlayerSAO();
3185 sao->updatePrivileges(
3186 getPlayerEffectivePrivs(name),
3191 void Server::reportInventoryFormspecModified(const std::string &name)
3193 RemotePlayer *player = m_env->getPlayer(name.c_str());
3196 SendPlayerInventoryFormspec(player->getPeerId());
3199 void Server::reportFormspecPrependModified(const std::string &name)
3201 RemotePlayer *player = m_env->getPlayer(name.c_str());
3204 SendPlayerFormspecPrepend(player->getPeerId());
3207 void Server::setIpBanned(const std::string &ip, const std::string &name)
3209 m_banmanager->add(ip, name);
3212 void Server::unsetIpBanned(const std::string &ip_or_name)
3214 m_banmanager->remove(ip_or_name);
3217 std::string Server::getBanDescription(const std::string &ip_or_name)
3219 return m_banmanager->getBanDescription(ip_or_name);
3222 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3224 // m_env will be NULL if the server is initializing
3228 if (m_admin_nick == name && !m_admin_nick.empty()) {
3229 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3232 RemotePlayer *player = m_env->getPlayer(name);
3237 if (player->getPeerId() == PEER_ID_INEXISTENT)
3240 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3243 bool Server::showFormspec(const char *playername, const std::string &formspec,
3244 const std::string &formname)
3246 // m_env will be NULL if the server is initializing
3250 RemotePlayer *player = m_env->getPlayer(playername);
3254 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3258 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3263 u32 id = player->addHud(form);
3265 SendHUDAdd(player->getPeerId(), id, form);
3270 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3274 HudElement* todel = player->removeHud(id);
3281 SendHUDRemove(player->getPeerId(), id);
3285 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3290 SendHUDChange(player->getPeerId(), id, stat, data);
3294 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3299 SendHUDSetFlags(player->getPeerId(), flags, mask);
3300 player->hud_flags &= ~mask;
3301 player->hud_flags |= flags;
3303 PlayerSAO* playersao = player->getPlayerSAO();
3308 m_script->player_event(playersao, "hud_changed");
3312 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3317 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3320 player->setHotbarItemcount(hotbar_itemcount);
3321 std::ostringstream os(std::ios::binary);
3322 writeS32(os, hotbar_itemcount);
3323 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3327 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3332 player->setHotbarImage(name);
3333 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3336 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3341 player->setHotbarSelectedImage(name);
3342 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3345 Address Server::getPeerAddress(session_t peer_id)
3347 // Note that this is only set after Init was received in Server::handleCommand_Init
3348 return getClient(peer_id, CS_Invalid)->getAddress();
3351 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3352 v2s32 animation_frames[4], f32 frame_speed)
3354 sanity_check(player);
3355 player->setLocalAnimations(animation_frames, frame_speed);
3356 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3359 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3361 sanity_check(player);
3362 player->eye_offset_first = first;
3363 player->eye_offset_third = third;
3364 SendEyeOffset(player->getPeerId(), first, third);
3367 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3369 sanity_check(player);
3370 player->setSky(params);
3371 SendSetSky(player->getPeerId(), params);
3374 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3376 sanity_check(player);
3377 player->setSun(params);
3378 SendSetSun(player->getPeerId(), params);
3381 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3383 sanity_check(player);
3384 player->setMoon(params);
3385 SendSetMoon(player->getPeerId(), params);
3388 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3390 sanity_check(player);
3391 player->setStars(params);
3392 SendSetStars(player->getPeerId(), params);
3395 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3397 sanity_check(player);
3398 player->setCloudParams(params);
3399 SendCloudParams(player->getPeerId(), params);
3402 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3405 sanity_check(player);
3406 player->overrideDayNightRatio(do_override, ratio);
3407 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3410 void Server::notifyPlayers(const std::wstring &msg)
3412 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3415 void Server::spawnParticle(const std::string &playername,
3416 const ParticleParameters &p)
3418 // m_env will be NULL if the server is initializing
3422 session_t peer_id = PEER_ID_INEXISTENT;
3424 if (!playername.empty()) {
3425 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3428 peer_id = player->getPeerId();
3429 proto_ver = player->protocol_version;
3432 SendSpawnParticle(peer_id, proto_ver, p);
3435 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3436 ServerActiveObject *attached, const std::string &playername)
3438 // m_env will be NULL if the server is initializing
3442 session_t peer_id = PEER_ID_INEXISTENT;
3444 if (!playername.empty()) {
3445 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3448 peer_id = player->getPeerId();
3449 proto_ver = player->protocol_version;
3452 u16 attached_id = attached ? attached->getId() : 0;
3455 if (attached_id == 0)
3456 id = m_env->addParticleSpawner(p.time);
3458 id = m_env->addParticleSpawner(p.time, attached_id);
3460 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3464 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3466 // m_env will be NULL if the server is initializing
3468 throw ServerError("Can't delete particle spawners during initialisation!");
3470 session_t peer_id = PEER_ID_INEXISTENT;
3471 if (!playername.empty()) {
3472 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3475 peer_id = player->getPeerId();
3478 m_env->deleteParticleSpawner(id);
3479 SendDeleteParticleSpawner(peer_id, id);
3482 bool Server::dynamicAddMedia(std::string filepath,
3483 const u32 token, const std::string &to_player, bool ephemeral)
3485 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3486 auto it = m_media.find(filename);
3487 if (it != m_media.end()) {
3488 // Allow the same path to be "added" again in certain conditions
3489 if (ephemeral || it->second.path != filepath) {
3490 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3491 << "\" already exists in media cache" << std::endl;
3496 // Load the file and add it to our media cache
3497 std::string filedata, raw_hash;
3498 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3503 // Create a copy of the file and swap out the path, this removes the
3504 // requirement that mods keep the file accessible at the original path.
3505 filepath = fs::CreateTempFile();
3506 bool ok = ([&] () -> bool {
3507 if (filepath.empty())
3509 std::ofstream os(filepath.c_str(), std::ios::binary);
3517 errorstream << "Server: failed to create a copy of media file "
3518 << "\"" << filename << "\"" << std::endl;
3519 m_media.erase(filename);
3522 verbosestream << "Server: \"" << filename << "\" temporarily copied to "
3523 << filepath << std::endl;
3525 m_media[filename].path = filepath;
3526 m_media[filename].no_announce = true;
3527 // stepPendingDynMediaCallbacks will clean this up later.
3528 } else if (!to_player.empty()) {
3529 m_media[filename].no_announce = true;
3532 // Push file to existing clients
3533 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3534 pkt << raw_hash << filename << (bool)ephemeral;
3536 NetworkPacket legacy_pkt = pkt;
3538 // Newer clients get asked to fetch the file (asynchronous)
3540 // Older clients have an awful hack that just throws the data at them
3541 legacy_pkt.putLongString(filedata);
3543 std::unordered_set<session_t> delivered, waiting;
3545 for (auto &pair : m_clients.getClientList()) {
3546 if (pair.second->getState() < CS_DefinitionsSent)
3548 const auto proto_ver = pair.second->net_proto_version;
3552 const session_t peer_id = pair.second->peer_id;
3553 if (!to_player.empty() && getPlayerName(peer_id) != to_player)
3556 if (proto_ver < 40) {
3557 delivered.emplace(peer_id);
3559 The network layer only guarantees ordered delivery inside a channel.
3560 Since the very next packet could be one that uses the media, we have
3561 to push the media over ALL channels to ensure it is processed before
3562 it is used. In practice this means channels 1 and 0.
3564 m_clients.send(peer_id, 1, &legacy_pkt, true);
3565 m_clients.send(peer_id, 0, &legacy_pkt, true);
3567 waiting.emplace(peer_id);
3568 Send(peer_id, &pkt);
3573 // Run callback for players that already had the file delivered (legacy-only)
3574 for (session_t peer_id : delivered) {
3575 if (auto player = m_env->getPlayer(peer_id))
3576 getScriptIface()->on_dynamic_media_added(token, player->getName());
3579 // Save all others in our pending state
3580 auto &state = m_pending_dyn_media[token];
3581 state.waiting_players = std::move(waiting);
3582 // regardless of success throw away the callback after a while
3583 state.expiry_timer = 60.0f;
3585 state.filename = filename;
3590 // actions: time-reversed list
3591 // Return value: success/failure
3592 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3593 std::list<std::string> *log)
3595 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3596 ServerMap *map = (ServerMap*)(&m_env->getMap());
3598 // Fail if no actions to handle
3599 if (actions.empty()) {
3601 log->push_back("Nothing to do.");
3608 for (const RollbackAction &action : actions) {
3610 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3613 std::ostringstream os;
3614 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3615 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3617 log->push_back(os.str());
3619 std::ostringstream os;
3620 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3621 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3623 log->push_back(os.str());
3627 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3628 <<" failed"<<std::endl;
3630 // Call it done if less than half failed
3631 return num_failed <= num_tried/2;
3634 // IGameDef interface
3636 IItemDefManager *Server::getItemDefManager()
3641 const NodeDefManager *Server::getNodeDefManager()
3646 ICraftDefManager *Server::getCraftDefManager()
3651 u16 Server::allocateUnknownNodeId(const std::string &name)
3653 return m_nodedef->allocateDummy(name);
3656 IWritableItemDefManager *Server::getWritableItemDefManager()
3661 NodeDefManager *Server::getWritableNodeDefManager()
3666 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3671 const std::vector<ModSpec> & Server::getMods() const
3673 return m_modmgr->getMods();
3676 const ModSpec *Server::getModSpec(const std::string &modname) const
3678 return m_modmgr->getModSpec(modname);
3681 void Server::getModNames(std::vector<std::string> &modlist)
3683 m_modmgr->getModNames(modlist);
3686 std::string Server::getBuiltinLuaPath()
3688 return porting::path_share + DIR_DELIM + "builtin";
3691 std::string Server::getModStoragePath() const
3693 return m_path_world + DIR_DELIM + "mod_storage";
3696 v3f Server::findSpawnPos()
3698 ServerMap &map = m_env->getServerMap();
3700 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3701 return nodeposf * BS;
3703 bool is_good = false;
3704 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3705 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3707 // Try to find a good place a few times
3708 for (s32 i = 0; i < 4000 && !is_good; i++) {
3709 s32 range = MYMIN(1 + i, range_max);
3710 // We're going to try to throw the player to this position
3711 v2s16 nodepos2d = v2s16(
3712 -range + (myrand() % (range * 2)),
3713 -range + (myrand() % (range * 2)));
3714 // Get spawn level at point
3715 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3716 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3717 // signify an unsuitable spawn position, or if outside limits.
3718 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3719 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3722 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3723 // Consecutive empty nodes
3726 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3727 // avoid obstructions in already-generated mapblocks.
3728 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3729 // no obstructions, but mapgen decorations are generated after spawn so
3730 // the player may end up inside one.
3731 for (s32 i = 0; i < 8; i++) {
3732 v3s16 blockpos = getNodeBlockPos(nodepos);
3733 map.emergeBlock(blockpos, true);
3734 content_t c = map.getNode(nodepos).getContent();
3736 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3737 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3738 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3740 if (air_count >= 2) {
3741 // Spawn in lower empty node
3743 nodeposf = intToFloat(nodepos, BS);
3744 // Don't spawn the player outside map boundaries
3745 if (objectpos_over_limit(nodeposf))
3746 // Exit this loop, positions above are probably over limit
3749 // Good position found, cause an exit from main loop
3763 // No suitable spawn point found, return fallback 0,0,0
3764 return v3f(0.0f, 0.0f, 0.0f);
3767 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3769 if (delay == 0.0f) {
3770 // No delay, shutdown immediately
3771 m_shutdown_state.is_requested = true;
3772 // only print to the infostream, a chat message saying
3773 // "Server Shutting Down" is sent when the server destructs.
3774 infostream << "*** Immediate Server shutdown requested." << std::endl;
3775 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3776 // Negative delay, cancel shutdown if requested
3777 m_shutdown_state.reset();
3778 std::wstringstream ws;
3780 ws << L"*** Server shutdown canceled.";
3782 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3783 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3784 // m_shutdown_* are already handled, skip.
3786 } else if (delay > 0.0f) {
3787 // Positive delay, tell the clients when the server will shut down
3788 std::wstringstream ws;
3790 ws << L"*** Server shutting down in "
3791 << duration_to_string(myround(delay)).c_str()
3794 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3795 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3798 m_shutdown_state.trigger(delay, msg, reconnect);
3801 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3804 Try to get an existing player
3806 RemotePlayer *player = m_env->getPlayer(name);
3808 // If player is already connected, cancel
3809 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3810 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3815 If player with the wanted peer_id already exists, cancel.
3817 if (m_env->getPlayer(peer_id)) {
3818 infostream<<"emergePlayer(): Player with wrong name but same"
3819 " peer_id already exists"<<std::endl;
3824 player = new RemotePlayer(name, idef());
3827 bool newplayer = false;
3830 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3832 // Complete init with server parts
3833 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3834 player->protocol_version = proto_version;
3838 m_script->on_newplayer(playersao);
3844 bool Server::registerModStorage(ModMetadata *storage)
3846 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3847 errorstream << "Unable to register same mod storage twice. Storage name: "
3848 << storage->getModName() << std::endl;
3852 m_mod_storages[storage->getModName()] = storage;
3856 void Server::unregisterModStorage(const std::string &name)
3858 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3859 if (it != m_mod_storages.end()) {
3860 // Save unconditionaly on unregistration
3861 it->second->save(getModStoragePath());
3862 m_mod_storages.erase(name);
3866 void dedicated_server_loop(Server &server, bool &kill)
3868 verbosestream<<"dedicated_server_loop()"<<std::endl;
3870 IntervalLimiter m_profiler_interval;
3872 static thread_local const float steplen =
3873 g_settings->getFloat("dedicated_server_step");
3874 static thread_local const float profiler_print_interval =
3875 g_settings->getFloat("profiler_print_interval");
3878 * The dedicated server loop only does time-keeping (in Server::step) and
3879 * provides a way to main.cpp to kill the server externally (bool &kill).
3883 // This is kind of a hack but can be done like this
3884 // because server.step() is very light
3885 sleep_ms((int)(steplen*1000.0));
3886 server.step(steplen);
3888 if (server.isShutdownRequested() || kill)
3894 if (profiler_print_interval != 0) {
3895 if(m_profiler_interval.step(steplen, profiler_print_interval))
3897 infostream<<"Profiler:"<<std::endl;
3898 g_profiler->print(infostream);
3899 g_profiler->clear();
3904 infostream << "Dedicated server quitting" << std::endl;
3906 if (g_settings->getBool("server_announce"))
3907 ServerList::sendAnnounce(ServerList::AA_DELETE,
3908 server.m_bind_addr.getPort());
3917 bool Server::joinModChannel(const std::string &channel)
3919 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3920 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3923 bool Server::leaveModChannel(const std::string &channel)
3925 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3928 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3930 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3933 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3937 ModChannel* Server::getModChannel(const std::string &channel)
3939 return m_modchannel_mgr->getModChannel(channel);
3942 void Server::broadcastModChannelMessage(const std::string &channel,
3943 const std::string &message, session_t from_peer)
3945 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3949 if (message.size() > STRING_MAX_LEN) {
3950 warningstream << "ModChannel message too long, dropping before sending "
3951 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3952 << channel << ")" << std::endl;
3957 if (from_peer != PEER_ID_SERVER) {
3958 sender = getPlayerName(from_peer);
3961 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3962 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3963 resp_pkt << channel << sender << message;
3964 for (session_t peer_id : peers) {
3966 if (peer_id == from_peer)
3969 Send(peer_id, &resp_pkt);
3972 if (from_peer != PEER_ID_SERVER) {
3973 m_script->on_modchannel_message(channel, sender, message);
3977 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3979 if (lang_code.empty())
3982 auto it = server_translations.find(lang_code);
3983 if (it != server_translations.end())
3984 return &it->second; // Already loaded
3986 // [] will create an entry
3987 auto *translations = &server_translations[lang_code];
3989 std::string suffix = "." + lang_code + ".tr";
3990 for (const auto &i : m_media) {
3991 if (str_ends_with(i.first, suffix)) {
3993 if (fs::ReadFile(i.second.path, data)) {
3994 translations->loadTranslation(data);
3999 return translations;