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;
2499 // The paths are ordered in descending priority
2500 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2501 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2502 m_modmgr->getModsMediaPaths(paths);
2504 // Collect media file information from paths into cache
2505 for (const std::string &mediapath : paths) {
2506 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2507 for (const fs::DirListNode &dln : dirlist) {
2508 if (dln.dir) // Ignore dirs (already in paths)
2511 const std::string &filename = dln.name;
2512 if (m_media.find(filename) != m_media.end()) // Do not override
2515 std::string filepath = mediapath;
2516 filepath.append(DIR_DELIM).append(filename);
2517 addMediaFile(filename, filepath);
2521 infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2524 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2527 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2530 std::string lang_suffix;
2531 lang_suffix.append(".").append(lang_code).append(".tr");
2532 for (const auto &i : m_media) {
2533 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2540 for (const auto &i : m_media) {
2541 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2543 pkt << i.first << i.second.sha1_digest;
2546 pkt << g_settings->get("remote_media");
2549 verbosestream << "Server: Announcing files to id(" << peer_id
2550 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2553 struct SendableMedia
2559 SendableMedia(const std::string &name_="", const std::string &path_="",
2560 const std::string &data_=""):
2567 void Server::sendRequestedMedia(session_t peer_id,
2568 const std::vector<std::string> &tosend)
2570 verbosestream<<"Server::sendRequestedMedia(): "
2571 <<"Sending files to client"<<std::endl;
2575 // Put 5kB in one bunch (this is not accurate)
2576 u32 bytes_per_bunch = 5000;
2578 std::vector< std::vector<SendableMedia> > file_bunches;
2579 file_bunches.emplace_back();
2581 u32 file_size_bunch_total = 0;
2583 for (const std::string &name : tosend) {
2584 if (m_media.find(name) == m_media.end()) {
2585 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2586 <<"unknown file \""<<(name)<<"\""<<std::endl;
2590 //TODO get path + name
2591 std::string tpath = m_media[name].path;
2594 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2596 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2597 <<tpath<<"\" for reading"<<std::endl;
2600 std::ostringstream tmp_os(std::ios_base::binary);
2604 fis.read(buf, 1024);
2605 std::streamsize len = fis.gcount();
2606 tmp_os.write(buf, len);
2607 file_size_bunch_total += len;
2616 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2617 <<name<<"\""<<std::endl;
2620 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2621 <<tname<<"\""<<std::endl;*/
2623 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2625 // Start next bunch if got enough data
2626 if(file_size_bunch_total >= bytes_per_bunch) {
2627 file_bunches.emplace_back();
2628 file_size_bunch_total = 0;
2633 /* Create and send packets */
2635 u16 num_bunches = file_bunches.size();
2636 for (u16 i = 0; i < num_bunches; i++) {
2639 u16 total number of texture bunches
2640 u16 index of this bunch
2641 u32 number of files in this bunch
2650 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2651 pkt << num_bunches << i << (u32) file_bunches[i].size();
2653 for (const SendableMedia &j : file_bunches[i]) {
2655 pkt.putLongString(j.data);
2658 verbosestream << "Server::sendRequestedMedia(): bunch "
2659 << i << "/" << num_bunches
2660 << " files=" << file_bunches[i].size()
2661 << " size=" << pkt.getSize() << std::endl;
2666 void Server::SendMinimapModes(session_t peer_id,
2667 std::vector<MinimapMode> &modes, size_t wanted_mode)
2669 RemotePlayer *player = m_env->getPlayer(peer_id);
2671 if (player->getPeerId() == PEER_ID_INEXISTENT)
2674 NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2675 pkt << (u16)modes.size() << (u16)wanted_mode;
2677 for (auto &mode : modes)
2678 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2683 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2685 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2689 pkt << false; // Remove inventory
2691 pkt << true; // Update inventory
2693 // Serialization & NetworkPacket isn't a love story
2694 std::ostringstream os(std::ios_base::binary);
2695 inventory->serialize(os);
2696 inventory->setModified(false);
2698 const std::string &os_str = os.str();
2699 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2700 pkt.putRawString(os_str);
2703 if (peer_id == PEER_ID_INEXISTENT)
2704 m_clients.sendToAll(&pkt);
2709 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2711 // Lookup player name, to filter detached inventories just after
2712 std::string peer_name;
2713 if (peer_id != PEER_ID_INEXISTENT) {
2714 peer_name = getClient(peer_id, CS_Created)->getName();
2717 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2718 sendDetachedInventory(inv, name, peer_id);
2721 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2728 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2730 PlayerSAO *playersao = getPlayerSAO(peer_id);
2733 infostream << "Server::DiePlayer(): Player "
2734 << playersao->getPlayer()->getName()
2735 << " dies" << std::endl;
2737 playersao->setHP(0, reason);
2738 playersao->clearParentAttachment();
2740 // Trigger scripted stuff
2741 m_script->on_dieplayer(playersao, reason);
2743 SendPlayerHP(peer_id);
2744 SendDeathscreen(peer_id, false, v3f(0,0,0));
2747 void Server::RespawnPlayer(session_t peer_id)
2749 PlayerSAO *playersao = getPlayerSAO(peer_id);
2752 infostream << "Server::RespawnPlayer(): Player "
2753 << playersao->getPlayer()->getName()
2754 << " respawns" << std::endl;
2756 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2757 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2758 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2760 bool repositioned = m_script->on_respawnplayer(playersao);
2761 if (!repositioned) {
2762 // setPos will send the new position to client
2763 playersao->setPos(findSpawnPos());
2766 SendPlayerHP(peer_id);
2770 void Server::DenySudoAccess(session_t peer_id)
2772 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2777 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2778 const std::string &str_reason, bool reconnect)
2780 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2782 m_clients.event(peer_id, CSE_SetDenied);
2783 DisconnectPeer(peer_id);
2787 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2788 const std::string &custom_reason)
2790 SendAccessDenied(peer_id, reason, custom_reason);
2791 m_clients.event(peer_id, CSE_SetDenied);
2792 DisconnectPeer(peer_id);
2795 // 13/03/15: remove this function when protocol version 25 will become
2796 // the minimum version for MT users, maybe in 1 year
2797 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2799 SendAccessDenied_Legacy(peer_id, reason);
2800 m_clients.event(peer_id, CSE_SetDenied);
2801 DisconnectPeer(peer_id);
2804 void Server::DisconnectPeer(session_t peer_id)
2806 m_modchannel_mgr->leaveAllChannels(peer_id);
2807 m_con->DisconnectPeer(peer_id);
2810 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2813 RemoteClient* client = getClient(peer_id, CS_Invalid);
2815 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2817 // Right now, the auth mechs don't change between login and sudo mode.
2818 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2819 client->allowed_sudo_mechs = sudo_auth_mechs;
2821 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2822 << g_settings->getFloat("dedicated_server_step")
2826 m_clients.event(peer_id, CSE_AuthAccept);
2828 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2830 // We only support SRP right now
2831 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2833 resp_pkt << sudo_auth_mechs;
2835 m_clients.event(peer_id, CSE_SudoSuccess);
2839 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2841 std::wstring message;
2844 Clear references to playing sounds
2846 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2847 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2848 ServerPlayingSound &psound = i->second;
2849 psound.clients.erase(peer_id);
2850 if (psound.clients.empty())
2851 m_playing_sounds.erase(i++);
2856 // clear formspec info so the next client can't abuse the current state
2857 m_formspec_state_data.erase(peer_id);
2859 RemotePlayer *player = m_env->getPlayer(peer_id);
2861 /* Run scripts and remove from environment */
2863 PlayerSAO *playersao = player->getPlayerSAO();
2866 playersao->clearChildAttachments();
2867 playersao->clearParentAttachment();
2869 // inform connected clients
2870 const std::string &player_name = player->getName();
2871 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2872 // (u16) 1 + std::string represents a vector serialization representation
2873 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2874 m_clients.sendToAll(¬ice);
2876 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2878 playersao->disconnected();
2885 if (player && reason != CDR_DENY) {
2886 std::ostringstream os(std::ios_base::binary);
2887 std::vector<session_t> clients = m_clients.getClientIDs();
2889 for (const session_t client_id : clients) {
2891 RemotePlayer *player = m_env->getPlayer(client_id);
2895 // Get name of player
2896 os << player->getName() << " ";
2899 std::string name = player->getName();
2900 actionstream << name << " "
2901 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2902 << " List of players: " << os.str() << std::endl;
2904 m_admin_chat->outgoing_queue.push_back(
2905 new ChatEventNick(CET_NICK_REMOVE, name));
2909 MutexAutoLock env_lock(m_env_mutex);
2910 m_clients.DeleteClient(peer_id);
2914 // Send leave chat message to all remaining clients
2915 if (!message.empty()) {
2916 SendChatMessage(PEER_ID_INEXISTENT,
2917 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2921 void Server::UpdateCrafting(RemotePlayer *player)
2923 InventoryList *clist = player->inventory.getList("craft");
2924 if (!clist || clist->getSize() == 0)
2927 if (!clist->checkModified())
2930 // Get a preview for crafting
2932 InventoryLocation loc;
2933 loc.setPlayer(player->getName());
2934 std::vector<ItemStack> output_replacements;
2935 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2936 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2939 InventoryList *plist = player->inventory.getList("craftpreview");
2940 if (plist && plist->getSize() >= 1) {
2941 // Put the new preview in
2942 plist->changeItem(0, preview);
2946 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2948 if (evt->type == CET_NICK_ADD) {
2949 // The terminal informed us of its nick choice
2950 m_admin_nick = ((ChatEventNick *)evt)->nick;
2951 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2952 errorstream << "You haven't set up an account." << std::endl
2953 << "Please log in using the client as '"
2954 << m_admin_nick << "' with a secure password." << std::endl
2955 << "Until then, you can't execute admin tasks via the console," << std::endl
2956 << "and everybody can claim the user account instead of you," << std::endl
2957 << "giving them full control over this server." << std::endl;
2960 assert(evt->type == CET_CHAT);
2961 handleAdminChat((ChatEventChat *)evt);
2965 std::wstring Server::handleChat(const std::string &name,
2966 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2968 // If something goes wrong, this player is to blame
2969 RollbackScopeActor rollback_scope(m_rollback,
2970 std::string("player:") + name);
2972 if (g_settings->getBool("strip_color_codes"))
2973 wmessage = unescape_enriched(wmessage);
2976 switch (player->canSendChatMessage()) {
2977 case RPLAYER_CHATRESULT_FLOODING: {
2978 std::wstringstream ws;
2979 ws << L"You cannot send more messages. You are limited to "
2980 << g_settings->getFloat("chat_message_limit_per_10sec")
2981 << L" messages per 10 seconds.";
2984 case RPLAYER_CHATRESULT_KICK:
2985 DenyAccess_Legacy(player->getPeerId(),
2986 L"You have been kicked due to message flooding.");
2988 case RPLAYER_CHATRESULT_OK:
2991 FATAL_ERROR("Unhandled chat filtering result found.");
2995 if (m_max_chatmessage_length > 0
2996 && wmessage.length() > m_max_chatmessage_length) {
2997 return L"Your message exceed the maximum chat message limit set on the server. "
2998 L"It was refused. Send a shorter message";
3001 auto message = trim(wide_to_utf8(wmessage));
3002 if (message.find_first_of("\n\r") != std::wstring::npos) {
3003 return L"Newlines are not permitted in chat messages";
3006 // Run script hook, exit if script ate the chat message
3007 if (m_script->on_chat_message(name, message))
3012 // Whether to send line to the player that sent the message, or to all players
3013 bool broadcast_line = true;
3015 if (check_shout_priv && !checkPriv(name, "shout")) {
3016 line += L"-!- You don't have permission to shout.";
3017 broadcast_line = false;
3020 Workaround for fixing chat on Android. Lua doesn't handle
3021 the Cyrillic alphabet and some characters on older Android devices
3024 line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
3026 line += utf8_to_wide(m_script->formatChatMessage(name,
3027 wide_to_utf8(wmessage)));
3032 Tell calling method to send the message to sender
3034 if (!broadcast_line)
3038 Send the message to others
3040 actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
3042 ChatMessage chatmsg(line);
3044 std::vector<session_t> clients = m_clients.getClientIDs();
3045 for (u16 cid : clients)
3046 SendChatMessage(cid, chatmsg);
3051 void Server::handleAdminChat(const ChatEventChat *evt)
3053 std::string name = evt->nick;
3054 std::wstring wmessage = evt->evt_msg;
3056 std::wstring answer = handleChat(name, wmessage);
3058 // If asked to send answer to sender
3059 if (!answer.empty()) {
3060 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3064 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3066 RemoteClient *client = getClientNoEx(peer_id,state_min);
3068 throw ClientNotFoundException("Client not found");
3072 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3074 return m_clients.getClientNoEx(peer_id, state_min);
3077 std::string Server::getPlayerName(session_t peer_id)
3079 RemotePlayer *player = m_env->getPlayer(peer_id);
3081 return "[id="+itos(peer_id)+"]";
3082 return player->getName();
3085 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3087 RemotePlayer *player = m_env->getPlayer(peer_id);
3090 return player->getPlayerSAO();
3093 std::string Server::getStatusString()
3095 std::ostringstream os(std::ios_base::binary);
3098 os << "version=" << g_version_string;
3100 os << ", uptime=" << m_uptime_counter->get();
3102 os << ", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3104 // Information about clients
3106 os << ", clients={";
3108 std::vector<session_t> clients = m_clients.getClientIDs();
3109 for (session_t client_id : clients) {
3110 RemotePlayer *player = m_env->getPlayer(client_id);
3112 // Get name of player
3113 const char *name = player ? player->getName() : "<unknown>";
3115 // Add name to information string
3125 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3126 os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
3128 if (!g_settings->get("motd").empty())
3129 os << std::endl << "# Server: " << g_settings->get("motd");
3134 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3136 std::set<std::string> privs;
3137 m_script->getAuth(name, NULL, &privs);
3141 bool Server::checkPriv(const std::string &name, const std::string &priv)
3143 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3144 return (privs.count(priv) != 0);
3147 void Server::reportPrivsModified(const std::string &name)
3150 std::vector<session_t> clients = m_clients.getClientIDs();
3151 for (const session_t client_id : clients) {
3152 RemotePlayer *player = m_env->getPlayer(client_id);
3153 reportPrivsModified(player->getName());
3156 RemotePlayer *player = m_env->getPlayer(name.c_str());
3159 SendPlayerPrivileges(player->getPeerId());
3160 PlayerSAO *sao = player->getPlayerSAO();
3163 sao->updatePrivileges(
3164 getPlayerEffectivePrivs(name),
3169 void Server::reportInventoryFormspecModified(const std::string &name)
3171 RemotePlayer *player = m_env->getPlayer(name.c_str());
3174 SendPlayerInventoryFormspec(player->getPeerId());
3177 void Server::reportFormspecPrependModified(const std::string &name)
3179 RemotePlayer *player = m_env->getPlayer(name.c_str());
3182 SendPlayerFormspecPrepend(player->getPeerId());
3185 void Server::setIpBanned(const std::string &ip, const std::string &name)
3187 m_banmanager->add(ip, name);
3190 void Server::unsetIpBanned(const std::string &ip_or_name)
3192 m_banmanager->remove(ip_or_name);
3195 std::string Server::getBanDescription(const std::string &ip_or_name)
3197 return m_banmanager->getBanDescription(ip_or_name);
3200 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3202 // m_env will be NULL if the server is initializing
3206 if (m_admin_nick == name && !m_admin_nick.empty()) {
3207 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3210 RemotePlayer *player = m_env->getPlayer(name);
3215 if (player->getPeerId() == PEER_ID_INEXISTENT)
3218 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3221 bool Server::showFormspec(const char *playername, const std::string &formspec,
3222 const std::string &formname)
3224 // m_env will be NULL if the server is initializing
3228 RemotePlayer *player = m_env->getPlayer(playername);
3232 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3236 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3241 u32 id = player->addHud(form);
3243 SendHUDAdd(player->getPeerId(), id, form);
3248 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3252 HudElement* todel = player->removeHud(id);
3259 SendHUDRemove(player->getPeerId(), id);
3263 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3268 SendHUDChange(player->getPeerId(), id, stat, data);
3272 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3277 SendHUDSetFlags(player->getPeerId(), flags, mask);
3278 player->hud_flags &= ~mask;
3279 player->hud_flags |= flags;
3281 PlayerSAO* playersao = player->getPlayerSAO();
3286 m_script->player_event(playersao, "hud_changed");
3290 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3295 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3298 player->setHotbarItemcount(hotbar_itemcount);
3299 std::ostringstream os(std::ios::binary);
3300 writeS32(os, hotbar_itemcount);
3301 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3305 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3310 player->setHotbarImage(name);
3311 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3314 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3319 player->setHotbarSelectedImage(name);
3320 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3323 Address Server::getPeerAddress(session_t peer_id)
3325 // Note that this is only set after Init was received in Server::handleCommand_Init
3326 return getClient(peer_id, CS_Invalid)->getAddress();
3329 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3330 v2s32 animation_frames[4], f32 frame_speed)
3332 sanity_check(player);
3333 player->setLocalAnimations(animation_frames, frame_speed);
3334 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3337 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3339 sanity_check(player);
3340 player->eye_offset_first = first;
3341 player->eye_offset_third = third;
3342 SendEyeOffset(player->getPeerId(), first, third);
3345 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3347 sanity_check(player);
3348 player->setSky(params);
3349 SendSetSky(player->getPeerId(), params);
3352 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3354 sanity_check(player);
3355 player->setSun(params);
3356 SendSetSun(player->getPeerId(), params);
3359 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3361 sanity_check(player);
3362 player->setMoon(params);
3363 SendSetMoon(player->getPeerId(), params);
3366 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3368 sanity_check(player);
3369 player->setStars(params);
3370 SendSetStars(player->getPeerId(), params);
3373 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3375 sanity_check(player);
3376 player->setCloudParams(params);
3377 SendCloudParams(player->getPeerId(), params);
3380 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3383 sanity_check(player);
3384 player->overrideDayNightRatio(do_override, ratio);
3385 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3388 void Server::notifyPlayers(const std::wstring &msg)
3390 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3393 void Server::spawnParticle(const std::string &playername,
3394 const ParticleParameters &p)
3396 // m_env will be NULL if the server is initializing
3400 session_t peer_id = PEER_ID_INEXISTENT;
3402 if (!playername.empty()) {
3403 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3406 peer_id = player->getPeerId();
3407 proto_ver = player->protocol_version;
3410 SendSpawnParticle(peer_id, proto_ver, p);
3413 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3414 ServerActiveObject *attached, const std::string &playername)
3416 // m_env will be NULL if the server is initializing
3420 session_t peer_id = PEER_ID_INEXISTENT;
3422 if (!playername.empty()) {
3423 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3426 peer_id = player->getPeerId();
3427 proto_ver = player->protocol_version;
3430 u16 attached_id = attached ? attached->getId() : 0;
3433 if (attached_id == 0)
3434 id = m_env->addParticleSpawner(p.time);
3436 id = m_env->addParticleSpawner(p.time, attached_id);
3438 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3442 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3444 // m_env will be NULL if the server is initializing
3446 throw ServerError("Can't delete particle spawners during initialisation!");
3448 session_t peer_id = PEER_ID_INEXISTENT;
3449 if (!playername.empty()) {
3450 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3453 peer_id = player->getPeerId();
3456 m_env->deleteParticleSpawner(id);
3457 SendDeleteParticleSpawner(peer_id, id);
3460 bool Server::dynamicAddMedia(const std::string &filepath,
3461 std::vector<RemotePlayer*> &sent_to)
3463 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3464 if (m_media.find(filename) != m_media.end()) {
3465 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3466 << "\" already exists in media cache" << std::endl;
3470 // Load the file and add it to our media cache
3471 std::string filedata, raw_hash;
3472 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3476 // Push file to existing clients
3477 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3478 pkt << raw_hash << filename << (bool) true;
3479 pkt.putLongString(filedata);
3482 for (auto &pair : m_clients.getClientList()) {
3483 if (pair.second->getState() < CS_DefinitionsSent)
3485 if (pair.second->net_proto_version < 39)
3488 if (auto player = m_env->getPlayer(pair.second->peer_id))
3489 sent_to.emplace_back(player);
3491 FIXME: this is a very awful hack
3492 The network layer only guarantees ordered delivery inside a channel.
3493 Since the very next packet could be one that uses the media, we have
3494 to push the media over ALL channels to ensure it is processed before
3496 In practice this means we have to send it twice:
3498 - channel 0 (everything else: e.g. play_sound, object messages)
3500 m_clients.send(pair.second->peer_id, 1, &pkt, true);
3501 m_clients.send(pair.second->peer_id, 0, &pkt, true);
3508 // actions: time-reversed list
3509 // Return value: success/failure
3510 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3511 std::list<std::string> *log)
3513 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3514 ServerMap *map = (ServerMap*)(&m_env->getMap());
3516 // Fail if no actions to handle
3517 if (actions.empty()) {
3519 log->push_back("Nothing to do.");
3526 for (const RollbackAction &action : actions) {
3528 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3531 std::ostringstream os;
3532 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3533 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3535 log->push_back(os.str());
3537 std::ostringstream os;
3538 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3539 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3541 log->push_back(os.str());
3545 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3546 <<" failed"<<std::endl;
3548 // Call it done if less than half failed
3549 return num_failed <= num_tried/2;
3552 // IGameDef interface
3554 IItemDefManager *Server::getItemDefManager()
3559 const NodeDefManager *Server::getNodeDefManager()
3564 ICraftDefManager *Server::getCraftDefManager()
3569 u16 Server::allocateUnknownNodeId(const std::string &name)
3571 return m_nodedef->allocateDummy(name);
3574 IWritableItemDefManager *Server::getWritableItemDefManager()
3579 NodeDefManager *Server::getWritableNodeDefManager()
3584 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3589 const std::vector<ModSpec> & Server::getMods() const
3591 return m_modmgr->getMods();
3594 const ModSpec *Server::getModSpec(const std::string &modname) const
3596 return m_modmgr->getModSpec(modname);
3599 void Server::getModNames(std::vector<std::string> &modlist)
3601 m_modmgr->getModNames(modlist);
3604 std::string Server::getBuiltinLuaPath()
3606 return porting::path_share + DIR_DELIM + "builtin";
3609 std::string Server::getModStoragePath() const
3611 return m_path_world + DIR_DELIM + "mod_storage";
3614 v3f Server::findSpawnPos()
3616 ServerMap &map = m_env->getServerMap();
3618 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3619 return nodeposf * BS;
3621 bool is_good = false;
3622 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3623 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3625 // Try to find a good place a few times
3626 for (s32 i = 0; i < 4000 && !is_good; i++) {
3627 s32 range = MYMIN(1 + i, range_max);
3628 // We're going to try to throw the player to this position
3629 v2s16 nodepos2d = v2s16(
3630 -range + (myrand() % (range * 2)),
3631 -range + (myrand() % (range * 2)));
3632 // Get spawn level at point
3633 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3634 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3635 // signify an unsuitable spawn position, or if outside limits.
3636 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3637 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3640 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3641 // Consecutive empty nodes
3644 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3645 // avoid obstructions in already-generated mapblocks.
3646 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3647 // no obstructions, but mapgen decorations are generated after spawn so
3648 // the player may end up inside one.
3649 for (s32 i = 0; i < 8; i++) {
3650 v3s16 blockpos = getNodeBlockPos(nodepos);
3651 map.emergeBlock(blockpos, true);
3652 content_t c = map.getNode(nodepos).getContent();
3654 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3655 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3656 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3658 if (air_count >= 2) {
3659 // Spawn in lower empty node
3661 nodeposf = intToFloat(nodepos, BS);
3662 // Don't spawn the player outside map boundaries
3663 if (objectpos_over_limit(nodeposf))
3664 // Exit this loop, positions above are probably over limit
3667 // Good position found, cause an exit from main loop
3681 // No suitable spawn point found, return fallback 0,0,0
3682 return v3f(0.0f, 0.0f, 0.0f);
3685 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3687 if (delay == 0.0f) {
3688 // No delay, shutdown immediately
3689 m_shutdown_state.is_requested = true;
3690 // only print to the infostream, a chat message saying
3691 // "Server Shutting Down" is sent when the server destructs.
3692 infostream << "*** Immediate Server shutdown requested." << std::endl;
3693 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3694 // Negative delay, cancel shutdown if requested
3695 m_shutdown_state.reset();
3696 std::wstringstream ws;
3698 ws << L"*** Server shutdown canceled.";
3700 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3701 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3702 // m_shutdown_* are already handled, skip.
3704 } else if (delay > 0.0f) {
3705 // Positive delay, tell the clients when the server will shut down
3706 std::wstringstream ws;
3708 ws << L"*** Server shutting down in "
3709 << duration_to_string(myround(delay)).c_str()
3712 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3713 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3716 m_shutdown_state.trigger(delay, msg, reconnect);
3719 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3722 Try to get an existing player
3724 RemotePlayer *player = m_env->getPlayer(name);
3726 // If player is already connected, cancel
3727 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3728 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3733 If player with the wanted peer_id already exists, cancel.
3735 if (m_env->getPlayer(peer_id)) {
3736 infostream<<"emergePlayer(): Player with wrong name but same"
3737 " peer_id already exists"<<std::endl;
3742 player = new RemotePlayer(name, idef());
3745 bool newplayer = false;
3748 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3750 // Complete init with server parts
3751 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3752 player->protocol_version = proto_version;
3756 m_script->on_newplayer(playersao);
3762 bool Server::registerModStorage(ModMetadata *storage)
3764 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3765 errorstream << "Unable to register same mod storage twice. Storage name: "
3766 << storage->getModName() << std::endl;
3770 m_mod_storages[storage->getModName()] = storage;
3774 void Server::unregisterModStorage(const std::string &name)
3776 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3777 if (it != m_mod_storages.end()) {
3778 // Save unconditionaly on unregistration
3779 it->second->save(getModStoragePath());
3780 m_mod_storages.erase(name);
3784 void dedicated_server_loop(Server &server, bool &kill)
3786 verbosestream<<"dedicated_server_loop()"<<std::endl;
3788 IntervalLimiter m_profiler_interval;
3790 static thread_local const float steplen =
3791 g_settings->getFloat("dedicated_server_step");
3792 static thread_local const float profiler_print_interval =
3793 g_settings->getFloat("profiler_print_interval");
3796 * The dedicated server loop only does time-keeping (in Server::step) and
3797 * provides a way to main.cpp to kill the server externally (bool &kill).
3801 // This is kind of a hack but can be done like this
3802 // because server.step() is very light
3803 sleep_ms((int)(steplen*1000.0));
3804 server.step(steplen);
3806 if (server.isShutdownRequested() || kill)
3812 if (profiler_print_interval != 0) {
3813 if(m_profiler_interval.step(steplen, profiler_print_interval))
3815 infostream<<"Profiler:"<<std::endl;
3816 g_profiler->print(infostream);
3817 g_profiler->clear();
3822 infostream << "Dedicated server quitting" << std::endl;
3824 if (g_settings->getBool("server_announce"))
3825 ServerList::sendAnnounce(ServerList::AA_DELETE,
3826 server.m_bind_addr.getPort());
3835 bool Server::joinModChannel(const std::string &channel)
3837 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3838 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3841 bool Server::leaveModChannel(const std::string &channel)
3843 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3846 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3848 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3851 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3855 ModChannel* Server::getModChannel(const std::string &channel)
3857 return m_modchannel_mgr->getModChannel(channel);
3860 void Server::broadcastModChannelMessage(const std::string &channel,
3861 const std::string &message, session_t from_peer)
3863 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3867 if (message.size() > STRING_MAX_LEN) {
3868 warningstream << "ModChannel message too long, dropping before sending "
3869 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3870 << channel << ")" << std::endl;
3875 if (from_peer != PEER_ID_SERVER) {
3876 sender = getPlayerName(from_peer);
3879 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3880 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3881 resp_pkt << channel << sender << message;
3882 for (session_t peer_id : peers) {
3884 if (peer_id == from_peer)
3887 Send(peer_id, &resp_pkt);
3890 if (from_peer != PEER_ID_SERVER) {
3891 m_script->on_modchannel_message(channel, sender, message);
3895 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3897 if (lang_code.empty())
3900 auto it = server_translations.find(lang_code);
3901 if (it != server_translations.end())
3902 return &it->second; // Already loaded
3904 // [] will create an entry
3905 auto *translations = &server_translations[lang_code];
3907 std::string suffix = "." + lang_code + ".tr";
3908 for (const auto &i : m_media) {
3909 if (str_ends_with(i.first, suffix)) {
3911 if (fs::ReadFile(i.second.path, data)) {
3912 translations->loadTranslation(data);
3917 return translations;