3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "server/serveractiveobject.h"
41 #include "scripting_server.h"
46 #include "mapgen/mapgen.h"
47 #include "mapgen/mg_biome.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content/mods.h"
51 #include "modchannels.h"
52 #include "serverlist.h"
53 #include "util/string.h"
55 #include "util/serialize.h"
56 #include "util/thread.h"
57 #include "defaultsettings.h"
58 #include "server/mods.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
62 #include "database/database.h"
63 #include "chatmessage.h"
64 #include "chat_interface.h"
65 #include "remoteplayer.h"
66 #include "server/player_sao.h"
67 #include "server/serverinventorymgr.h"
68 #include "translation.h"
70 class ClientNotFoundException : public BaseException
73 ClientNotFoundException(const char *s):
78 class ServerThread : public Thread
82 ServerThread(Server *server):
93 void *ServerThread::run()
95 BEGIN_DEBUG_EXCEPTION_HANDLER
98 * The real business of the server happens on the ServerThread.
100 * AsyncRunStep() runs an actual server step as soon as enough time has
101 * passed (dedicated_server_loop keeps track of that).
102 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
103 * doesn't busy wait) and will process any remaining packets.
106 m_server->AsyncRunStep(true);
108 while (!stopRequested()) {
110 m_server->AsyncRunStep();
114 } catch (con::PeerNotFoundException &e) {
115 infostream<<"Server: PeerNotFoundException"<<std::endl;
116 } catch (ClientNotFoundException &e) {
117 } catch (con::ConnectionBindFailed &e) {
118 m_server->setAsyncFatalError(e.what());
119 } catch (LuaError &e) {
120 m_server->setAsyncFatalError(
121 "ServerThread::run Lua: " + std::string(e.what()));
125 END_DEBUG_EXCEPTION_HANDLER
130 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
132 if(pos_exists) *pos_exists = false;
137 if(pos_exists) *pos_exists = true;
142 ServerActiveObject *sao = env->getActiveObject(object);
145 if(pos_exists) *pos_exists = true;
146 return sao->getBasePosition(); }
151 void Server::ShutdownState::reset()
155 should_reconnect = false;
156 is_requested = false;
159 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
163 should_reconnect = reconnect;
166 void Server::ShutdownState::tick(float dtime, Server *server)
172 static const float shutdown_msg_times[] =
174 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
177 // Automated messages
178 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
179 for (float t : shutdown_msg_times) {
180 // If shutdown timer matches an automessage, shot it
181 if (m_timer > t && m_timer - dtime < t) {
182 std::wstring periodicMsg = getShutdownTimerMessage();
184 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
185 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
192 if (m_timer < 0.0f) {
198 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
200 std::wstringstream ws;
201 ws << L"*** Server shutting down in "
202 << duration_to_string(myround(m_timer)).c_str() << ".";
211 const std::string &path_world,
212 const SubgameSpec &gamespec,
213 bool simple_singleplayer_mode,
216 ChatInterface *iface,
217 std::string *on_shutdown_errmsg
219 m_bind_addr(bind_addr),
220 m_path_world(path_world),
221 m_gamespec(gamespec),
222 m_simple_singleplayer_mode(simple_singleplayer_mode),
223 m_dedicated(dedicated),
224 m_async_fatal_error(""),
225 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
228 m_bind_addr.isIPv6(),
230 m_itemdef(createItemDefManager()),
231 m_nodedef(createNodeDefManager()),
232 m_craftdef(createCraftDefManager()),
233 m_thread(new ServerThread(this)),
236 m_on_shutdown_errmsg(on_shutdown_errmsg),
237 m_modchannel_mgr(new ModChannelMgr())
239 if (m_path_world.empty())
240 throw ServerError("Supplied empty world path");
242 if (!gamespec.isValid())
243 throw ServerError("Supplied invalid gamespec");
246 m_metrics_backend = std::unique_ptr<MetricsBackend>(createPrometheusMetricsBackend());
248 m_metrics_backend = std::unique_ptr<MetricsBackend>(new MetricsBackend());
251 m_uptime_counter = m_metrics_backend->addCounter("minetest_core_server_uptime", "Server uptime (in seconds)");
252 m_player_gauge = m_metrics_backend->addGauge("minetest_core_player_number", "Number of connected players");
254 m_timeofday_gauge = m_metrics_backend->addGauge(
255 "minetest_core_timeofday",
256 "Time of day value");
258 m_lag_gauge = m_metrics_backend->addGauge(
259 "minetest_core_latency",
260 "Latency value (in seconds)");
262 m_aom_buffer_counter = m_metrics_backend->addCounter(
263 "minetest_core_aom_generated_count",
264 "Number of active object messages generated");
266 m_packet_recv_counter = m_metrics_backend->addCounter(
267 "minetest_core_server_packet_recv",
268 "Processable packets received");
270 m_packet_recv_processed_counter = m_metrics_backend->addCounter(
271 "minetest_core_server_packet_recv_processed",
272 "Valid received packets processed");
274 m_lag_gauge->set(g_settings->getFloat("dedicated_server_step"));
280 // Send shutdown message
281 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
282 L"*** Server shutting down"));
285 MutexAutoLock envlock(m_env_mutex);
287 infostream << "Server: Saving players" << std::endl;
288 m_env->saveLoadedPlayers();
290 infostream << "Server: Kicking players" << std::endl;
291 std::string kick_msg;
292 bool reconnect = false;
293 if (isShutdownRequested()) {
294 reconnect = m_shutdown_state.should_reconnect;
295 kick_msg = m_shutdown_state.message;
297 if (kick_msg.empty()) {
298 kick_msg = g_settings->get("kick_msg_shutdown");
300 m_env->saveLoadedPlayers(true);
301 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
302 kick_msg, reconnect);
305 actionstream << "Server: Shutting down" << std::endl;
307 // Do this before stopping the server in case mapgen callbacks need to access
308 // server-controlled resources (like ModStorages). Also do them before
309 // shutdown callbacks since they may modify state that is finalized in a
312 m_emerge->stopThreads();
315 MutexAutoLock envlock(m_env_mutex);
317 // Execute script shutdown hooks
318 infostream << "Executing shutdown hooks" << std::endl;
320 m_script->on_shutdown();
321 } catch (ModError &e) {
322 errorstream << "ModError: " << e.what() << std::endl;
323 if (m_on_shutdown_errmsg) {
324 if (m_on_shutdown_errmsg->empty()) {
325 *m_on_shutdown_errmsg = std::string("ModError: ") + e.what();
327 *m_on_shutdown_errmsg += std::string("\nModError: ") + e.what();
332 infostream << "Server: Saving environment metadata" << std::endl;
342 // Delete things in the reverse order of creation
351 // Deinitialize scripting
352 infostream << "Server: Deinitializing scripting" << std::endl;
354 delete m_startup_server_map; // if available
355 delete m_game_settings;
357 while (!m_unsent_map_edit_queue.empty()) {
358 delete m_unsent_map_edit_queue.front();
359 m_unsent_map_edit_queue.pop();
365 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
366 if (m_simple_singleplayer_mode)
367 infostream << " in simple singleplayer mode" << std::endl;
369 infostream << std::endl;
370 infostream << "- world: " << m_path_world << std::endl;
371 infostream << "- game: " << m_gamespec.path << std::endl;
373 m_game_settings = Settings::createLayer(SL_GAME);
375 // Create world if it doesn't exist
377 loadGameConfAndInitWorld(m_path_world,
378 fs::GetFilenameFromPath(m_path_world.c_str()),
380 } catch (const BaseException &e) {
381 throw ServerError(std::string("Failed to initialize world: ") + e.what());
384 // Create emerge manager
385 m_emerge = new EmergeManager(this);
387 // Create ban manager
388 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
389 m_banmanager = new BanManager(ban_path);
391 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
392 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
393 // complain about mods with unsatisfied dependencies
394 if (!m_modmgr->isConsistent()) {
395 m_modmgr->printUnsatisfiedModsError();
399 MutexAutoLock envlock(m_env_mutex);
401 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
402 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge, m_metrics_backend.get());
403 m_startup_server_map = servermap;
405 // Initialize scripting
406 infostream << "Server: Initializing Lua" << std::endl;
408 m_script = new ServerScripting(this);
410 // Must be created before mod loading because we have some inventory creation
411 m_inventory_mgr = std::unique_ptr<ServerInventoryManager>(new ServerInventoryManager());
413 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
415 m_modmgr->loadMods(m_script);
417 // Read Textures and calculate sha1 sums
420 // Apply item aliases in the node definition manager
421 m_nodedef->updateAliases(m_itemdef);
423 // Apply texture overrides from texturepack/override.txt
424 std::vector<std::string> paths;
425 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
426 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
427 for (const std::string &path : paths) {
428 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
429 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
430 m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
433 m_nodedef->setNodeRegistrationStatus(true);
435 // Perform pending node name resolutions
436 m_nodedef->runNodeResolveCallbacks();
438 // unmap node names in cross-references
439 m_nodedef->resolveCrossrefs();
441 // init the recipe hashes to speed up crafting
442 m_craftdef->initHashes(this);
444 // Initialize Environment
445 m_startup_server_map = nullptr; // Ownership moved to ServerEnvironment
446 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
448 m_inventory_mgr->setEnv(m_env);
449 m_clients.setEnv(m_env);
451 if (!servermap->settings_mgr.makeMapgenParams())
452 FATAL_ERROR("Couldn't create any mapgen type");
454 // Initialize mapgens
455 m_emerge->initMapgens(servermap->getMapgenParams());
457 if (g_settings->getBool("enable_rollback_recording")) {
458 // Create rollback manager
459 m_rollback = new RollbackManager(m_path_world, this);
462 // Give environment reference to scripting api
463 m_script->initializeEnvironment(m_env);
465 // Register us to receive map edit events
466 servermap->addEventReceiver(this);
470 // Those settings can be overwritten in world.mt, they are
471 // intended to be cached after environment loading.
472 m_liquid_transform_every = g_settings->getFloat("liquid_update");
473 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
474 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
475 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
482 infostream << "Starting server on " << m_bind_addr.serializeString()
483 << "..." << std::endl;
485 // Stop thread if already running
488 // Initialize connection
489 m_con->SetTimeoutMs(30);
490 m_con->Serve(m_bind_addr);
495 // ASCII art for the win!
497 << " .__ __ __ " << std::endl
498 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
499 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
500 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
501 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
502 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
503 actionstream << "World at [" << m_path_world << "]" << std::endl;
504 actionstream << "Server for gameid=\"" << m_gamespec.id
505 << "\" listening on " << m_bind_addr.serializeString() << ":"
506 << m_bind_addr.getPort() << "." << std::endl;
511 infostream<<"Server: Stopping and waiting threads"<<std::endl;
513 // Stop threads (set run=false first so both start stopping)
515 //m_emergethread.setRun(false);
517 //m_emergethread.stop();
519 infostream<<"Server: Threads stopped"<<std::endl;
522 void Server::step(float dtime)
528 MutexAutoLock lock(m_step_dtime_mutex);
529 m_step_dtime += dtime;
531 // Throw if fatal error occurred in thread
532 std::string async_err = m_async_fatal_error.get();
533 if (!async_err.empty()) {
534 if (!m_simple_singleplayer_mode) {
535 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
536 g_settings->get("kick_msg_crash"),
537 g_settings->getBool("ask_reconnect_on_crash"));
539 throw ServerError("AsyncErr: " + async_err);
543 void Server::AsyncRunStep(bool initial_step)
548 MutexAutoLock lock1(m_step_dtime_mutex);
549 dtime = m_step_dtime;
553 // Send blocks to clients
557 if((dtime < 0.001) && !initial_step)
560 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
563 MutexAutoLock lock1(m_step_dtime_mutex);
564 m_step_dtime -= dtime;
570 m_uptime_counter->increment(dtime);
575 Update time of day and overall game time
577 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
580 Send to clients at constant intervals
583 m_time_of_day_send_timer -= dtime;
584 if (m_time_of_day_send_timer < 0.0) {
585 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
586 u16 time = m_env->getTimeOfDay();
587 float time_speed = g_settings->getFloat("time_speed");
588 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
590 m_timeofday_gauge->set(time);
594 MutexAutoLock lock(m_env_mutex);
595 // Figure out and report maximum lag to environment
596 float max_lag = m_env->getMaxLagEstimate();
597 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
599 if(dtime > 0.1 && dtime > max_lag * 2.0)
600 infostream<<"Server: Maximum lag peaked to "<<dtime
604 m_env->reportMaxLagEstimate(max_lag);
609 static const float map_timer_and_unload_dtime = 2.92;
610 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
612 MutexAutoLock lock(m_env_mutex);
613 // Run Map's timers and unload unused data
614 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
615 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
616 g_settings->getFloat("server_unload_unused_data_timeout"),
621 Listen to the admin chat, if available
624 if (!m_admin_chat->command_queue.empty()) {
625 MutexAutoLock lock(m_env_mutex);
626 while (!m_admin_chat->command_queue.empty()) {
627 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
628 handleChatInterfaceEvent(evt);
632 m_admin_chat->outgoing_queue.push_back(
633 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
640 /* Transform liquids */
641 m_liquid_transform_timer += dtime;
642 if(m_liquid_transform_timer >= m_liquid_transform_every)
644 m_liquid_transform_timer -= m_liquid_transform_every;
646 MutexAutoLock lock(m_env_mutex);
648 ScopeProfiler sp(g_profiler, "Server: liquid transform");
650 std::map<v3s16, MapBlock*> modified_blocks;
651 m_env->getMap().transformLiquids(modified_blocks, m_env);
654 Set the modified blocks unsent for all the clients
656 if (!modified_blocks.empty()) {
657 SetBlocksNotSent(modified_blocks);
660 m_clients.step(dtime);
662 // increase/decrease lag gauge gradually
663 if (m_lag_gauge->get() > dtime) {
664 m_lag_gauge->decrement(dtime/100);
666 m_lag_gauge->increment(dtime/100);
669 // send masterserver announce
671 float &counter = m_masterserver_timer;
672 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
673 g_settings->getBool("server_announce")) {
674 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
675 ServerList::AA_START,
676 m_bind_addr.getPort(),
677 m_clients.getPlayerNames(),
678 m_uptime_counter->get(),
679 m_env->getGameTime(),
682 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
692 Check added and deleted active objects
695 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
696 MutexAutoLock envlock(m_env_mutex);
699 const RemoteClientMap &clients = m_clients.getClientList();
700 ScopeProfiler sp(g_profiler, "Server: update objects within range");
702 m_player_gauge->set(clients.size());
703 for (const auto &client_it : clients) {
704 RemoteClient *client = client_it.second;
706 if (client->getState() < CS_DefinitionsSent)
709 // This can happen if the client times out somehow
710 if (!m_env->getPlayer(client->peer_id))
713 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
717 SendActiveObjectRemoveAdd(client, playersao);
721 // Save mod storages if modified
722 m_mod_storage_save_timer -= dtime;
723 if (m_mod_storage_save_timer <= 0.0f) {
724 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
726 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
727 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
728 if (it->second->isModified()) {
729 it->second->save(getModStoragePath());
734 infostream << "Saved " << n << " modified mod storages." << std::endl;
742 MutexAutoLock envlock(m_env_mutex);
743 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
746 // Value = data sent by object
747 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
749 // Get active object messages from environment
750 ActiveObjectMessage aom(0);
753 if (!m_env->getActiveObjectMessage(&aom))
756 std::vector<ActiveObjectMessage>* message_list = nullptr;
757 auto n = buffered_messages.find(aom.id);
758 if (n == buffered_messages.end()) {
759 message_list = new std::vector<ActiveObjectMessage>;
760 buffered_messages[aom.id] = message_list;
762 message_list = n->second;
764 message_list->push_back(std::move(aom));
768 m_aom_buffer_counter->increment(aom_count);
771 const RemoteClientMap &clients = m_clients.getClientList();
772 // Route data to every client
773 std::string reliable_data, unreliable_data;
774 for (const auto &client_it : clients) {
775 reliable_data.clear();
776 unreliable_data.clear();
777 RemoteClient *client = client_it.second;
778 PlayerSAO *player = getPlayerSAO(client->peer_id);
779 // Go through all objects in message buffer
780 for (const auto &buffered_message : buffered_messages) {
781 // If object does not exist or is not known by client, skip it
782 u16 id = buffered_message.first;
783 ServerActiveObject *sao = m_env->getActiveObject(id);
784 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
787 // Get message list of object
788 std::vector<ActiveObjectMessage>* list = buffered_message.second;
789 // Go through every message
790 for (const ActiveObjectMessage &aom : *list) {
791 // Send position updates to players who do not see the attachment
792 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
793 if (sao->getId() == player->getId())
796 // Do not send position updates for attached players
797 // as long the parent is known to the client
798 ServerActiveObject *parent = sao->getParent();
799 if (parent && client->m_known_objects.find(parent->getId()) !=
800 client->m_known_objects.end())
804 // Add full new data to appropriate buffer
805 std::string &buffer = aom.reliable ? reliable_data : unreliable_data;
807 writeU16((u8*) idbuf, aom.id);
810 buffer.append(idbuf, sizeof(idbuf));
811 buffer.append(serializeString16(aom.datastring));
815 reliable_data and unreliable_data are now ready.
818 if (!reliable_data.empty()) {
819 SendActiveObjectMessages(client->peer_id, reliable_data);
822 if (!unreliable_data.empty()) {
823 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
828 // Clear buffered_messages
829 for (auto &buffered_message : buffered_messages) {
830 delete buffered_message.second;
835 Send queued-for-sending map edit events.
838 // We will be accessing the environment
839 MutexAutoLock lock(m_env_mutex);
841 // Don't send too many at a time
844 // Single change sending is disabled if queue size is not small
845 bool disable_single_change_sending = false;
846 if(m_unsent_map_edit_queue.size() >= 4)
847 disable_single_change_sending = true;
849 int event_count = m_unsent_map_edit_queue.size();
851 // We'll log the amount of each
854 std::list<v3s16> node_meta_updates;
856 while (!m_unsent_map_edit_queue.empty()) {
857 MapEditEvent* event = m_unsent_map_edit_queue.front();
858 m_unsent_map_edit_queue.pop();
860 // Players far away from the change are stored here.
861 // Instead of sending the changes, MapBlocks are set not sent
863 std::unordered_set<u16> far_players;
865 switch (event->type) {
868 prof.add("MEET_ADDNODE", 1);
869 sendAddNode(event->p, event->n, &far_players,
870 disable_single_change_sending ? 5 : 30,
871 event->type == MEET_ADDNODE);
873 case MEET_REMOVENODE:
874 prof.add("MEET_REMOVENODE", 1);
875 sendRemoveNode(event->p, &far_players,
876 disable_single_change_sending ? 5 : 30);
878 case MEET_BLOCK_NODE_METADATA_CHANGED: {
879 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
880 if (!event->is_private_change) {
881 // Don't send the change yet. Collect them to eliminate dupes.
882 node_meta_updates.remove(event->p);
883 node_meta_updates.push_back(event->p);
886 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
887 getNodeBlockPos(event->p))) {
888 block->raiseModified(MOD_STATE_WRITE_NEEDED,
889 MOD_REASON_REPORT_META_CHANGE);
894 prof.add("MEET_OTHER", 1);
895 for (const v3s16 &modified_block : event->modified_blocks) {
896 m_clients.markBlockposAsNotSent(modified_block);
900 prof.add("unknown", 1);
901 warningstream << "Server: Unknown MapEditEvent "
902 << ((u32)event->type) << std::endl;
907 Set blocks not sent to far players
909 if (!far_players.empty()) {
910 // Convert list format to that wanted by SetBlocksNotSent
911 std::map<v3s16, MapBlock*> modified_blocks2;
912 for (const v3s16 &modified_block : event->modified_blocks) {
913 modified_blocks2[modified_block] =
914 m_env->getMap().getBlockNoCreateNoEx(modified_block);
917 // Set blocks not sent
918 for (const u16 far_player : far_players) {
919 if (RemoteClient *client = getClient(far_player))
920 client->SetBlocksNotSent(modified_blocks2);
927 if (event_count >= 5) {
928 infostream << "Server: MapEditEvents:" << std::endl;
929 prof.print(infostream);
930 } else if (event_count != 0) {
931 verbosestream << "Server: MapEditEvents:" << std::endl;
932 prof.print(verbosestream);
935 // Send all metadata updates
936 if (node_meta_updates.size())
937 sendMetadataChanged(node_meta_updates);
941 Trigger emergethread (it somehow gets to a non-triggered but
942 bysy state sometimes)
945 float &counter = m_emergethread_trigger_timer;
947 if (counter >= 2.0) {
950 m_emerge->startThreads();
954 // Save map, players and auth stuff
956 float &counter = m_savemap_timer;
958 static thread_local const float save_interval =
959 g_settings->getFloat("server_map_save_interval");
960 if (counter >= save_interval) {
962 MutexAutoLock lock(m_env_mutex);
964 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
967 if (m_banmanager->isModified()) {
968 m_banmanager->save();
971 // Save changed parts of map
972 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
975 m_env->saveLoadedPlayers();
977 // Save environment metadata
982 m_shutdown_state.tick(dtime, this);
985 void Server::Receive()
995 In the first iteration *wait* for a packet, afterwards process
996 all packets that are immediately available (no waiting).
999 m_con->Receive(&pkt);
1002 if (!m_con->TryReceive(&pkt))
1006 peer_id = pkt.getPeerId();
1007 m_packet_recv_counter->increment();
1009 m_packet_recv_processed_counter->increment();
1010 } catch (const con::InvalidIncomingDataException &e) {
1011 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1012 << e.what() << std::endl;
1013 } catch (const SerializationError &e) {
1014 infostream << "Server::Receive(): SerializationError: what()="
1015 << e.what() << std::endl;
1016 } catch (const ClientStateError &e) {
1017 errorstream << "ProcessData: peer=" << peer_id << " what()="
1018 << e.what() << std::endl;
1019 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1020 L"Try reconnecting or updating your client");
1021 } catch (const con::PeerNotFoundException &e) {
1023 } catch (const con::NoIncomingDataException &e) {
1029 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1031 std::string playername;
1032 PlayerSAO *playersao = NULL;
1035 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1037 playername = client->getName();
1038 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1040 } catch (std::exception &e) {
1046 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1048 // If failed, cancel
1049 if (!playersao || !player) {
1050 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1051 actionstream << "Server: Failed to emerge player \"" << playername
1052 << "\" (player allocated to an another client)" << std::endl;
1053 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1054 L"name. If your client closed unexpectedly, try again in "
1057 errorstream << "Server: " << playername << ": Failed to emerge player"
1059 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1065 Send complete position information
1067 SendMovePlayer(peer_id);
1070 SendPlayerPrivileges(peer_id);
1072 // Send inventory formspec
1073 SendPlayerInventoryFormspec(peer_id);
1076 SendInventory(playersao, false);
1078 // Send HP or death screen
1079 if (playersao->isDead())
1080 SendDeathscreen(peer_id, false, v3f(0,0,0));
1082 SendPlayerHPOrDie(playersao,
1083 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1086 SendPlayerBreath(playersao);
1092 Address addr = getPeerAddress(player->getPeerId());
1093 std::string ip_str = addr.serializeString();
1094 const std::vector<std::string> &names = m_clients.getPlayerNames();
1096 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1098 for (const std::string &name : names) {
1099 actionstream << name << " ";
1102 actionstream << player->getName() <<std::endl;
1107 inline void Server::handleCommand(NetworkPacket *pkt)
1109 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1110 (this->*opHandle.handler)(pkt);
1113 void Server::ProcessData(NetworkPacket *pkt)
1115 // Environment is locked first.
1116 MutexAutoLock envlock(m_env_mutex);
1118 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1119 u32 peer_id = pkt->getPeerId();
1122 Address address = getPeerAddress(peer_id);
1123 std::string addr_s = address.serializeString();
1125 if(m_banmanager->isIpBanned(addr_s)) {
1126 std::string ban_name = m_banmanager->getBanName(addr_s);
1127 infostream << "Server: A banned client tried to connect from "
1128 << addr_s << "; banned name was "
1129 << ban_name << std::endl;
1130 // This actually doesn't seem to transfer to the client
1131 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1132 + utf8_to_wide(ban_name));
1136 catch(con::PeerNotFoundException &e) {
1138 * no peer for this packet found
1139 * most common reason is peer timeout, e.g. peer didn't
1140 * respond for some time, your server was overloaded or
1143 infostream << "Server::ProcessData(): Canceling: peer "
1144 << peer_id << " not found" << std::endl;
1149 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1151 // Command must be handled into ToServerCommandHandler
1152 if (command >= TOSERVER_NUM_MSG_TYPES) {
1153 infostream << "Server: Ignoring unknown command "
1154 << command << std::endl;
1158 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1163 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1165 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1166 errorstream << "Server::ProcessData(): Cancelling: Peer"
1167 " serialization format invalid or not initialized."
1168 " Skipping incoming command=" << command << std::endl;
1172 /* Handle commands related to client startup */
1173 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1178 if (m_clients.getClientState(peer_id) < CS_Active) {
1179 if (command == TOSERVER_PLAYERPOS) return;
1181 errorstream << "Got packet command: " << command << " for peer id "
1182 << peer_id << " but client isn't active yet. Dropping packet "
1188 } catch (SendFailedException &e) {
1189 errorstream << "Server::ProcessData(): SendFailedException: "
1190 << "what=" << e.what()
1192 } catch (PacketError &e) {
1193 actionstream << "Server::ProcessData(): PacketError: "
1194 << "what=" << e.what()
1199 void Server::setTimeOfDay(u32 time)
1201 m_env->setTimeOfDay(time);
1202 m_time_of_day_send_timer = 0;
1205 void Server::onMapEditEvent(const MapEditEvent &event)
1207 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1210 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1213 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1215 std::vector<session_t> clients = m_clients.getClientIDs();
1217 // Set the modified blocks unsent for all the clients
1218 for (const session_t client_id : clients) {
1219 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1220 client->SetBlocksNotSent(block);
1225 void Server::peerAdded(con::Peer *peer)
1227 verbosestream<<"Server::peerAdded(): peer->id="
1228 <<peer->id<<std::endl;
1230 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1233 void Server::deletingPeer(con::Peer *peer, bool timeout)
1235 verbosestream<<"Server::deletingPeer(): peer->id="
1236 <<peer->id<<", timeout="<<timeout<<std::endl;
1238 m_clients.event(peer->id, CSE_Disconnect);
1239 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1242 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1244 *retval = m_con->getPeerStat(peer_id,type);
1245 return *retval != -1;
1248 bool Server::getClientInfo(session_t peer_id, ClientInfo &ret)
1251 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1258 ret.state = client->getState();
1259 ret.addr = client->getAddress();
1260 ret.uptime = client->uptime();
1261 ret.ser_vers = client->serialization_version;
1262 ret.prot_vers = client->net_proto_version;
1264 ret.major = client->getMajor();
1265 ret.minor = client->getMinor();
1266 ret.patch = client->getPatch();
1267 ret.vers_string = client->getFullVer();
1269 ret.lang_code = client->getLangCode();
1276 void Server::handlePeerChanges()
1278 while(!m_peer_change_queue.empty())
1280 con::PeerChange c = m_peer_change_queue.front();
1281 m_peer_change_queue.pop();
1283 verbosestream<<"Server: Handling peer change: "
1284 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1289 case con::PEER_ADDED:
1290 m_clients.CreateClient(c.peer_id);
1293 case con::PEER_REMOVED:
1294 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1298 FATAL_ERROR("Invalid peer change event received!");
1304 void Server::printToConsoleOnly(const std::string &text)
1307 m_admin_chat->outgoing_queue.push_back(
1308 new ChatEventChat("", utf8_to_wide(text)));
1310 std::cout << text << std::endl;
1314 void Server::Send(NetworkPacket *pkt)
1316 Send(pkt->getPeerId(), pkt);
1319 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1321 m_clients.send(peer_id,
1322 clientCommandFactoryTable[pkt->getCommand()].channel,
1324 clientCommandFactoryTable[pkt->getCommand()].reliable);
1327 void Server::SendMovement(session_t peer_id)
1329 std::ostringstream os(std::ios_base::binary);
1331 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1333 pkt << g_settings->getFloat("movement_acceleration_default");
1334 pkt << g_settings->getFloat("movement_acceleration_air");
1335 pkt << g_settings->getFloat("movement_acceleration_fast");
1336 pkt << g_settings->getFloat("movement_speed_walk");
1337 pkt << g_settings->getFloat("movement_speed_crouch");
1338 pkt << g_settings->getFloat("movement_speed_fast");
1339 pkt << g_settings->getFloat("movement_speed_climb");
1340 pkt << g_settings->getFloat("movement_speed_jump");
1341 pkt << g_settings->getFloat("movement_liquid_fluidity");
1342 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1343 pkt << g_settings->getFloat("movement_liquid_sink");
1344 pkt << g_settings->getFloat("movement_gravity");
1349 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1351 if (playersao->isImmortal())
1354 session_t peer_id = playersao->getPeerID();
1355 bool is_alive = !playersao->isDead();
1358 SendPlayerHP(peer_id);
1360 DiePlayer(peer_id, reason);
1363 void Server::SendHP(session_t peer_id, u16 hp)
1365 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1370 void Server::SendBreath(session_t peer_id, u16 breath)
1372 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1373 pkt << (u16) breath;
1377 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1378 const std::string &custom_reason, bool reconnect)
1380 assert(reason < SERVER_ACCESSDENIED_MAX);
1382 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1384 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1385 pkt << custom_reason;
1386 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1387 reason == SERVER_ACCESSDENIED_CRASH)
1388 pkt << custom_reason << (u8)reconnect;
1392 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1394 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1399 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1400 v3f camera_point_target)
1402 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1403 pkt << set_camera_point_target << camera_point_target;
1407 void Server::SendItemDef(session_t peer_id,
1408 IItemDefManager *itemdef, u16 protocol_version)
1410 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1414 u32 length of the next item
1415 zlib-compressed serialized ItemDefManager
1417 std::ostringstream tmp_os(std::ios::binary);
1418 itemdef->serialize(tmp_os, protocol_version);
1419 std::ostringstream tmp_os2(std::ios::binary);
1420 compressZlib(tmp_os.str(), tmp_os2);
1421 pkt.putLongString(tmp_os2.str());
1424 verbosestream << "Server: Sending item definitions to id(" << peer_id
1425 << "): size=" << pkt.getSize() << std::endl;
1430 void Server::SendNodeDef(session_t peer_id,
1431 const NodeDefManager *nodedef, u16 protocol_version)
1433 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1437 u32 length of the next item
1438 zlib-compressed serialized NodeDefManager
1440 std::ostringstream tmp_os(std::ios::binary);
1441 nodedef->serialize(tmp_os, protocol_version);
1442 std::ostringstream tmp_os2(std::ios::binary);
1443 compressZlib(tmp_os.str(), tmp_os2);
1445 pkt.putLongString(tmp_os2.str());
1448 verbosestream << "Server: Sending node definitions to id(" << peer_id
1449 << "): size=" << pkt.getSize() << std::endl;
1455 Non-static send methods
1458 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1460 RemotePlayer *player = sao->getPlayer();
1462 // Do not send new format to old clients
1463 incremental &= player->protocol_version >= 38;
1465 UpdateCrafting(player);
1471 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1473 std::ostringstream os(std::ios::binary);
1474 sao->getInventory()->serialize(os, incremental);
1475 sao->getInventory()->setModified(false);
1476 player->setModified(true);
1478 const std::string &s = os.str();
1479 pkt.putRawString(s.c_str(), s.size());
1483 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1485 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1487 u8 type = message.type;
1488 pkt << version << type << message.sender << message.message
1489 << static_cast<u64>(message.timestamp);
1491 if (peer_id != PEER_ID_INEXISTENT) {
1492 RemotePlayer *player = m_env->getPlayer(peer_id);
1498 m_clients.sendToAll(&pkt);
1502 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1503 const std::string &formname)
1505 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1506 if (formspec.empty()){
1507 //the client should close the formspec
1508 //but make sure there wasn't another one open in meantime
1509 const auto it = m_formspec_state_data.find(peer_id);
1510 if (it != m_formspec_state_data.end() && it->second == formname) {
1511 m_formspec_state_data.erase(peer_id);
1513 pkt.putLongString("");
1515 m_formspec_state_data[peer_id] = formname;
1516 pkt.putLongString(formspec);
1523 // Spawns a particle on peer with peer_id
1524 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1525 const ParticleParameters &p)
1527 static thread_local const float radius =
1528 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1530 if (peer_id == PEER_ID_INEXISTENT) {
1531 std::vector<session_t> clients = m_clients.getClientIDs();
1532 const v3f pos = p.pos * BS;
1533 const float radius_sq = radius * radius;
1535 for (const session_t client_id : clients) {
1536 RemotePlayer *player = m_env->getPlayer(client_id);
1540 PlayerSAO *sao = player->getPlayerSAO();
1544 // Do not send to distant clients
1545 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1548 SendSpawnParticle(client_id, player->protocol_version, p);
1552 assert(protocol_version != 0);
1554 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1557 // NetworkPacket and iostreams are incompatible...
1558 std::ostringstream oss(std::ios_base::binary);
1559 p.serialize(oss, protocol_version);
1560 pkt.putRawString(oss.str());
1566 // Adds a ParticleSpawner on peer with peer_id
1567 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1568 const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1570 static thread_local const float radius =
1571 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1573 if (peer_id == PEER_ID_INEXISTENT) {
1574 std::vector<session_t> clients = m_clients.getClientIDs();
1575 const v3f pos = (p.minpos + p.maxpos) / 2.0f * BS;
1576 const float radius_sq = radius * radius;
1577 /* Don't send short-lived spawners to distant players.
1578 * This could be replaced with proper tracking at some point. */
1579 const bool distance_check = !attached_id && p.time <= 1.0f;
1581 for (const session_t client_id : clients) {
1582 RemotePlayer *player = m_env->getPlayer(client_id);
1586 if (distance_check) {
1587 PlayerSAO *sao = player->getPlayerSAO();
1590 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1594 SendAddParticleSpawner(client_id, player->protocol_version,
1595 p, attached_id, id);
1599 assert(protocol_version != 0);
1601 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1603 pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
1604 << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
1605 << p.minsize << p.maxsize << p.collisiondetection;
1607 pkt.putLongString(p.texture);
1609 pkt << id << p.vertical << p.collision_removal << attached_id;
1611 std::ostringstream os(std::ios_base::binary);
1612 p.animation.serialize(os, protocol_version);
1613 pkt.putRawString(os.str());
1615 pkt << p.glow << p.object_collision;
1616 pkt << p.node.param0 << p.node.param2 << p.node_tile;
1621 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1623 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1627 if (peer_id != PEER_ID_INEXISTENT)
1630 m_clients.sendToAll(&pkt);
1634 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1636 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1638 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1639 << form->text << form->number << form->item << form->dir
1640 << form->align << form->offset << form->world_pos << form->size
1641 << form->z_index << form->text2;
1646 void Server::SendHUDRemove(session_t peer_id, u32 id)
1648 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1653 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1655 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1656 pkt << id << (u8) stat;
1660 case HUD_STAT_SCALE:
1661 case HUD_STAT_ALIGN:
1662 case HUD_STAT_OFFSET:
1663 pkt << *(v2f *) value;
1667 case HUD_STAT_TEXT2:
1668 pkt << *(std::string *) value;
1670 case HUD_STAT_WORLD_POS:
1671 pkt << *(v3f *) value;
1674 pkt << *(v2s32 *) value;
1676 case HUD_STAT_NUMBER:
1680 pkt << *(u32 *) value;
1687 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1689 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1691 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1693 pkt << flags << mask;
1698 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1700 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1701 pkt << param << value;
1705 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1707 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1709 // Handle prior clients here
1710 if (m_clients.getProtocolVersion(peer_id) < 39) {
1711 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1713 for (const std::string& texture : params.textures)
1716 pkt << params.clouds;
1717 } else { // Handle current clients and future clients
1718 pkt << params.bgcolor << params.type
1719 << params.clouds << params.fog_sun_tint
1720 << params.fog_moon_tint << params.fog_tint_type;
1722 if (params.type == "skybox") {
1723 pkt << (u16) params.textures.size();
1724 for (const std::string &texture : params.textures)
1726 } else if (params.type == "regular") {
1727 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1728 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1729 << params.sky_color.night_sky << params.sky_color.night_horizon
1730 << params.sky_color.indoors;
1737 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1739 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1740 pkt << params.visible << params.texture
1741 << params.tonemap << params.sunrise
1742 << params.sunrise_visible << params.scale;
1746 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1748 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1750 pkt << params.visible << params.texture
1751 << params.tonemap << params.scale;
1755 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1757 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1759 pkt << params.visible << params.count
1760 << params.starcolor << params.scale;
1765 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1767 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1768 pkt << params.density << params.color_bright << params.color_ambient
1769 << params.height << params.thickness << params.speed;
1773 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1776 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1779 pkt << do_override << (u16) (ratio * 65535);
1784 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1786 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1787 pkt << time << time_speed;
1789 if (peer_id == PEER_ID_INEXISTENT) {
1790 m_clients.sendToAll(&pkt);
1797 void Server::SendPlayerHP(session_t peer_id)
1799 PlayerSAO *playersao = getPlayerSAO(peer_id);
1802 SendHP(peer_id, playersao->getHP());
1803 m_script->player_event(playersao,"health_changed");
1805 // Send to other clients
1806 playersao->sendPunchCommand();
1809 void Server::SendPlayerBreath(PlayerSAO *sao)
1813 m_script->player_event(sao, "breath_changed");
1814 SendBreath(sao->getPeerID(), sao->getBreath());
1817 void Server::SendMovePlayer(session_t peer_id)
1819 RemotePlayer *player = m_env->getPlayer(peer_id);
1821 PlayerSAO *sao = player->getPlayerSAO();
1824 // Send attachment updates instantly to the client prior updating position
1825 sao->sendOutdatedData();
1827 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1828 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1831 v3f pos = sao->getBasePosition();
1832 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1833 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1834 << " pitch=" << sao->getLookPitch()
1835 << " yaw=" << sao->getRotation().Y
1842 void Server::SendPlayerFov(session_t peer_id)
1844 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1846 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1847 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1852 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1853 f32 animation_speed)
1855 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1858 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1859 << animation_frames[3] << animation_speed;
1864 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1866 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1867 pkt << first << third;
1871 void Server::SendPlayerPrivileges(session_t peer_id)
1873 RemotePlayer *player = m_env->getPlayer(peer_id);
1875 if(player->getPeerId() == PEER_ID_INEXISTENT)
1878 std::set<std::string> privs;
1879 m_script->getAuth(player->getName(), NULL, &privs);
1881 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1882 pkt << (u16) privs.size();
1884 for (const std::string &priv : privs) {
1891 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1893 RemotePlayer *player = m_env->getPlayer(peer_id);
1895 if (player->getPeerId() == PEER_ID_INEXISTENT)
1898 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1899 pkt.putLongString(player->inventory_formspec);
1904 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1906 RemotePlayer *player = m_env->getPlayer(peer_id);
1908 if (player->getPeerId() == PEER_ID_INEXISTENT)
1911 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1912 pkt << player->formspec_prepend;
1916 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1918 // Radius inside which objects are active
1919 static thread_local const s16 radius =
1920 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1922 // Radius inside which players are active
1923 static thread_local const bool is_transfer_limited =
1924 g_settings->exists("unlimited_player_transfer_distance") &&
1925 !g_settings->getBool("unlimited_player_transfer_distance");
1927 static thread_local const s16 player_transfer_dist =
1928 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1930 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1931 radius : player_transfer_dist;
1933 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1937 std::queue<u16> removed_objects, added_objects;
1938 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1939 client->m_known_objects, removed_objects);
1940 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1941 client->m_known_objects, added_objects);
1943 int removed_count = removed_objects.size();
1944 int added_count = added_objects.size();
1946 if (removed_objects.empty() && added_objects.empty())
1952 // Handle removed objects
1953 writeU16((u8*)buf, removed_objects.size());
1954 data.append(buf, 2);
1955 while (!removed_objects.empty()) {
1957 u16 id = removed_objects.front();
1958 ServerActiveObject* obj = m_env->getActiveObject(id);
1960 // Add to data buffer for sending
1961 writeU16((u8*)buf, id);
1962 data.append(buf, 2);
1964 // Remove from known objects
1965 client->m_known_objects.erase(id);
1967 if (obj && obj->m_known_by_count > 0)
1968 obj->m_known_by_count--;
1970 removed_objects.pop();
1973 // Handle added objects
1974 writeU16((u8*)buf, added_objects.size());
1975 data.append(buf, 2);
1976 while (!added_objects.empty()) {
1978 u16 id = added_objects.front();
1979 ServerActiveObject *obj = m_env->getActiveObject(id);
1980 added_objects.pop();
1983 warningstream << FUNCTION_NAME << ": NULL object id="
1984 << (int)id << std::endl;
1989 u8 type = obj->getSendType();
1991 // Add to data buffer for sending
1992 writeU16((u8*)buf, id);
1993 data.append(buf, 2);
1994 writeU8((u8*)buf, type);
1995 data.append(buf, 1);
1997 data.append(serializeString32(
1998 obj->getClientInitializationData(client->net_proto_version)));
2000 // Add to known objects
2001 client->m_known_objects.insert(id);
2003 obj->m_known_by_count++;
2006 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2007 pkt.putRawString(data.c_str(), data.size());
2010 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2011 << removed_count << " removed, " << added_count << " added, "
2012 << "packet size is " << pkt.getSize() << std::endl;
2015 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2018 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2019 datas.size(), peer_id);
2021 pkt.putRawString(datas.c_str(), datas.size());
2023 m_clients.send(pkt.getPeerId(),
2024 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2028 void Server::SendCSMRestrictionFlags(session_t peer_id)
2030 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2031 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2032 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2036 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2038 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2043 inline s32 Server::nextSoundId()
2045 s32 ret = m_next_sound_id;
2046 if (m_next_sound_id == INT32_MAX)
2047 m_next_sound_id = 0; // signed overflow is undefined
2053 s32 Server::playSound(const SimpleSoundSpec &spec,
2054 const ServerSoundParams ¶ms, bool ephemeral)
2056 // Find out initial position of sound
2057 bool pos_exists = false;
2058 v3f pos = params.getPos(m_env, &pos_exists);
2059 // If position is not found while it should be, cancel sound
2060 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2063 // Filter destination clients
2064 std::vector<session_t> dst_clients;
2065 if (!params.to_player.empty()) {
2066 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2068 infostream<<"Server::playSound: Player \""<<params.to_player
2069 <<"\" not found"<<std::endl;
2072 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2073 infostream<<"Server::playSound: Player \""<<params.to_player
2074 <<"\" not connected"<<std::endl;
2077 dst_clients.push_back(player->getPeerId());
2079 std::vector<session_t> clients = m_clients.getClientIDs();
2081 for (const session_t client_id : clients) {
2082 RemotePlayer *player = m_env->getPlayer(client_id);
2085 if (!params.exclude_player.empty() &&
2086 params.exclude_player == player->getName())
2089 PlayerSAO *sao = player->getPlayerSAO();
2094 if(sao->getBasePosition().getDistanceFrom(pos) >
2095 params.max_hear_distance)
2098 dst_clients.push_back(client_id);
2102 if(dst_clients.empty())
2107 ServerPlayingSound *psound = nullptr;
2109 id = -1; // old clients will still use this, so pick a reserved ID
2112 // The sound will exist as a reference in m_playing_sounds
2113 m_playing_sounds[id] = ServerPlayingSound();
2114 psound = &m_playing_sounds[id];
2115 psound->params = params;
2116 psound->spec = spec;
2119 float gain = params.gain * spec.gain;
2120 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2121 pkt << id << spec.name << gain
2122 << (u8) params.type << pos << params.object
2123 << params.loop << params.fade << params.pitch
2126 bool as_reliable = !ephemeral;
2128 for (const u16 dst_client : dst_clients) {
2130 psound->clients.insert(dst_client);
2131 m_clients.send(dst_client, 0, &pkt, as_reliable);
2135 void Server::stopSound(s32 handle)
2137 // Get sound reference
2138 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2139 m_playing_sounds.find(handle);
2140 if (i == m_playing_sounds.end())
2142 ServerPlayingSound &psound = i->second;
2144 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2147 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2148 si != psound.clients.end(); ++si) {
2150 m_clients.send(*si, 0, &pkt, true);
2152 // Remove sound reference
2153 m_playing_sounds.erase(i);
2156 void Server::fadeSound(s32 handle, float step, float gain)
2158 // Get sound reference
2159 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2160 m_playing_sounds.find(handle);
2161 if (i == m_playing_sounds.end())
2164 ServerPlayingSound &psound = i->second;
2165 psound.params.gain = gain;
2167 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2168 pkt << handle << step << gain;
2170 // Backwards compability
2171 bool play_sound = gain > 0;
2172 ServerPlayingSound compat_psound = psound;
2173 compat_psound.clients.clear();
2175 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2176 compat_pkt << handle;
2178 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2179 it != psound.clients.end();) {
2180 if (m_clients.getProtocolVersion(*it) >= 32) {
2182 m_clients.send(*it, 0, &pkt, true);
2185 compat_psound.clients.insert(*it);
2187 m_clients.send(*it, 0, &compat_pkt, true);
2188 psound.clients.erase(it++);
2192 // Remove sound reference
2193 if (!play_sound || psound.clients.empty())
2194 m_playing_sounds.erase(i);
2196 if (play_sound && !compat_psound.clients.empty()) {
2197 // Play new sound volume on older clients
2198 playSound(compat_psound.spec, compat_psound.params);
2202 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2205 float maxd = far_d_nodes * BS;
2206 v3f p_f = intToFloat(p, BS);
2207 v3s16 block_pos = getNodeBlockPos(p);
2209 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2212 std::vector<session_t> clients = m_clients.getClientIDs();
2215 for (session_t client_id : clients) {
2216 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2220 RemotePlayer *player = m_env->getPlayer(client_id);
2221 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2223 // If player is far away, only set modified blocks not sent
2224 if (!client->isBlockSent(block_pos) || (sao &&
2225 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2227 far_players->emplace(client_id);
2229 client->SetBlockNotSent(block_pos);
2234 m_clients.send(client_id, 0, &pkt, true);
2240 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2241 float far_d_nodes, bool remove_metadata)
2243 float maxd = far_d_nodes * BS;
2244 v3f p_f = intToFloat(p, BS);
2245 v3s16 block_pos = getNodeBlockPos(p);
2247 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2248 pkt << p << n.param0 << n.param1 << n.param2
2249 << (u8) (remove_metadata ? 0 : 1);
2251 std::vector<session_t> clients = m_clients.getClientIDs();
2254 for (session_t client_id : clients) {
2255 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2259 RemotePlayer *player = m_env->getPlayer(client_id);
2260 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2262 // If player is far away, only set modified blocks not sent
2263 if (!client->isBlockSent(block_pos) || (sao &&
2264 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2266 far_players->emplace(client_id);
2268 client->SetBlockNotSent(block_pos);
2273 m_clients.send(client_id, 0, &pkt, true);
2279 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2281 float maxd = far_d_nodes * BS;
2282 NodeMetadataList meta_updates_list(false);
2283 std::vector<session_t> clients = m_clients.getClientIDs();
2287 for (session_t i : clients) {
2288 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2292 ServerActiveObject *player = m_env->getActiveObject(i);
2293 v3f player_pos = player ? player->getBasePosition() : v3f();
2295 for (const v3s16 &pos : meta_updates) {
2296 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2301 v3s16 block_pos = getNodeBlockPos(pos);
2302 if (!client->isBlockSent(block_pos) || (player &&
2303 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2304 client->SetBlockNotSent(block_pos);
2308 // Add the change to send list
2309 meta_updates_list.set(pos, meta);
2311 if (meta_updates_list.size() == 0)
2314 // Send the meta changes
2315 std::ostringstream os(std::ios::binary);
2316 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2317 std::ostringstream oss(std::ios::binary);
2318 compressZlib(os.str(), oss);
2320 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2321 pkt.putLongString(oss.str());
2322 m_clients.send(i, 0, &pkt, true);
2324 meta_updates_list.clear();
2330 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2331 u16 net_proto_version)
2334 Create a packet with the block in the right format
2336 thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
2337 std::ostringstream os(std::ios_base::binary);
2338 block->serialize(os, ver, false, net_compression_level);
2339 block->serializeNetworkSpecific(os);
2340 std::string s = os.str();
2342 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + s.size(), peer_id);
2344 pkt << block->getPos();
2345 pkt.putRawString(s.c_str(), s.size());
2349 void Server::SendBlocks(float dtime)
2351 MutexAutoLock envlock(m_env_mutex);
2352 //TODO check if one big lock could be faster then multiple small ones
2354 std::vector<PrioritySortedBlockTransfer> queue;
2356 u32 total_sending = 0;
2359 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2361 std::vector<session_t> clients = m_clients.getClientIDs();
2364 for (const session_t client_id : clients) {
2365 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2370 total_sending += client->getSendingCount();
2371 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2377 // Lowest priority number comes first.
2378 // Lowest is most important.
2379 std::sort(queue.begin(), queue.end());
2383 // Maximal total count calculation
2384 // The per-client block sends is halved with the maximal online users
2385 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2386 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2388 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2389 Map &map = m_env->getMap();
2391 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2392 if (total_sending >= max_blocks_to_send)
2395 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2399 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2404 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2405 client->net_proto_version);
2407 client->SentBlock(block_to_send.pos);
2413 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2415 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2420 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2421 if (!client || client->isBlockSent(blockpos)) {
2425 SendBlockNoLock(peer_id, block, client->serialization_version,
2426 client->net_proto_version);
2432 bool Server::addMediaFile(const std::string &filename,
2433 const std::string &filepath, std::string *filedata_to,
2434 std::string *digest_to)
2436 // If name contains illegal characters, ignore the file
2437 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2438 infostream << "Server: ignoring illegal file name: \""
2439 << filename << "\"" << std::endl;
2442 // If name is not in a supported format, ignore it
2443 const char *supported_ext[] = {
2444 ".png", ".jpg", ".bmp", ".tga",
2445 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2447 ".x", ".b3d", ".md2", ".obj",
2448 // Custom translation file format
2452 if (removeStringEnd(filename, supported_ext).empty()) {
2453 infostream << "Server: ignoring unsupported file extension: \""
2454 << filename << "\"" << std::endl;
2457 // Ok, attempt to load the file and add to cache
2460 std::string filedata;
2461 if (!fs::ReadFile(filepath, filedata)) {
2462 errorstream << "Server::addMediaFile(): Failed to open \""
2463 << filename << "\" for reading" << std::endl;
2467 if (filedata.empty()) {
2468 errorstream << "Server::addMediaFile(): Empty file \""
2469 << filepath << "\"" << std::endl;
2474 sha1.addBytes(filedata.c_str(), filedata.length());
2476 unsigned char *digest = sha1.getDigest();
2477 std::string sha1_base64 = base64_encode(digest, 20);
2478 std::string sha1_hex = hex_encode((char*) digest, 20);
2480 *digest_to = std::string((char*) digest, 20);
2484 m_media[filename] = MediaInfo(filepath, sha1_base64);
2485 verbosestream << "Server: " << sha1_hex << " is " << filename
2489 *filedata_to = std::move(filedata);
2493 void Server::fillMediaCache()
2495 infostream << "Server: Calculating media file checksums" << std::endl;
2497 // Collect all media file paths
2498 std::vector<std::string> paths;
2500 // ordered in descending priority
2501 paths.push_back(getBuiltinLuaPath() + DIR_DELIM + "locale");
2502 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2503 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2504 m_modmgr->getModsMediaPaths(paths);
2506 // Collect media file information from paths into cache
2507 for (const std::string &mediapath : paths) {
2508 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2509 for (const fs::DirListNode &dln : dirlist) {
2510 if (dln.dir) // Ignore dirs (already in paths)
2513 const std::string &filename = dln.name;
2514 if (m_media.find(filename) != m_media.end()) // Do not override
2517 std::string filepath = mediapath;
2518 filepath.append(DIR_DELIM).append(filename);
2519 addMediaFile(filename, filepath);
2523 infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2526 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2529 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2532 std::string lang_suffix;
2533 lang_suffix.append(".").append(lang_code).append(".tr");
2534 for (const auto &i : m_media) {
2535 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2542 for (const auto &i : m_media) {
2543 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2545 pkt << i.first << i.second.sha1_digest;
2548 pkt << g_settings->get("remote_media");
2551 verbosestream << "Server: Announcing files to id(" << peer_id
2552 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2555 struct SendableMedia
2561 SendableMedia(const std::string &name_="", const std::string &path_="",
2562 const std::string &data_=""):
2569 void Server::sendRequestedMedia(session_t peer_id,
2570 const std::vector<std::string> &tosend)
2572 verbosestream<<"Server::sendRequestedMedia(): "
2573 <<"Sending files to client"<<std::endl;
2577 // Put 5kB in one bunch (this is not accurate)
2578 u32 bytes_per_bunch = 5000;
2580 std::vector< std::vector<SendableMedia> > file_bunches;
2581 file_bunches.emplace_back();
2583 u32 file_size_bunch_total = 0;
2585 for (const std::string &name : tosend) {
2586 if (m_media.find(name) == m_media.end()) {
2587 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2588 <<"unknown file \""<<(name)<<"\""<<std::endl;
2592 //TODO get path + name
2593 std::string tpath = m_media[name].path;
2596 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2598 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2599 <<tpath<<"\" for reading"<<std::endl;
2602 std::ostringstream tmp_os(std::ios_base::binary);
2606 fis.read(buf, 1024);
2607 std::streamsize len = fis.gcount();
2608 tmp_os.write(buf, len);
2609 file_size_bunch_total += len;
2618 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2619 <<name<<"\""<<std::endl;
2622 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2623 <<tname<<"\""<<std::endl;*/
2625 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2627 // Start next bunch if got enough data
2628 if(file_size_bunch_total >= bytes_per_bunch) {
2629 file_bunches.emplace_back();
2630 file_size_bunch_total = 0;
2635 /* Create and send packets */
2637 u16 num_bunches = file_bunches.size();
2638 for (u16 i = 0; i < num_bunches; i++) {
2641 u16 total number of texture bunches
2642 u16 index of this bunch
2643 u32 number of files in this bunch
2652 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2653 pkt << num_bunches << i << (u32) file_bunches[i].size();
2655 for (const SendableMedia &j : file_bunches[i]) {
2657 pkt.putLongString(j.data);
2660 verbosestream << "Server::sendRequestedMedia(): bunch "
2661 << i << "/" << num_bunches
2662 << " files=" << file_bunches[i].size()
2663 << " size=" << pkt.getSize() << std::endl;
2668 void Server::SendMinimapModes(session_t peer_id,
2669 std::vector<MinimapMode> &modes, size_t wanted_mode)
2671 RemotePlayer *player = m_env->getPlayer(peer_id);
2673 if (player->getPeerId() == PEER_ID_INEXISTENT)
2676 NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2677 pkt << (u16)modes.size() << (u16)wanted_mode;
2679 for (auto &mode : modes)
2680 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2685 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2687 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2691 pkt << false; // Remove inventory
2693 pkt << true; // Update inventory
2695 // Serialization & NetworkPacket isn't a love story
2696 std::ostringstream os(std::ios_base::binary);
2697 inventory->serialize(os);
2698 inventory->setModified(false);
2700 const std::string &os_str = os.str();
2701 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2702 pkt.putRawString(os_str);
2705 if (peer_id == PEER_ID_INEXISTENT)
2706 m_clients.sendToAll(&pkt);
2711 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2713 // Lookup player name, to filter detached inventories just after
2714 std::string peer_name;
2715 if (peer_id != PEER_ID_INEXISTENT) {
2716 peer_name = getClient(peer_id, CS_Created)->getName();
2719 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2720 sendDetachedInventory(inv, name, peer_id);
2723 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2730 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2732 PlayerSAO *playersao = getPlayerSAO(peer_id);
2735 infostream << "Server::DiePlayer(): Player "
2736 << playersao->getPlayer()->getName()
2737 << " dies" << std::endl;
2739 playersao->setHP(0, reason);
2740 playersao->clearParentAttachment();
2742 // Trigger scripted stuff
2743 m_script->on_dieplayer(playersao, reason);
2745 SendPlayerHP(peer_id);
2746 SendDeathscreen(peer_id, false, v3f(0,0,0));
2749 void Server::RespawnPlayer(session_t peer_id)
2751 PlayerSAO *playersao = getPlayerSAO(peer_id);
2754 infostream << "Server::RespawnPlayer(): Player "
2755 << playersao->getPlayer()->getName()
2756 << " respawns" << std::endl;
2758 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2759 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2760 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2762 bool repositioned = m_script->on_respawnplayer(playersao);
2763 if (!repositioned) {
2764 // setPos will send the new position to client
2765 playersao->setPos(findSpawnPos());
2768 SendPlayerHP(peer_id);
2772 void Server::DenySudoAccess(session_t peer_id)
2774 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2779 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2780 const std::string &str_reason, bool reconnect)
2782 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2784 m_clients.event(peer_id, CSE_SetDenied);
2785 DisconnectPeer(peer_id);
2789 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2790 const std::string &custom_reason)
2792 SendAccessDenied(peer_id, reason, custom_reason);
2793 m_clients.event(peer_id, CSE_SetDenied);
2794 DisconnectPeer(peer_id);
2797 // 13/03/15: remove this function when protocol version 25 will become
2798 // the minimum version for MT users, maybe in 1 year
2799 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2801 SendAccessDenied_Legacy(peer_id, reason);
2802 m_clients.event(peer_id, CSE_SetDenied);
2803 DisconnectPeer(peer_id);
2806 void Server::DisconnectPeer(session_t peer_id)
2808 m_modchannel_mgr->leaveAllChannels(peer_id);
2809 m_con->DisconnectPeer(peer_id);
2812 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2815 RemoteClient* client = getClient(peer_id, CS_Invalid);
2817 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2819 // Right now, the auth mechs don't change between login and sudo mode.
2820 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2821 client->allowed_sudo_mechs = sudo_auth_mechs;
2823 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2824 << g_settings->getFloat("dedicated_server_step")
2828 m_clients.event(peer_id, CSE_AuthAccept);
2830 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2832 // We only support SRP right now
2833 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2835 resp_pkt << sudo_auth_mechs;
2837 m_clients.event(peer_id, CSE_SudoSuccess);
2841 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2843 std::wstring message;
2846 Clear references to playing sounds
2848 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2849 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2850 ServerPlayingSound &psound = i->second;
2851 psound.clients.erase(peer_id);
2852 if (psound.clients.empty())
2853 m_playing_sounds.erase(i++);
2858 // clear formspec info so the next client can't abuse the current state
2859 m_formspec_state_data.erase(peer_id);
2861 RemotePlayer *player = m_env->getPlayer(peer_id);
2863 /* Run scripts and remove from environment */
2865 PlayerSAO *playersao = player->getPlayerSAO();
2868 playersao->clearChildAttachments();
2869 playersao->clearParentAttachment();
2871 // inform connected clients
2872 const std::string &player_name = player->getName();
2873 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2874 // (u16) 1 + std::string represents a vector serialization representation
2875 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2876 m_clients.sendToAll(¬ice);
2878 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2880 playersao->disconnected();
2887 if (player && reason != CDR_DENY) {
2888 std::ostringstream os(std::ios_base::binary);
2889 std::vector<session_t> clients = m_clients.getClientIDs();
2891 for (const session_t client_id : clients) {
2893 RemotePlayer *player = m_env->getPlayer(client_id);
2897 // Get name of player
2898 os << player->getName() << " ";
2901 std::string name = player->getName();
2902 actionstream << name << " "
2903 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2904 << " List of players: " << os.str() << std::endl;
2906 m_admin_chat->outgoing_queue.push_back(
2907 new ChatEventNick(CET_NICK_REMOVE, name));
2911 MutexAutoLock env_lock(m_env_mutex);
2912 m_clients.DeleteClient(peer_id);
2916 // Send leave chat message to all remaining clients
2917 if (!message.empty()) {
2918 SendChatMessage(PEER_ID_INEXISTENT,
2919 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2923 void Server::UpdateCrafting(RemotePlayer *player)
2925 InventoryList *clist = player->inventory.getList("craft");
2926 if (!clist || clist->getSize() == 0)
2929 if (!clist->checkModified())
2932 // Get a preview for crafting
2934 InventoryLocation loc;
2935 loc.setPlayer(player->getName());
2936 std::vector<ItemStack> output_replacements;
2937 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2938 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2941 InventoryList *plist = player->inventory.getList("craftpreview");
2942 if (plist && plist->getSize() >= 1) {
2943 // Put the new preview in
2944 plist->changeItem(0, preview);
2948 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2950 if (evt->type == CET_NICK_ADD) {
2951 // The terminal informed us of its nick choice
2952 m_admin_nick = ((ChatEventNick *)evt)->nick;
2953 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2954 errorstream << "You haven't set up an account." << std::endl
2955 << "Please log in using the client as '"
2956 << m_admin_nick << "' with a secure password." << std::endl
2957 << "Until then, you can't execute admin tasks via the console," << std::endl
2958 << "and everybody can claim the user account instead of you," << std::endl
2959 << "giving them full control over this server." << std::endl;
2962 assert(evt->type == CET_CHAT);
2963 handleAdminChat((ChatEventChat *)evt);
2967 std::wstring Server::handleChat(const std::string &name,
2968 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2970 // If something goes wrong, this player is to blame
2971 RollbackScopeActor rollback_scope(m_rollback,
2972 std::string("player:") + name);
2974 if (g_settings->getBool("strip_color_codes"))
2975 wmessage = unescape_enriched(wmessage);
2978 switch (player->canSendChatMessage()) {
2979 case RPLAYER_CHATRESULT_FLOODING: {
2980 std::wstringstream ws;
2981 ws << L"You cannot send more messages. You are limited to "
2982 << g_settings->getFloat("chat_message_limit_per_10sec")
2983 << L" messages per 10 seconds.";
2986 case RPLAYER_CHATRESULT_KICK:
2987 DenyAccess_Legacy(player->getPeerId(),
2988 L"You have been kicked due to message flooding.");
2990 case RPLAYER_CHATRESULT_OK:
2993 FATAL_ERROR("Unhandled chat filtering result found.");
2997 if (m_max_chatmessage_length > 0
2998 && wmessage.length() > m_max_chatmessage_length) {
2999 return L"Your message exceed the maximum chat message limit set on the server. "
3000 L"It was refused. Send a shorter message";
3003 auto message = trim(wide_to_utf8(wmessage));
3004 if (message.empty())
3007 if (message.find_first_of("\n\r") != std::wstring::npos) {
3008 return L"Newlines are not permitted in chat messages";
3011 // Run script hook, exit if script ate the chat message
3012 if (m_script->on_chat_message(name, message))
3017 // Whether to send line to the player that sent the message, or to all players
3018 bool broadcast_line = true;
3020 if (check_shout_priv && !checkPriv(name, "shout")) {
3021 line += L"-!- You don't have permission to shout.";
3022 broadcast_line = false;
3025 Workaround for fixing chat on Android. Lua doesn't handle
3026 the Cyrillic alphabet and some characters on older Android devices
3029 line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
3031 line += utf8_to_wide(m_script->formatChatMessage(name,
3032 wide_to_utf8(wmessage)));
3037 Tell calling method to send the message to sender
3039 if (!broadcast_line)
3043 Send the message to others
3045 actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
3047 ChatMessage chatmsg(line);
3049 std::vector<session_t> clients = m_clients.getClientIDs();
3050 for (u16 cid : clients)
3051 SendChatMessage(cid, chatmsg);
3056 void Server::handleAdminChat(const ChatEventChat *evt)
3058 std::string name = evt->nick;
3059 std::wstring wmessage = evt->evt_msg;
3061 std::wstring answer = handleChat(name, wmessage);
3063 // If asked to send answer to sender
3064 if (!answer.empty()) {
3065 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3069 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3071 RemoteClient *client = getClientNoEx(peer_id,state_min);
3073 throw ClientNotFoundException("Client not found");
3077 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3079 return m_clients.getClientNoEx(peer_id, state_min);
3082 std::string Server::getPlayerName(session_t peer_id)
3084 RemotePlayer *player = m_env->getPlayer(peer_id);
3086 return "[id="+itos(peer_id)+"]";
3087 return player->getName();
3090 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3092 RemotePlayer *player = m_env->getPlayer(peer_id);
3095 return player->getPlayerSAO();
3098 std::string Server::getStatusString()
3100 std::ostringstream os(std::ios_base::binary);
3103 os << "version=" << g_version_string;
3105 os << ", uptime=" << m_uptime_counter->get();
3107 os << ", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3109 // Information about clients
3111 os << ", clients={";
3113 std::vector<session_t> clients = m_clients.getClientIDs();
3114 for (session_t client_id : clients) {
3115 RemotePlayer *player = m_env->getPlayer(client_id);
3117 // Get name of player
3118 const char *name = player ? player->getName() : "<unknown>";
3120 // Add name to information string
3130 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3131 os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
3133 if (!g_settings->get("motd").empty())
3134 os << std::endl << "# Server: " << g_settings->get("motd");
3139 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3141 std::set<std::string> privs;
3142 m_script->getAuth(name, NULL, &privs);
3146 bool Server::checkPriv(const std::string &name, const std::string &priv)
3148 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3149 return (privs.count(priv) != 0);
3152 void Server::reportPrivsModified(const std::string &name)
3155 std::vector<session_t> clients = m_clients.getClientIDs();
3156 for (const session_t client_id : clients) {
3157 RemotePlayer *player = m_env->getPlayer(client_id);
3158 reportPrivsModified(player->getName());
3161 RemotePlayer *player = m_env->getPlayer(name.c_str());
3164 SendPlayerPrivileges(player->getPeerId());
3165 PlayerSAO *sao = player->getPlayerSAO();
3168 sao->updatePrivileges(
3169 getPlayerEffectivePrivs(name),
3174 void Server::reportInventoryFormspecModified(const std::string &name)
3176 RemotePlayer *player = m_env->getPlayer(name.c_str());
3179 SendPlayerInventoryFormspec(player->getPeerId());
3182 void Server::reportFormspecPrependModified(const std::string &name)
3184 RemotePlayer *player = m_env->getPlayer(name.c_str());
3187 SendPlayerFormspecPrepend(player->getPeerId());
3190 void Server::setIpBanned(const std::string &ip, const std::string &name)
3192 m_banmanager->add(ip, name);
3195 void Server::unsetIpBanned(const std::string &ip_or_name)
3197 m_banmanager->remove(ip_or_name);
3200 std::string Server::getBanDescription(const std::string &ip_or_name)
3202 return m_banmanager->getBanDescription(ip_or_name);
3205 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3207 // m_env will be NULL if the server is initializing
3211 if (m_admin_nick == name && !m_admin_nick.empty()) {
3212 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3215 RemotePlayer *player = m_env->getPlayer(name);
3220 if (player->getPeerId() == PEER_ID_INEXISTENT)
3223 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3226 bool Server::showFormspec(const char *playername, const std::string &formspec,
3227 const std::string &formname)
3229 // m_env will be NULL if the server is initializing
3233 RemotePlayer *player = m_env->getPlayer(playername);
3237 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3241 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3246 u32 id = player->addHud(form);
3248 SendHUDAdd(player->getPeerId(), id, form);
3253 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3257 HudElement* todel = player->removeHud(id);
3264 SendHUDRemove(player->getPeerId(), id);
3268 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3273 SendHUDChange(player->getPeerId(), id, stat, data);
3277 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3282 SendHUDSetFlags(player->getPeerId(), flags, mask);
3283 player->hud_flags &= ~mask;
3284 player->hud_flags |= flags;
3286 PlayerSAO* playersao = player->getPlayerSAO();
3291 m_script->player_event(playersao, "hud_changed");
3295 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3300 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3303 player->setHotbarItemcount(hotbar_itemcount);
3304 std::ostringstream os(std::ios::binary);
3305 writeS32(os, hotbar_itemcount);
3306 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3310 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3315 player->setHotbarImage(name);
3316 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3319 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3324 player->setHotbarSelectedImage(name);
3325 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3328 Address Server::getPeerAddress(session_t peer_id)
3330 // Note that this is only set after Init was received in Server::handleCommand_Init
3331 return getClient(peer_id, CS_Invalid)->getAddress();
3334 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3335 v2s32 animation_frames[4], f32 frame_speed)
3337 sanity_check(player);
3338 player->setLocalAnimations(animation_frames, frame_speed);
3339 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3342 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3344 sanity_check(player);
3345 player->eye_offset_first = first;
3346 player->eye_offset_third = third;
3347 SendEyeOffset(player->getPeerId(), first, third);
3350 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3352 sanity_check(player);
3353 player->setSky(params);
3354 SendSetSky(player->getPeerId(), params);
3357 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3359 sanity_check(player);
3360 player->setSun(params);
3361 SendSetSun(player->getPeerId(), params);
3364 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3366 sanity_check(player);
3367 player->setMoon(params);
3368 SendSetMoon(player->getPeerId(), params);
3371 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3373 sanity_check(player);
3374 player->setStars(params);
3375 SendSetStars(player->getPeerId(), params);
3378 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3380 sanity_check(player);
3381 player->setCloudParams(params);
3382 SendCloudParams(player->getPeerId(), params);
3385 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3388 sanity_check(player);
3389 player->overrideDayNightRatio(do_override, ratio);
3390 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3393 void Server::notifyPlayers(const std::wstring &msg)
3395 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3398 void Server::spawnParticle(const std::string &playername,
3399 const ParticleParameters &p)
3401 // m_env will be NULL if the server is initializing
3405 session_t peer_id = PEER_ID_INEXISTENT;
3407 if (!playername.empty()) {
3408 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3411 peer_id = player->getPeerId();
3412 proto_ver = player->protocol_version;
3415 SendSpawnParticle(peer_id, proto_ver, p);
3418 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3419 ServerActiveObject *attached, const std::string &playername)
3421 // m_env will be NULL if the server is initializing
3425 session_t peer_id = PEER_ID_INEXISTENT;
3427 if (!playername.empty()) {
3428 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3431 peer_id = player->getPeerId();
3432 proto_ver = player->protocol_version;
3435 u16 attached_id = attached ? attached->getId() : 0;
3438 if (attached_id == 0)
3439 id = m_env->addParticleSpawner(p.time);
3441 id = m_env->addParticleSpawner(p.time, attached_id);
3443 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3447 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3449 // m_env will be NULL if the server is initializing
3451 throw ServerError("Can't delete particle spawners during initialisation!");
3453 session_t peer_id = PEER_ID_INEXISTENT;
3454 if (!playername.empty()) {
3455 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3458 peer_id = player->getPeerId();
3461 m_env->deleteParticleSpawner(id);
3462 SendDeleteParticleSpawner(peer_id, id);
3465 bool Server::dynamicAddMedia(const std::string &filepath,
3466 std::vector<RemotePlayer*> &sent_to)
3468 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3469 if (m_media.find(filename) != m_media.end()) {
3470 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3471 << "\" already exists in media cache" << std::endl;
3475 // Load the file and add it to our media cache
3476 std::string filedata, raw_hash;
3477 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3481 // Push file to existing clients
3482 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3483 pkt << raw_hash << filename << (bool) true;
3484 pkt.putLongString(filedata);
3487 for (auto &pair : m_clients.getClientList()) {
3488 if (pair.second->getState() < CS_DefinitionsSent)
3490 if (pair.second->net_proto_version < 39)
3493 if (auto player = m_env->getPlayer(pair.second->peer_id))
3494 sent_to.emplace_back(player);
3496 FIXME: this is a very awful hack
3497 The network layer only guarantees ordered delivery inside a channel.
3498 Since the very next packet could be one that uses the media, we have
3499 to push the media over ALL channels to ensure it is processed before
3501 In practice this means we have to send it twice:
3503 - channel 0 (everything else: e.g. play_sound, object messages)
3505 m_clients.send(pair.second->peer_id, 1, &pkt, true);
3506 m_clients.send(pair.second->peer_id, 0, &pkt, true);
3513 // actions: time-reversed list
3514 // Return value: success/failure
3515 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3516 std::list<std::string> *log)
3518 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3519 ServerMap *map = (ServerMap*)(&m_env->getMap());
3521 // Fail if no actions to handle
3522 if (actions.empty()) {
3524 log->push_back("Nothing to do.");
3531 for (const RollbackAction &action : actions) {
3533 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3536 std::ostringstream os;
3537 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3538 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3540 log->push_back(os.str());
3542 std::ostringstream os;
3543 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3544 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3546 log->push_back(os.str());
3550 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3551 <<" failed"<<std::endl;
3553 // Call it done if less than half failed
3554 return num_failed <= num_tried/2;
3557 // IGameDef interface
3559 IItemDefManager *Server::getItemDefManager()
3564 const NodeDefManager *Server::getNodeDefManager()
3569 ICraftDefManager *Server::getCraftDefManager()
3574 u16 Server::allocateUnknownNodeId(const std::string &name)
3576 return m_nodedef->allocateDummy(name);
3579 IWritableItemDefManager *Server::getWritableItemDefManager()
3584 NodeDefManager *Server::getWritableNodeDefManager()
3589 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3594 const std::vector<ModSpec> & Server::getMods() const
3596 return m_modmgr->getMods();
3599 const ModSpec *Server::getModSpec(const std::string &modname) const
3601 return m_modmgr->getModSpec(modname);
3604 void Server::getModNames(std::vector<std::string> &modlist)
3606 m_modmgr->getModNames(modlist);
3609 std::string Server::getBuiltinLuaPath()
3611 return porting::path_share + DIR_DELIM + "builtin";
3614 std::string Server::getModStoragePath() const
3616 return m_path_world + DIR_DELIM + "mod_storage";
3619 v3f Server::findSpawnPos()
3621 ServerMap &map = m_env->getServerMap();
3623 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3624 return nodeposf * BS;
3626 bool is_good = false;
3627 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3628 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3630 // Try to find a good place a few times
3631 for (s32 i = 0; i < 4000 && !is_good; i++) {
3632 s32 range = MYMIN(1 + i, range_max);
3633 // We're going to try to throw the player to this position
3634 v2s16 nodepos2d = v2s16(
3635 -range + (myrand() % (range * 2)),
3636 -range + (myrand() % (range * 2)));
3637 // Get spawn level at point
3638 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3639 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3640 // signify an unsuitable spawn position, or if outside limits.
3641 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3642 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3645 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3646 // Consecutive empty nodes
3649 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3650 // avoid obstructions in already-generated mapblocks.
3651 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3652 // no obstructions, but mapgen decorations are generated after spawn so
3653 // the player may end up inside one.
3654 for (s32 i = 0; i < 8; i++) {
3655 v3s16 blockpos = getNodeBlockPos(nodepos);
3656 map.emergeBlock(blockpos, true);
3657 content_t c = map.getNode(nodepos).getContent();
3659 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3660 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3661 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3663 if (air_count >= 2) {
3664 // Spawn in lower empty node
3666 nodeposf = intToFloat(nodepos, BS);
3667 // Don't spawn the player outside map boundaries
3668 if (objectpos_over_limit(nodeposf))
3669 // Exit this loop, positions above are probably over limit
3672 // Good position found, cause an exit from main loop
3686 // No suitable spawn point found, return fallback 0,0,0
3687 return v3f(0.0f, 0.0f, 0.0f);
3690 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3692 if (delay == 0.0f) {
3693 // No delay, shutdown immediately
3694 m_shutdown_state.is_requested = true;
3695 // only print to the infostream, a chat message saying
3696 // "Server Shutting Down" is sent when the server destructs.
3697 infostream << "*** Immediate Server shutdown requested." << std::endl;
3698 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3699 // Negative delay, cancel shutdown if requested
3700 m_shutdown_state.reset();
3701 std::wstringstream ws;
3703 ws << L"*** Server shutdown canceled.";
3705 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3706 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3707 // m_shutdown_* are already handled, skip.
3709 } else if (delay > 0.0f) {
3710 // Positive delay, tell the clients when the server will shut down
3711 std::wstringstream ws;
3713 ws << L"*** Server shutting down in "
3714 << duration_to_string(myround(delay)).c_str()
3717 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3718 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3721 m_shutdown_state.trigger(delay, msg, reconnect);
3724 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3727 Try to get an existing player
3729 RemotePlayer *player = m_env->getPlayer(name);
3731 // If player is already connected, cancel
3732 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3733 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3738 If player with the wanted peer_id already exists, cancel.
3740 if (m_env->getPlayer(peer_id)) {
3741 infostream<<"emergePlayer(): Player with wrong name but same"
3742 " peer_id already exists"<<std::endl;
3747 player = new RemotePlayer(name, idef());
3750 bool newplayer = false;
3753 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3755 // Complete init with server parts
3756 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3757 player->protocol_version = proto_version;
3761 m_script->on_newplayer(playersao);
3767 bool Server::registerModStorage(ModMetadata *storage)
3769 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3770 errorstream << "Unable to register same mod storage twice. Storage name: "
3771 << storage->getModName() << std::endl;
3775 m_mod_storages[storage->getModName()] = storage;
3779 void Server::unregisterModStorage(const std::string &name)
3781 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3782 if (it != m_mod_storages.end()) {
3783 // Save unconditionaly on unregistration
3784 it->second->save(getModStoragePath());
3785 m_mod_storages.erase(name);
3789 void dedicated_server_loop(Server &server, bool &kill)
3791 verbosestream<<"dedicated_server_loop()"<<std::endl;
3793 IntervalLimiter m_profiler_interval;
3795 static thread_local const float steplen =
3796 g_settings->getFloat("dedicated_server_step");
3797 static thread_local const float profiler_print_interval =
3798 g_settings->getFloat("profiler_print_interval");
3801 * The dedicated server loop only does time-keeping (in Server::step) and
3802 * provides a way to main.cpp to kill the server externally (bool &kill).
3806 // This is kind of a hack but can be done like this
3807 // because server.step() is very light
3808 sleep_ms((int)(steplen*1000.0));
3809 server.step(steplen);
3811 if (server.isShutdownRequested() || kill)
3817 if (profiler_print_interval != 0) {
3818 if(m_profiler_interval.step(steplen, profiler_print_interval))
3820 infostream<<"Profiler:"<<std::endl;
3821 g_profiler->print(infostream);
3822 g_profiler->clear();
3827 infostream << "Dedicated server quitting" << std::endl;
3829 if (g_settings->getBool("server_announce"))
3830 ServerList::sendAnnounce(ServerList::AA_DELETE,
3831 server.m_bind_addr.getPort());
3840 bool Server::joinModChannel(const std::string &channel)
3842 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3843 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3846 bool Server::leaveModChannel(const std::string &channel)
3848 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3851 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3853 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3856 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3860 ModChannel* Server::getModChannel(const std::string &channel)
3862 return m_modchannel_mgr->getModChannel(channel);
3865 void Server::broadcastModChannelMessage(const std::string &channel,
3866 const std::string &message, session_t from_peer)
3868 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3872 if (message.size() > STRING_MAX_LEN) {
3873 warningstream << "ModChannel message too long, dropping before sending "
3874 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3875 << channel << ")" << std::endl;
3880 if (from_peer != PEER_ID_SERVER) {
3881 sender = getPlayerName(from_peer);
3884 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3885 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3886 resp_pkt << channel << sender << message;
3887 for (session_t peer_id : peers) {
3889 if (peer_id == from_peer)
3892 Send(peer_id, &resp_pkt);
3895 if (from_peer != PEER_ID_SERVER) {
3896 m_script->on_modchannel_message(channel, sender, message);
3900 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3902 if (lang_code.empty())
3905 auto it = server_translations.find(lang_code);
3906 if (it != server_translations.end())
3907 return &it->second; // Already loaded
3909 // [] will create an entry
3910 auto *translations = &server_translations[lang_code];
3912 std::string suffix = "." + lang_code + ".tr";
3913 for (const auto &i : m_media) {
3914 if (str_ends_with(i.first, suffix)) {
3916 if (fs::ReadFile(i.second.path, data)) {
3917 translations->loadTranslation(data);
3922 return translations;