3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "server/serveractiveobject.h"
41 #include "scripting_server.h"
46 #include "mapgen/mapgen.h"
47 #include "mapgen/mg_biome.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content/mods.h"
51 #include "modchannels.h"
52 #include "serverlist.h"
53 #include "util/string.h"
55 #include "util/serialize.h"
56 #include "util/thread.h"
57 #include "defaultsettings.h"
58 #include "server/mods.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
62 #include "database/database.h"
63 #include "chatmessage.h"
64 #include "chat_interface.h"
65 #include "remoteplayer.h"
66 #include "server/player_sao.h"
67 #include "server/serverinventorymgr.h"
68 #include "translation.h"
70 class ClientNotFoundException : public BaseException
73 ClientNotFoundException(const char *s):
78 class ServerThread : public Thread
82 ServerThread(Server *server):
93 void *ServerThread::run()
95 BEGIN_DEBUG_EXCEPTION_HANDLER
98 * The real business of the server happens on the ServerThread.
100 * AsyncRunStep() runs an actual server step as soon as enough time has
101 * passed (dedicated_server_loop keeps track of that).
102 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
103 * doesn't busy wait) and will process any remaining packets.
107 m_server->AsyncRunStep(true);
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError(e);
114 while (!stopRequested()) {
116 m_server->AsyncRunStep();
120 } catch (con::PeerNotFoundException &e) {
121 infostream<<"Server: PeerNotFoundException"<<std::endl;
122 } catch (ClientNotFoundException &e) {
123 } catch (con::ConnectionBindFailed &e) {
124 m_server->setAsyncFatalError(e.what());
125 } catch (LuaError &e) {
126 m_server->setAsyncFatalError(e);
130 END_DEBUG_EXCEPTION_HANDLER
135 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
137 if(pos_exists) *pos_exists = false;
142 if(pos_exists) *pos_exists = true;
147 ServerActiveObject *sao = env->getActiveObject(object);
150 if(pos_exists) *pos_exists = true;
151 return sao->getBasePosition(); }
156 void Server::ShutdownState::reset()
160 should_reconnect = false;
161 is_requested = false;
164 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
168 should_reconnect = reconnect;
171 void Server::ShutdownState::tick(float dtime, Server *server)
177 static const float shutdown_msg_times[] =
179 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
182 // Automated messages
183 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
184 for (float t : shutdown_msg_times) {
185 // If shutdown timer matches an automessage, shot it
186 if (m_timer > t && m_timer - dtime < t) {
187 std::wstring periodicMsg = getShutdownTimerMessage();
189 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
190 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
197 if (m_timer < 0.0f) {
203 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
205 std::wstringstream ws;
206 ws << L"*** Server shutting down in "
207 << duration_to_string(myround(m_timer)).c_str() << ".";
216 const std::string &path_world,
217 const SubgameSpec &gamespec,
218 bool simple_singleplayer_mode,
221 ChatInterface *iface,
222 std::string *on_shutdown_errmsg
224 m_bind_addr(bind_addr),
225 m_path_world(path_world),
226 m_gamespec(gamespec),
227 m_simple_singleplayer_mode(simple_singleplayer_mode),
228 m_dedicated(dedicated),
229 m_async_fatal_error(""),
230 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
233 m_bind_addr.isIPv6(),
235 m_itemdef(createItemDefManager()),
236 m_nodedef(createNodeDefManager()),
237 m_craftdef(createCraftDefManager()),
238 m_thread(new ServerThread(this)),
241 m_on_shutdown_errmsg(on_shutdown_errmsg),
242 m_modchannel_mgr(new ModChannelMgr())
244 if (m_path_world.empty())
245 throw ServerError("Supplied empty world path");
247 if (!gamespec.isValid())
248 throw ServerError("Supplied invalid gamespec");
251 m_metrics_backend = std::unique_ptr<MetricsBackend>(createPrometheusMetricsBackend());
253 m_metrics_backend = std::unique_ptr<MetricsBackend>(new MetricsBackend());
256 m_uptime_counter = m_metrics_backend->addCounter("minetest_core_server_uptime", "Server uptime (in seconds)");
257 m_player_gauge = m_metrics_backend->addGauge("minetest_core_player_number", "Number of connected players");
259 m_timeofday_gauge = m_metrics_backend->addGauge(
260 "minetest_core_timeofday",
261 "Time of day value");
263 m_lag_gauge = m_metrics_backend->addGauge(
264 "minetest_core_latency",
265 "Latency value (in seconds)");
267 m_aom_buffer_counter = m_metrics_backend->addCounter(
268 "minetest_core_aom_generated_count",
269 "Number of active object messages generated");
271 m_packet_recv_counter = m_metrics_backend->addCounter(
272 "minetest_core_server_packet_recv",
273 "Processable packets received");
275 m_packet_recv_processed_counter = m_metrics_backend->addCounter(
276 "minetest_core_server_packet_recv_processed",
277 "Valid received packets processed");
279 m_lag_gauge->set(g_settings->getFloat("dedicated_server_step"));
285 // Send shutdown message
286 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
287 L"*** Server shutting down"));
290 MutexAutoLock envlock(m_env_mutex);
292 infostream << "Server: Saving players" << std::endl;
293 m_env->saveLoadedPlayers();
295 infostream << "Server: Kicking players" << std::endl;
296 std::string kick_msg;
297 bool reconnect = false;
298 if (isShutdownRequested()) {
299 reconnect = m_shutdown_state.should_reconnect;
300 kick_msg = m_shutdown_state.message;
302 if (kick_msg.empty()) {
303 kick_msg = g_settings->get("kick_msg_shutdown");
305 m_env->saveLoadedPlayers(true);
306 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
307 kick_msg, reconnect);
310 actionstream << "Server: Shutting down" << std::endl;
312 // Do this before stopping the server in case mapgen callbacks need to access
313 // server-controlled resources (like ModStorages). Also do them before
314 // shutdown callbacks since they may modify state that is finalized in a
317 m_emerge->stopThreads();
320 MutexAutoLock envlock(m_env_mutex);
322 // Execute script shutdown hooks
323 infostream << "Executing shutdown hooks" << std::endl;
325 m_script->on_shutdown();
326 } catch (ModError &e) {
327 errorstream << "ModError: " << e.what() << std::endl;
328 if (m_on_shutdown_errmsg) {
329 if (m_on_shutdown_errmsg->empty()) {
330 *m_on_shutdown_errmsg = std::string("ModError: ") + e.what();
332 *m_on_shutdown_errmsg += std::string("\nModError: ") + e.what();
337 infostream << "Server: Saving environment metadata" << std::endl;
347 // Delete things in the reverse order of creation
356 // Deinitialize scripting
357 infostream << "Server: Deinitializing scripting" << std::endl;
359 delete m_startup_server_map; // if available
360 delete m_game_settings;
362 while (!m_unsent_map_edit_queue.empty()) {
363 delete m_unsent_map_edit_queue.front();
364 m_unsent_map_edit_queue.pop();
370 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
371 if (m_simple_singleplayer_mode)
372 infostream << " in simple singleplayer mode" << std::endl;
374 infostream << std::endl;
375 infostream << "- world: " << m_path_world << std::endl;
376 infostream << "- game: " << m_gamespec.path << std::endl;
378 m_game_settings = Settings::createLayer(SL_GAME);
380 // Create world if it doesn't exist
382 loadGameConfAndInitWorld(m_path_world,
383 fs::GetFilenameFromPath(m_path_world.c_str()),
385 } catch (const BaseException &e) {
386 throw ServerError(std::string("Failed to initialize world: ") + e.what());
389 // Create emerge manager
390 m_emerge = new EmergeManager(this);
392 // Create ban manager
393 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
394 m_banmanager = new BanManager(ban_path);
396 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
397 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
398 // complain about mods with unsatisfied dependencies
399 if (!m_modmgr->isConsistent()) {
400 m_modmgr->printUnsatisfiedModsError();
404 MutexAutoLock envlock(m_env_mutex);
406 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
407 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge, m_metrics_backend.get());
408 m_startup_server_map = servermap;
410 // Initialize scripting
411 infostream << "Server: Initializing Lua" << std::endl;
413 m_script = new ServerScripting(this);
415 // Must be created before mod loading because we have some inventory creation
416 m_inventory_mgr = std::unique_ptr<ServerInventoryManager>(new ServerInventoryManager());
418 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
420 m_modmgr->loadMods(m_script);
422 // Read Textures and calculate sha1 sums
425 // Apply item aliases in the node definition manager
426 m_nodedef->updateAliases(m_itemdef);
428 // Apply texture overrides from texturepack/override.txt
429 std::vector<std::string> paths;
430 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
431 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
432 for (const std::string &path : paths) {
433 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
434 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
435 m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
438 m_nodedef->setNodeRegistrationStatus(true);
440 // Perform pending node name resolutions
441 m_nodedef->runNodeResolveCallbacks();
443 // unmap node names in cross-references
444 m_nodedef->resolveCrossrefs();
446 // init the recipe hashes to speed up crafting
447 m_craftdef->initHashes(this);
449 // Initialize Environment
450 m_startup_server_map = nullptr; // Ownership moved to ServerEnvironment
451 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
453 m_inventory_mgr->setEnv(m_env);
454 m_clients.setEnv(m_env);
456 if (!servermap->settings_mgr.makeMapgenParams())
457 FATAL_ERROR("Couldn't create any mapgen type");
459 // Initialize mapgens
460 m_emerge->initMapgens(servermap->getMapgenParams());
462 if (g_settings->getBool("enable_rollback_recording")) {
463 // Create rollback manager
464 m_rollback = new RollbackManager(m_path_world, this);
467 // Give environment reference to scripting api
468 m_script->initializeEnvironment(m_env);
470 // Register us to receive map edit events
471 servermap->addEventReceiver(this);
475 // Those settings can be overwritten in world.mt, they are
476 // intended to be cached after environment loading.
477 m_liquid_transform_every = g_settings->getFloat("liquid_update");
478 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
479 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
480 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
487 infostream << "Starting server on " << m_bind_addr.serializeString()
488 << "..." << std::endl;
490 // Stop thread if already running
493 // Initialize connection
494 m_con->SetTimeoutMs(30);
495 m_con->Serve(m_bind_addr);
500 // ASCII art for the win!
502 << " .__ __ __ " << std::endl
503 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
504 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
505 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
506 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
507 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
508 actionstream << "World at [" << m_path_world << "]" << std::endl;
509 actionstream << "Server for gameid=\"" << m_gamespec.id
510 << "\" listening on " << m_bind_addr.serializeString() << ":"
511 << m_bind_addr.getPort() << "." << std::endl;
516 infostream<<"Server: Stopping and waiting threads"<<std::endl;
518 // Stop threads (set run=false first so both start stopping)
520 //m_emergethread.setRun(false);
522 //m_emergethread.stop();
524 infostream<<"Server: Threads stopped"<<std::endl;
527 void Server::step(float dtime)
533 MutexAutoLock lock(m_step_dtime_mutex);
534 m_step_dtime += dtime;
536 // Throw if fatal error occurred in thread
537 std::string async_err = m_async_fatal_error.get();
538 if (!async_err.empty()) {
539 if (!m_simple_singleplayer_mode) {
540 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
541 g_settings->get("kick_msg_crash"),
542 g_settings->getBool("ask_reconnect_on_crash"));
544 throw ServerError("AsyncErr: " + async_err);
548 void Server::AsyncRunStep(bool initial_step)
553 MutexAutoLock lock1(m_step_dtime_mutex);
554 dtime = m_step_dtime;
558 // Send blocks to clients
562 if((dtime < 0.001) && !initial_step)
565 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
568 MutexAutoLock lock1(m_step_dtime_mutex);
569 m_step_dtime -= dtime;
575 m_uptime_counter->increment(dtime);
580 Update time of day and overall game time
582 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
585 Send to clients at constant intervals
588 m_time_of_day_send_timer -= dtime;
589 if (m_time_of_day_send_timer < 0.0) {
590 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
591 u16 time = m_env->getTimeOfDay();
592 float time_speed = g_settings->getFloat("time_speed");
593 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
595 m_timeofday_gauge->set(time);
599 MutexAutoLock lock(m_env_mutex);
600 // Figure out and report maximum lag to environment
601 float max_lag = m_env->getMaxLagEstimate();
602 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
604 if(dtime > 0.1 && dtime > max_lag * 2.0)
605 infostream<<"Server: Maximum lag peaked to "<<dtime
609 m_env->reportMaxLagEstimate(max_lag);
614 static const float map_timer_and_unload_dtime = 2.92;
615 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
617 MutexAutoLock lock(m_env_mutex);
618 // Run Map's timers and unload unused data
619 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
620 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
621 g_settings->getFloat("server_unload_unused_data_timeout"),
626 Listen to the admin chat, if available
629 if (!m_admin_chat->command_queue.empty()) {
630 MutexAutoLock lock(m_env_mutex);
631 while (!m_admin_chat->command_queue.empty()) {
632 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
633 handleChatInterfaceEvent(evt);
637 m_admin_chat->outgoing_queue.push_back(
638 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
645 /* Transform liquids */
646 m_liquid_transform_timer += dtime;
647 if(m_liquid_transform_timer >= m_liquid_transform_every)
649 m_liquid_transform_timer -= m_liquid_transform_every;
651 MutexAutoLock lock(m_env_mutex);
653 ScopeProfiler sp(g_profiler, "Server: liquid transform");
655 std::map<v3s16, MapBlock*> modified_blocks;
656 m_env->getMap().transformLiquids(modified_blocks, m_env);
659 Set the modified blocks unsent for all the clients
661 if (!modified_blocks.empty()) {
662 SetBlocksNotSent(modified_blocks);
665 m_clients.step(dtime);
667 // increase/decrease lag gauge gradually
668 if (m_lag_gauge->get() > dtime) {
669 m_lag_gauge->decrement(dtime/100);
671 m_lag_gauge->increment(dtime/100);
675 float &counter = m_step_pending_dyn_media_timer;
677 if (counter >= 5.0f) {
678 stepPendingDynMediaCallbacks(counter);
685 // send masterserver announce
687 float &counter = m_masterserver_timer;
688 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
689 g_settings->getBool("server_announce")) {
690 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
691 ServerList::AA_START,
692 m_bind_addr.getPort(),
693 m_clients.getPlayerNames(),
694 m_uptime_counter->get(),
695 m_env->getGameTime(),
698 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
708 Check added and deleted active objects
711 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
712 MutexAutoLock envlock(m_env_mutex);
715 const RemoteClientMap &clients = m_clients.getClientList();
716 ScopeProfiler sp(g_profiler, "Server: update objects within range");
718 m_player_gauge->set(clients.size());
719 for (const auto &client_it : clients) {
720 RemoteClient *client = client_it.second;
722 if (client->getState() < CS_DefinitionsSent)
725 // This can happen if the client times out somehow
726 if (!m_env->getPlayer(client->peer_id))
729 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
733 SendActiveObjectRemoveAdd(client, playersao);
737 // Save mod storages if modified
738 m_mod_storage_save_timer -= dtime;
739 if (m_mod_storage_save_timer <= 0.0f) {
740 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
742 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
743 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
744 if (it->second->isModified()) {
745 it->second->save(getModStoragePath());
750 infostream << "Saved " << n << " modified mod storages." << std::endl;
758 MutexAutoLock envlock(m_env_mutex);
759 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
762 // Value = data sent by object
763 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
765 // Get active object messages from environment
766 ActiveObjectMessage aom(0);
769 if (!m_env->getActiveObjectMessage(&aom))
772 std::vector<ActiveObjectMessage>* message_list = nullptr;
773 auto n = buffered_messages.find(aom.id);
774 if (n == buffered_messages.end()) {
775 message_list = new std::vector<ActiveObjectMessage>;
776 buffered_messages[aom.id] = message_list;
778 message_list = n->second;
780 message_list->push_back(std::move(aom));
784 m_aom_buffer_counter->increment(aom_count);
787 const RemoteClientMap &clients = m_clients.getClientList();
788 // Route data to every client
789 std::string reliable_data, unreliable_data;
790 for (const auto &client_it : clients) {
791 reliable_data.clear();
792 unreliable_data.clear();
793 RemoteClient *client = client_it.second;
794 PlayerSAO *player = getPlayerSAO(client->peer_id);
795 // Go through all objects in message buffer
796 for (const auto &buffered_message : buffered_messages) {
797 // If object does not exist or is not known by client, skip it
798 u16 id = buffered_message.first;
799 ServerActiveObject *sao = m_env->getActiveObject(id);
800 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
803 // Get message list of object
804 std::vector<ActiveObjectMessage>* list = buffered_message.second;
805 // Go through every message
806 for (const ActiveObjectMessage &aom : *list) {
807 // Send position updates to players who do not see the attachment
808 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
809 if (sao->getId() == player->getId())
812 // Do not send position updates for attached players
813 // as long the parent is known to the client
814 ServerActiveObject *parent = sao->getParent();
815 if (parent && client->m_known_objects.find(parent->getId()) !=
816 client->m_known_objects.end())
820 // Add full new data to appropriate buffer
821 std::string &buffer = aom.reliable ? reliable_data : unreliable_data;
823 writeU16((u8*) idbuf, aom.id);
826 buffer.append(idbuf, sizeof(idbuf));
827 buffer.append(serializeString16(aom.datastring));
831 reliable_data and unreliable_data are now ready.
834 if (!reliable_data.empty()) {
835 SendActiveObjectMessages(client->peer_id, reliable_data);
838 if (!unreliable_data.empty()) {
839 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
844 // Clear buffered_messages
845 for (auto &buffered_message : buffered_messages) {
846 delete buffered_message.second;
851 Send queued-for-sending map edit events.
854 // We will be accessing the environment
855 MutexAutoLock lock(m_env_mutex);
857 // Don't send too many at a time
860 // Single change sending is disabled if queue size is not small
861 bool disable_single_change_sending = false;
862 if(m_unsent_map_edit_queue.size() >= 4)
863 disable_single_change_sending = true;
865 int event_count = m_unsent_map_edit_queue.size();
867 // We'll log the amount of each
870 std::list<v3s16> node_meta_updates;
872 while (!m_unsent_map_edit_queue.empty()) {
873 MapEditEvent* event = m_unsent_map_edit_queue.front();
874 m_unsent_map_edit_queue.pop();
876 // Players far away from the change are stored here.
877 // Instead of sending the changes, MapBlocks are set not sent
879 std::unordered_set<u16> far_players;
881 switch (event->type) {
884 prof.add("MEET_ADDNODE", 1);
885 sendAddNode(event->p, event->n, &far_players,
886 disable_single_change_sending ? 5 : 30,
887 event->type == MEET_ADDNODE);
889 case MEET_REMOVENODE:
890 prof.add("MEET_REMOVENODE", 1);
891 sendRemoveNode(event->p, &far_players,
892 disable_single_change_sending ? 5 : 30);
894 case MEET_BLOCK_NODE_METADATA_CHANGED: {
895 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
896 if (!event->is_private_change) {
897 // Don't send the change yet. Collect them to eliminate dupes.
898 node_meta_updates.remove(event->p);
899 node_meta_updates.push_back(event->p);
902 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
903 getNodeBlockPos(event->p))) {
904 block->raiseModified(MOD_STATE_WRITE_NEEDED,
905 MOD_REASON_REPORT_META_CHANGE);
910 prof.add("MEET_OTHER", 1);
911 for (const v3s16 &modified_block : event->modified_blocks) {
912 m_clients.markBlockposAsNotSent(modified_block);
916 prof.add("unknown", 1);
917 warningstream << "Server: Unknown MapEditEvent "
918 << ((u32)event->type) << std::endl;
923 Set blocks not sent to far players
925 if (!far_players.empty()) {
926 // Convert list format to that wanted by SetBlocksNotSent
927 std::map<v3s16, MapBlock*> modified_blocks2;
928 for (const v3s16 &modified_block : event->modified_blocks) {
929 modified_blocks2[modified_block] =
930 m_env->getMap().getBlockNoCreateNoEx(modified_block);
933 // Set blocks not sent
934 for (const u16 far_player : far_players) {
935 if (RemoteClient *client = getClient(far_player))
936 client->SetBlocksNotSent(modified_blocks2);
943 if (event_count >= 5) {
944 infostream << "Server: MapEditEvents:" << std::endl;
945 prof.print(infostream);
946 } else if (event_count != 0) {
947 verbosestream << "Server: MapEditEvents:" << std::endl;
948 prof.print(verbosestream);
951 // Send all metadata updates
952 if (node_meta_updates.size())
953 sendMetadataChanged(node_meta_updates);
957 Trigger emergethread (it somehow gets to a non-triggered but
958 bysy state sometimes)
961 float &counter = m_emergethread_trigger_timer;
963 if (counter >= 2.0) {
966 m_emerge->startThreads();
970 // Save map, players and auth stuff
972 float &counter = m_savemap_timer;
974 static thread_local const float save_interval =
975 g_settings->getFloat("server_map_save_interval");
976 if (counter >= save_interval) {
978 MutexAutoLock lock(m_env_mutex);
980 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
983 if (m_banmanager->isModified()) {
984 m_banmanager->save();
987 // Save changed parts of map
988 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
991 m_env->saveLoadedPlayers();
993 // Save environment metadata
998 m_shutdown_state.tick(dtime, this);
1001 void Server::Receive()
1011 In the first iteration *wait* for a packet, afterwards process
1012 all packets that are immediately available (no waiting).
1015 m_con->Receive(&pkt);
1018 if (!m_con->TryReceive(&pkt))
1022 peer_id = pkt.getPeerId();
1023 m_packet_recv_counter->increment();
1025 m_packet_recv_processed_counter->increment();
1026 } catch (const con::InvalidIncomingDataException &e) {
1027 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1028 << e.what() << std::endl;
1029 } catch (const SerializationError &e) {
1030 infostream << "Server::Receive(): SerializationError: what()="
1031 << e.what() << std::endl;
1032 } catch (const ClientStateError &e) {
1033 errorstream << "ProcessData: peer=" << peer_id << " what()="
1034 << e.what() << std::endl;
1035 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1036 L"Try reconnecting or updating your client");
1037 } catch (const con::PeerNotFoundException &e) {
1039 } catch (const con::NoIncomingDataException &e) {
1045 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1047 std::string playername;
1048 PlayerSAO *playersao = NULL;
1051 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1053 playername = client->getName();
1054 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1056 } catch (std::exception &e) {
1062 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1064 // If failed, cancel
1065 if (!playersao || !player) {
1066 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1067 actionstream << "Server: Failed to emerge player \"" << playername
1068 << "\" (player allocated to an another client)" << std::endl;
1069 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1070 L"name. If your client closed unexpectedly, try again in "
1073 errorstream << "Server: " << playername << ": Failed to emerge player"
1075 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1081 Send complete position information
1083 SendMovePlayer(peer_id);
1086 SendPlayerPrivileges(peer_id);
1088 // Send inventory formspec
1089 SendPlayerInventoryFormspec(peer_id);
1092 SendInventory(playersao, false);
1094 // Send HP or death screen
1095 if (playersao->isDead())
1096 SendDeathscreen(peer_id, false, v3f(0,0,0));
1098 SendPlayerHP(peer_id);
1101 SendPlayerBreath(playersao);
1107 Address addr = getPeerAddress(player->getPeerId());
1108 std::string ip_str = addr.serializeString();
1109 const std::vector<std::string> &names = m_clients.getPlayerNames();
1111 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1113 for (const std::string &name : names) {
1114 actionstream << name << " ";
1117 actionstream << player->getName() <<std::endl;
1122 inline void Server::handleCommand(NetworkPacket *pkt)
1124 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1125 (this->*opHandle.handler)(pkt);
1128 void Server::ProcessData(NetworkPacket *pkt)
1130 // Environment is locked first.
1131 MutexAutoLock envlock(m_env_mutex);
1133 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1134 u32 peer_id = pkt->getPeerId();
1137 Address address = getPeerAddress(peer_id);
1138 std::string addr_s = address.serializeString();
1140 if(m_banmanager->isIpBanned(addr_s)) {
1141 std::string ban_name = m_banmanager->getBanName(addr_s);
1142 infostream << "Server: A banned client tried to connect from "
1143 << addr_s << "; banned name was "
1144 << ban_name << std::endl;
1145 // This actually doesn't seem to transfer to the client
1146 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1147 + utf8_to_wide(ban_name));
1151 catch(con::PeerNotFoundException &e) {
1153 * no peer for this packet found
1154 * most common reason is peer timeout, e.g. peer didn't
1155 * respond for some time, your server was overloaded or
1158 infostream << "Server::ProcessData(): Canceling: peer "
1159 << peer_id << " not found" << std::endl;
1164 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1166 // Command must be handled into ToServerCommandHandler
1167 if (command >= TOSERVER_NUM_MSG_TYPES) {
1168 infostream << "Server: Ignoring unknown command "
1169 << command << std::endl;
1173 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1178 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1180 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1181 errorstream << "Server::ProcessData(): Cancelling: Peer"
1182 " serialization format invalid or not initialized."
1183 " Skipping incoming command=" << command << std::endl;
1187 /* Handle commands related to client startup */
1188 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1193 if (m_clients.getClientState(peer_id) < CS_Active) {
1194 if (command == TOSERVER_PLAYERPOS) return;
1196 errorstream << "Got packet command: " << command << " for peer id "
1197 << peer_id << " but client isn't active yet. Dropping packet "
1203 } catch (SendFailedException &e) {
1204 errorstream << "Server::ProcessData(): SendFailedException: "
1205 << "what=" << e.what()
1207 } catch (PacketError &e) {
1208 actionstream << "Server::ProcessData(): PacketError: "
1209 << "what=" << e.what()
1214 void Server::setTimeOfDay(u32 time)
1216 m_env->setTimeOfDay(time);
1217 m_time_of_day_send_timer = 0;
1220 void Server::onMapEditEvent(const MapEditEvent &event)
1222 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1225 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1228 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1230 std::vector<session_t> clients = m_clients.getClientIDs();
1232 // Set the modified blocks unsent for all the clients
1233 for (const session_t client_id : clients) {
1234 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1235 client->SetBlocksNotSent(block);
1240 void Server::peerAdded(con::Peer *peer)
1242 verbosestream<<"Server::peerAdded(): peer->id="
1243 <<peer->id<<std::endl;
1245 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1248 void Server::deletingPeer(con::Peer *peer, bool timeout)
1250 verbosestream<<"Server::deletingPeer(): peer->id="
1251 <<peer->id<<", timeout="<<timeout<<std::endl;
1253 m_clients.event(peer->id, CSE_Disconnect);
1254 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1257 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1259 *retval = m_con->getPeerStat(peer_id,type);
1260 return *retval != -1;
1263 bool Server::getClientInfo(session_t peer_id, ClientInfo &ret)
1266 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1273 ret.state = client->getState();
1274 ret.addr = client->getAddress();
1275 ret.uptime = client->uptime();
1276 ret.ser_vers = client->serialization_version;
1277 ret.prot_vers = client->net_proto_version;
1279 ret.major = client->getMajor();
1280 ret.minor = client->getMinor();
1281 ret.patch = client->getPatch();
1282 ret.vers_string = client->getFullVer();
1284 ret.lang_code = client->getLangCode();
1291 void Server::handlePeerChanges()
1293 while(!m_peer_change_queue.empty())
1295 con::PeerChange c = m_peer_change_queue.front();
1296 m_peer_change_queue.pop();
1298 verbosestream<<"Server: Handling peer change: "
1299 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1304 case con::PEER_ADDED:
1305 m_clients.CreateClient(c.peer_id);
1308 case con::PEER_REMOVED:
1309 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1313 FATAL_ERROR("Invalid peer change event received!");
1319 void Server::printToConsoleOnly(const std::string &text)
1322 m_admin_chat->outgoing_queue.push_back(
1323 new ChatEventChat("", utf8_to_wide(text)));
1325 std::cout << text << std::endl;
1329 void Server::Send(NetworkPacket *pkt)
1331 Send(pkt->getPeerId(), pkt);
1334 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1336 m_clients.send(peer_id,
1337 clientCommandFactoryTable[pkt->getCommand()].channel,
1339 clientCommandFactoryTable[pkt->getCommand()].reliable);
1342 void Server::SendMovement(session_t peer_id)
1344 std::ostringstream os(std::ios_base::binary);
1346 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1348 pkt << g_settings->getFloat("movement_acceleration_default");
1349 pkt << g_settings->getFloat("movement_acceleration_air");
1350 pkt << g_settings->getFloat("movement_acceleration_fast");
1351 pkt << g_settings->getFloat("movement_speed_walk");
1352 pkt << g_settings->getFloat("movement_speed_crouch");
1353 pkt << g_settings->getFloat("movement_speed_fast");
1354 pkt << g_settings->getFloat("movement_speed_climb");
1355 pkt << g_settings->getFloat("movement_speed_jump");
1356 pkt << g_settings->getFloat("movement_liquid_fluidity");
1357 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1358 pkt << g_settings->getFloat("movement_liquid_sink");
1359 pkt << g_settings->getFloat("movement_gravity");
1364 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1366 if (playersao->isImmortal())
1369 session_t peer_id = playersao->getPeerID();
1370 bool is_alive = !playersao->isDead();
1373 SendPlayerHP(peer_id);
1375 DiePlayer(peer_id, reason);
1378 void Server::SendHP(session_t peer_id, u16 hp)
1380 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1385 void Server::SendBreath(session_t peer_id, u16 breath)
1387 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1388 pkt << (u16) breath;
1392 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1393 const std::string &custom_reason, bool reconnect)
1395 assert(reason < SERVER_ACCESSDENIED_MAX);
1397 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1399 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1400 pkt << custom_reason;
1401 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1402 reason == SERVER_ACCESSDENIED_CRASH)
1403 pkt << custom_reason << (u8)reconnect;
1407 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1409 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1414 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1415 v3f camera_point_target)
1417 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1418 pkt << set_camera_point_target << camera_point_target;
1422 void Server::SendItemDef(session_t peer_id,
1423 IItemDefManager *itemdef, u16 protocol_version)
1425 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1429 u32 length of the next item
1430 zlib-compressed serialized ItemDefManager
1432 std::ostringstream tmp_os(std::ios::binary);
1433 itemdef->serialize(tmp_os, protocol_version);
1434 std::ostringstream tmp_os2(std::ios::binary);
1435 compressZlib(tmp_os.str(), tmp_os2);
1436 pkt.putLongString(tmp_os2.str());
1439 verbosestream << "Server: Sending item definitions to id(" << peer_id
1440 << "): size=" << pkt.getSize() << std::endl;
1445 void Server::SendNodeDef(session_t peer_id,
1446 const NodeDefManager *nodedef, u16 protocol_version)
1448 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1452 u32 length of the next item
1453 zlib-compressed serialized NodeDefManager
1455 std::ostringstream tmp_os(std::ios::binary);
1456 nodedef->serialize(tmp_os, protocol_version);
1457 std::ostringstream tmp_os2(std::ios::binary);
1458 compressZlib(tmp_os.str(), tmp_os2);
1460 pkt.putLongString(tmp_os2.str());
1463 verbosestream << "Server: Sending node definitions to id(" << peer_id
1464 << "): size=" << pkt.getSize() << std::endl;
1470 Non-static send methods
1473 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1475 RemotePlayer *player = sao->getPlayer();
1477 // Do not send new format to old clients
1478 incremental &= player->protocol_version >= 38;
1480 UpdateCrafting(player);
1486 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1488 std::ostringstream os(std::ios::binary);
1489 sao->getInventory()->serialize(os, incremental);
1490 sao->getInventory()->setModified(false);
1491 player->setModified(true);
1493 const std::string &s = os.str();
1494 pkt.putRawString(s.c_str(), s.size());
1498 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1500 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1502 u8 type = message.type;
1503 pkt << version << type << message.sender << message.message
1504 << static_cast<u64>(message.timestamp);
1506 if (peer_id != PEER_ID_INEXISTENT) {
1507 RemotePlayer *player = m_env->getPlayer(peer_id);
1513 m_clients.sendToAll(&pkt);
1517 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1518 const std::string &formname)
1520 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1521 if (formspec.empty()){
1522 //the client should close the formspec
1523 //but make sure there wasn't another one open in meantime
1524 const auto it = m_formspec_state_data.find(peer_id);
1525 if (it != m_formspec_state_data.end() && it->second == formname) {
1526 m_formspec_state_data.erase(peer_id);
1528 pkt.putLongString("");
1530 m_formspec_state_data[peer_id] = formname;
1531 pkt.putLongString(formspec);
1538 // Spawns a particle on peer with peer_id
1539 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1540 const ParticleParameters &p)
1542 static thread_local const float radius =
1543 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1545 if (peer_id == PEER_ID_INEXISTENT) {
1546 std::vector<session_t> clients = m_clients.getClientIDs();
1547 const v3f pos = p.pos * BS;
1548 const float radius_sq = radius * radius;
1550 for (const session_t client_id : clients) {
1551 RemotePlayer *player = m_env->getPlayer(client_id);
1555 PlayerSAO *sao = player->getPlayerSAO();
1559 // Do not send to distant clients
1560 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1563 SendSpawnParticle(client_id, player->protocol_version, p);
1567 assert(protocol_version != 0);
1569 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1572 // NetworkPacket and iostreams are incompatible...
1573 std::ostringstream oss(std::ios_base::binary);
1574 p.serialize(oss, protocol_version);
1575 pkt.putRawString(oss.str());
1581 // Adds a ParticleSpawner on peer with peer_id
1582 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1583 const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1585 static thread_local const float radius =
1586 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1588 if (peer_id == PEER_ID_INEXISTENT) {
1589 std::vector<session_t> clients = m_clients.getClientIDs();
1590 const v3f pos = (p.minpos + p.maxpos) / 2.0f * BS;
1591 const float radius_sq = radius * radius;
1592 /* Don't send short-lived spawners to distant players.
1593 * This could be replaced with proper tracking at some point. */
1594 const bool distance_check = !attached_id && p.time <= 1.0f;
1596 for (const session_t client_id : clients) {
1597 RemotePlayer *player = m_env->getPlayer(client_id);
1601 if (distance_check) {
1602 PlayerSAO *sao = player->getPlayerSAO();
1605 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1609 SendAddParticleSpawner(client_id, player->protocol_version,
1610 p, attached_id, id);
1614 assert(protocol_version != 0);
1616 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1618 pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
1619 << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
1620 << p.minsize << p.maxsize << p.collisiondetection;
1622 pkt.putLongString(p.texture);
1624 pkt << id << p.vertical << p.collision_removal << attached_id;
1626 std::ostringstream os(std::ios_base::binary);
1627 p.animation.serialize(os, protocol_version);
1628 pkt.putRawString(os.str());
1630 pkt << p.glow << p.object_collision;
1631 pkt << p.node.param0 << p.node.param2 << p.node_tile;
1636 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1638 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1642 if (peer_id != PEER_ID_INEXISTENT)
1645 m_clients.sendToAll(&pkt);
1649 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1651 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1653 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1654 << form->text << form->number << form->item << form->dir
1655 << form->align << form->offset << form->world_pos << form->size
1656 << form->z_index << form->text2 << form->style;
1661 void Server::SendHUDRemove(session_t peer_id, u32 id)
1663 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1668 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1670 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1671 pkt << id << (u8) stat;
1675 case HUD_STAT_SCALE:
1676 case HUD_STAT_ALIGN:
1677 case HUD_STAT_OFFSET:
1678 pkt << *(v2f *) value;
1682 case HUD_STAT_TEXT2:
1683 pkt << *(std::string *) value;
1685 case HUD_STAT_WORLD_POS:
1686 pkt << *(v3f *) value;
1689 pkt << *(v2s32 *) value;
1691 default: // all other types
1692 pkt << *(u32 *) value;
1699 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1701 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1703 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1705 pkt << flags << mask;
1710 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1712 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1713 pkt << param << value;
1717 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1719 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1721 // Handle prior clients here
1722 if (m_clients.getProtocolVersion(peer_id) < 39) {
1723 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1725 for (const std::string& texture : params.textures)
1728 pkt << params.clouds;
1729 } else { // Handle current clients and future clients
1730 pkt << params.bgcolor << params.type
1731 << params.clouds << params.fog_sun_tint
1732 << params.fog_moon_tint << params.fog_tint_type;
1734 if (params.type == "skybox") {
1735 pkt << (u16) params.textures.size();
1736 for (const std::string &texture : params.textures)
1738 } else if (params.type == "regular") {
1739 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1740 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1741 << params.sky_color.night_sky << params.sky_color.night_horizon
1742 << params.sky_color.indoors;
1749 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1751 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1752 pkt << params.visible << params.texture
1753 << params.tonemap << params.sunrise
1754 << params.sunrise_visible << params.scale;
1758 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1760 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1762 pkt << params.visible << params.texture
1763 << params.tonemap << params.scale;
1767 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1769 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1771 pkt << params.visible << params.count
1772 << params.starcolor << params.scale;
1777 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1779 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1780 pkt << params.density << params.color_bright << params.color_ambient
1781 << params.height << params.thickness << params.speed;
1785 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1788 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1791 pkt << do_override << (u16) (ratio * 65535);
1796 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1798 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1799 pkt << time << time_speed;
1801 if (peer_id == PEER_ID_INEXISTENT) {
1802 m_clients.sendToAll(&pkt);
1809 void Server::SendPlayerHP(session_t peer_id)
1811 PlayerSAO *playersao = getPlayerSAO(peer_id);
1814 SendHP(peer_id, playersao->getHP());
1815 m_script->player_event(playersao,"health_changed");
1817 // Send to other clients
1818 playersao->sendPunchCommand();
1821 void Server::SendPlayerBreath(PlayerSAO *sao)
1825 m_script->player_event(sao, "breath_changed");
1826 SendBreath(sao->getPeerID(), sao->getBreath());
1829 void Server::SendMovePlayer(session_t peer_id)
1831 RemotePlayer *player = m_env->getPlayer(peer_id);
1833 PlayerSAO *sao = player->getPlayerSAO();
1836 // Send attachment updates instantly to the client prior updating position
1837 sao->sendOutdatedData();
1839 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1840 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1843 v3f pos = sao->getBasePosition();
1844 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1845 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1846 << " pitch=" << sao->getLookPitch()
1847 << " yaw=" << sao->getRotation().Y
1854 void Server::SendPlayerFov(session_t peer_id)
1856 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1858 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1859 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1864 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1865 f32 animation_speed)
1867 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1870 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1871 << animation_frames[3] << animation_speed;
1876 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1878 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1879 pkt << first << third;
1883 void Server::SendPlayerPrivileges(session_t peer_id)
1885 RemotePlayer *player = m_env->getPlayer(peer_id);
1887 if(player->getPeerId() == PEER_ID_INEXISTENT)
1890 std::set<std::string> privs;
1891 m_script->getAuth(player->getName(), NULL, &privs);
1893 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1894 pkt << (u16) privs.size();
1896 for (const std::string &priv : privs) {
1903 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1905 RemotePlayer *player = m_env->getPlayer(peer_id);
1907 if (player->getPeerId() == PEER_ID_INEXISTENT)
1910 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1911 pkt.putLongString(player->inventory_formspec);
1916 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1918 RemotePlayer *player = m_env->getPlayer(peer_id);
1920 if (player->getPeerId() == PEER_ID_INEXISTENT)
1923 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1924 pkt << player->formspec_prepend;
1928 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1930 // Radius inside which objects are active
1931 static thread_local const s16 radius =
1932 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1934 // Radius inside which players are active
1935 static thread_local const bool is_transfer_limited =
1936 g_settings->exists("unlimited_player_transfer_distance") &&
1937 !g_settings->getBool("unlimited_player_transfer_distance");
1939 static thread_local const s16 player_transfer_dist =
1940 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1942 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1943 radius : player_transfer_dist;
1945 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1949 std::queue<u16> removed_objects, added_objects;
1950 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1951 client->m_known_objects, removed_objects);
1952 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1953 client->m_known_objects, added_objects);
1955 int removed_count = removed_objects.size();
1956 int added_count = added_objects.size();
1958 if (removed_objects.empty() && added_objects.empty())
1964 // Handle removed objects
1965 writeU16((u8*)buf, removed_objects.size());
1966 data.append(buf, 2);
1967 while (!removed_objects.empty()) {
1969 u16 id = removed_objects.front();
1970 ServerActiveObject* obj = m_env->getActiveObject(id);
1972 // Add to data buffer for sending
1973 writeU16((u8*)buf, id);
1974 data.append(buf, 2);
1976 // Remove from known objects
1977 client->m_known_objects.erase(id);
1979 if (obj && obj->m_known_by_count > 0)
1980 obj->m_known_by_count--;
1982 removed_objects.pop();
1985 // Handle added objects
1986 writeU16((u8*)buf, added_objects.size());
1987 data.append(buf, 2);
1988 while (!added_objects.empty()) {
1990 u16 id = added_objects.front();
1991 ServerActiveObject *obj = m_env->getActiveObject(id);
1992 added_objects.pop();
1995 warningstream << FUNCTION_NAME << ": NULL object id="
1996 << (int)id << std::endl;
2001 u8 type = obj->getSendType();
2003 // Add to data buffer for sending
2004 writeU16((u8*)buf, id);
2005 data.append(buf, 2);
2006 writeU8((u8*)buf, type);
2007 data.append(buf, 1);
2009 data.append(serializeString32(
2010 obj->getClientInitializationData(client->net_proto_version)));
2012 // Add to known objects
2013 client->m_known_objects.insert(id);
2015 obj->m_known_by_count++;
2018 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2019 pkt.putRawString(data.c_str(), data.size());
2022 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2023 << removed_count << " removed, " << added_count << " added, "
2024 << "packet size is " << pkt.getSize() << std::endl;
2027 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2030 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2031 datas.size(), peer_id);
2033 pkt.putRawString(datas.c_str(), datas.size());
2035 m_clients.send(pkt.getPeerId(),
2036 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2040 void Server::SendCSMRestrictionFlags(session_t peer_id)
2042 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2043 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2044 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2048 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2050 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2055 inline s32 Server::nextSoundId()
2057 s32 ret = m_next_sound_id;
2058 if (m_next_sound_id == INT32_MAX)
2059 m_next_sound_id = 0; // signed overflow is undefined
2065 s32 Server::playSound(const SimpleSoundSpec &spec,
2066 const ServerSoundParams ¶ms, bool ephemeral)
2068 // Find out initial position of sound
2069 bool pos_exists = false;
2070 v3f pos = params.getPos(m_env, &pos_exists);
2071 // If position is not found while it should be, cancel sound
2072 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2075 // Filter destination clients
2076 std::vector<session_t> dst_clients;
2077 if (!params.to_player.empty()) {
2078 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2080 infostream<<"Server::playSound: Player \""<<params.to_player
2081 <<"\" not found"<<std::endl;
2084 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2085 infostream<<"Server::playSound: Player \""<<params.to_player
2086 <<"\" not connected"<<std::endl;
2089 dst_clients.push_back(player->getPeerId());
2091 std::vector<session_t> clients = m_clients.getClientIDs();
2093 for (const session_t client_id : clients) {
2094 RemotePlayer *player = m_env->getPlayer(client_id);
2097 if (!params.exclude_player.empty() &&
2098 params.exclude_player == player->getName())
2101 PlayerSAO *sao = player->getPlayerSAO();
2106 if(sao->getBasePosition().getDistanceFrom(pos) >
2107 params.max_hear_distance)
2110 dst_clients.push_back(client_id);
2114 if(dst_clients.empty())
2119 ServerPlayingSound *psound = nullptr;
2121 id = -1; // old clients will still use this, so pick a reserved ID
2124 // The sound will exist as a reference in m_playing_sounds
2125 m_playing_sounds[id] = ServerPlayingSound();
2126 psound = &m_playing_sounds[id];
2127 psound->params = params;
2128 psound->spec = spec;
2131 float gain = params.gain * spec.gain;
2132 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2133 pkt << id << spec.name << gain
2134 << (u8) params.type << pos << params.object
2135 << params.loop << params.fade << params.pitch
2138 bool as_reliable = !ephemeral;
2140 for (const u16 dst_client : dst_clients) {
2142 psound->clients.insert(dst_client);
2143 m_clients.send(dst_client, 0, &pkt, as_reliable);
2147 void Server::stopSound(s32 handle)
2149 // Get sound reference
2150 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2151 m_playing_sounds.find(handle);
2152 if (i == m_playing_sounds.end())
2154 ServerPlayingSound &psound = i->second;
2156 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2159 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2160 si != psound.clients.end(); ++si) {
2162 m_clients.send(*si, 0, &pkt, true);
2164 // Remove sound reference
2165 m_playing_sounds.erase(i);
2168 void Server::fadeSound(s32 handle, float step, float gain)
2170 // Get sound reference
2171 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2172 m_playing_sounds.find(handle);
2173 if (i == m_playing_sounds.end())
2176 ServerPlayingSound &psound = i->second;
2177 psound.params.gain = gain;
2179 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2180 pkt << handle << step << gain;
2182 // Backwards compability
2183 bool play_sound = gain > 0;
2184 ServerPlayingSound compat_psound = psound;
2185 compat_psound.clients.clear();
2187 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2188 compat_pkt << handle;
2190 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2191 it != psound.clients.end();) {
2192 if (m_clients.getProtocolVersion(*it) >= 32) {
2194 m_clients.send(*it, 0, &pkt, true);
2197 compat_psound.clients.insert(*it);
2199 m_clients.send(*it, 0, &compat_pkt, true);
2200 psound.clients.erase(it++);
2204 // Remove sound reference
2205 if (!play_sound || psound.clients.empty())
2206 m_playing_sounds.erase(i);
2208 if (play_sound && !compat_psound.clients.empty()) {
2209 // Play new sound volume on older clients
2210 playSound(compat_psound.spec, compat_psound.params);
2214 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2217 float maxd = far_d_nodes * BS;
2218 v3f p_f = intToFloat(p, BS);
2219 v3s16 block_pos = getNodeBlockPos(p);
2221 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2224 std::vector<session_t> clients = m_clients.getClientIDs();
2227 for (session_t client_id : clients) {
2228 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2232 RemotePlayer *player = m_env->getPlayer(client_id);
2233 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2235 // If player is far away, only set modified blocks not sent
2236 if (!client->isBlockSent(block_pos) || (sao &&
2237 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2239 far_players->emplace(client_id);
2241 client->SetBlockNotSent(block_pos);
2246 m_clients.send(client_id, 0, &pkt, true);
2252 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2253 float far_d_nodes, bool remove_metadata)
2255 float maxd = far_d_nodes * BS;
2256 v3f p_f = intToFloat(p, BS);
2257 v3s16 block_pos = getNodeBlockPos(p);
2259 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2260 pkt << p << n.param0 << n.param1 << n.param2
2261 << (u8) (remove_metadata ? 0 : 1);
2263 std::vector<session_t> clients = m_clients.getClientIDs();
2266 for (session_t client_id : clients) {
2267 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2271 RemotePlayer *player = m_env->getPlayer(client_id);
2272 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2274 // If player is far away, only set modified blocks not sent
2275 if (!client->isBlockSent(block_pos) || (sao &&
2276 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2278 far_players->emplace(client_id);
2280 client->SetBlockNotSent(block_pos);
2285 m_clients.send(client_id, 0, &pkt, true);
2291 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2293 float maxd = far_d_nodes * BS;
2294 NodeMetadataList meta_updates_list(false);
2295 std::vector<session_t> clients = m_clients.getClientIDs();
2299 for (session_t i : clients) {
2300 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2304 ServerActiveObject *player = m_env->getActiveObject(i);
2305 v3f player_pos = player ? player->getBasePosition() : v3f();
2307 for (const v3s16 &pos : meta_updates) {
2308 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2313 v3s16 block_pos = getNodeBlockPos(pos);
2314 if (!client->isBlockSent(block_pos) || (player &&
2315 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2316 client->SetBlockNotSent(block_pos);
2320 // Add the change to send list
2321 meta_updates_list.set(pos, meta);
2323 if (meta_updates_list.size() == 0)
2326 // Send the meta changes
2327 std::ostringstream os(std::ios::binary);
2328 meta_updates_list.serialize(os, client->serialization_version, false, true, true);
2329 std::ostringstream oss(std::ios::binary);
2330 compressZlib(os.str(), oss);
2332 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2333 pkt.putLongString(oss.str());
2334 m_clients.send(i, 0, &pkt, true);
2336 meta_updates_list.clear();
2342 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2343 u16 net_proto_version)
2346 Create a packet with the block in the right format
2348 thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
2349 std::ostringstream os(std::ios_base::binary);
2350 block->serialize(os, ver, false, net_compression_level);
2351 block->serializeNetworkSpecific(os);
2352 std::string s = os.str();
2354 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + s.size(), peer_id);
2356 pkt << block->getPos();
2357 pkt.putRawString(s.c_str(), s.size());
2361 void Server::SendBlocks(float dtime)
2363 MutexAutoLock envlock(m_env_mutex);
2364 //TODO check if one big lock could be faster then multiple small ones
2366 std::vector<PrioritySortedBlockTransfer> queue;
2368 u32 total_sending = 0;
2371 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2373 std::vector<session_t> clients = m_clients.getClientIDs();
2376 for (const session_t client_id : clients) {
2377 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2382 total_sending += client->getSendingCount();
2383 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2389 // Lowest priority number comes first.
2390 // Lowest is most important.
2391 std::sort(queue.begin(), queue.end());
2395 // Maximal total count calculation
2396 // The per-client block sends is halved with the maximal online users
2397 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2398 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2400 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2401 Map &map = m_env->getMap();
2403 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2404 if (total_sending >= max_blocks_to_send)
2407 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2411 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2416 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2417 client->net_proto_version);
2419 client->SentBlock(block_to_send.pos);
2425 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2427 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2432 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2433 if (!client || client->isBlockSent(blockpos)) {
2437 SendBlockNoLock(peer_id, block, client->serialization_version,
2438 client->net_proto_version);
2444 bool Server::addMediaFile(const std::string &filename,
2445 const std::string &filepath, std::string *filedata_to,
2446 std::string *digest_to)
2448 // If name contains illegal characters, ignore the file
2449 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2450 infostream << "Server: ignoring illegal file name: \""
2451 << filename << "\"" << std::endl;
2454 // If name is not in a supported format, ignore it
2455 const char *supported_ext[] = {
2456 ".png", ".jpg", ".bmp", ".tga",
2458 ".x", ".b3d", ".obj",
2459 // Custom translation file format
2463 if (removeStringEnd(filename, supported_ext).empty()) {
2464 infostream << "Server: ignoring unsupported file extension: \""
2465 << filename << "\"" << std::endl;
2468 // Ok, attempt to load the file and add to cache
2471 std::string filedata;
2472 if (!fs::ReadFile(filepath, filedata)) {
2473 errorstream << "Server::addMediaFile(): Failed to open \""
2474 << filename << "\" for reading" << std::endl;
2478 if (filedata.empty()) {
2479 errorstream << "Server::addMediaFile(): Empty file \""
2480 << filepath << "\"" << std::endl;
2485 sha1.addBytes(filedata.c_str(), filedata.length());
2487 unsigned char *digest = sha1.getDigest();
2488 std::string sha1_base64 = base64_encode(digest, 20);
2489 std::string sha1_hex = hex_encode((char*) digest, 20);
2491 *digest_to = std::string((char*) digest, 20);
2495 m_media[filename] = MediaInfo(filepath, sha1_base64);
2496 verbosestream << "Server: " << sha1_hex << " is " << filename
2500 *filedata_to = std::move(filedata);
2504 void Server::fillMediaCache()
2506 infostream << "Server: Calculating media file checksums" << std::endl;
2508 // Collect all media file paths
2509 std::vector<std::string> paths;
2511 // ordered in descending priority
2512 paths.push_back(getBuiltinLuaPath() + DIR_DELIM + "locale");
2513 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2514 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2515 m_modmgr->getModsMediaPaths(paths);
2517 // Collect media file information from paths into cache
2518 for (const std::string &mediapath : paths) {
2519 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2520 for (const fs::DirListNode &dln : dirlist) {
2521 if (dln.dir) // Ignore dirs (already in paths)
2524 const std::string &filename = dln.name;
2525 if (m_media.find(filename) != m_media.end()) // Do not override
2528 std::string filepath = mediapath;
2529 filepath.append(DIR_DELIM).append(filename);
2530 addMediaFile(filename, filepath);
2534 infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2537 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2540 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2543 std::string lang_suffix;
2544 lang_suffix.append(".").append(lang_code).append(".tr");
2545 for (const auto &i : m_media) {
2546 if (i.second.no_announce)
2548 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2555 for (const auto &i : m_media) {
2556 if (i.second.no_announce)
2558 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2560 pkt << i.first << i.second.sha1_digest;
2563 pkt << g_settings->get("remote_media");
2566 verbosestream << "Server: Announcing files to id(" << peer_id
2567 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2570 struct SendableMedia
2576 SendableMedia(const std::string &name, const std::string &path,
2577 std::string &&data):
2578 name(name), path(path), data(std::move(data))
2582 void Server::sendRequestedMedia(session_t peer_id,
2583 const std::vector<std::string> &tosend)
2585 verbosestream<<"Server::sendRequestedMedia(): "
2586 <<"Sending files to client"<<std::endl;
2590 // Put 5kB in one bunch (this is not accurate)
2591 u32 bytes_per_bunch = 5000;
2593 std::vector< std::vector<SendableMedia> > file_bunches;
2594 file_bunches.emplace_back();
2596 u32 file_size_bunch_total = 0;
2598 for (const std::string &name : tosend) {
2599 if (m_media.find(name) == m_media.end()) {
2600 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2601 <<"unknown file \""<<(name)<<"\""<<std::endl;
2605 const auto &m = m_media[name];
2609 if (!fs::ReadFile(m.path, data)) {
2610 errorstream << "Server::sendRequestedMedia(): Failed to read \""
2611 << name << "\"" << std::endl;
2614 file_size_bunch_total += data.size();
2617 file_bunches.back().emplace_back(name, m.path, std::move(data));
2619 // Start next bunch if got enough data
2620 if(file_size_bunch_total >= bytes_per_bunch) {
2621 file_bunches.emplace_back();
2622 file_size_bunch_total = 0;
2627 /* Create and send packets */
2629 u16 num_bunches = file_bunches.size();
2630 for (u16 i = 0; i < num_bunches; i++) {
2633 u16 total number of texture bunches
2634 u16 index of this bunch
2635 u32 number of files in this bunch
2644 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2645 pkt << num_bunches << i << (u32) file_bunches[i].size();
2647 for (const SendableMedia &j : file_bunches[i]) {
2649 pkt.putLongString(j.data);
2652 verbosestream << "Server::sendRequestedMedia(): bunch "
2653 << i << "/" << num_bunches
2654 << " files=" << file_bunches[i].size()
2655 << " size=" << pkt.getSize() << std::endl;
2660 void Server::stepPendingDynMediaCallbacks(float dtime)
2662 MutexAutoLock lock(m_env_mutex);
2664 for (auto it = m_pending_dyn_media.begin(); it != m_pending_dyn_media.end();) {
2665 it->second.expiry_timer -= dtime;
2666 bool del = it->second.waiting_players.empty() || it->second.expiry_timer < 0;
2673 const auto &name = it->second.filename;
2674 if (!name.empty()) {
2675 assert(m_media.count(name));
2676 // if no_announce isn't set we're definitely deleting the wrong file!
2677 sanity_check(m_media[name].no_announce);
2679 fs::DeleteSingleFileOrEmptyDirectory(m_media[name].path);
2680 m_media.erase(name);
2682 getScriptIface()->freeDynamicMediaCallback(it->first);
2683 it = m_pending_dyn_media.erase(it);
2687 void Server::SendMinimapModes(session_t peer_id,
2688 std::vector<MinimapMode> &modes, size_t wanted_mode)
2690 RemotePlayer *player = m_env->getPlayer(peer_id);
2692 if (player->getPeerId() == PEER_ID_INEXISTENT)
2695 NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2696 pkt << (u16)modes.size() << (u16)wanted_mode;
2698 for (auto &mode : modes)
2699 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2704 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2706 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2710 pkt << false; // Remove inventory
2712 pkt << true; // Update inventory
2714 // Serialization & NetworkPacket isn't a love story
2715 std::ostringstream os(std::ios_base::binary);
2716 inventory->serialize(os);
2717 inventory->setModified(false);
2719 const std::string &os_str = os.str();
2720 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2721 pkt.putRawString(os_str);
2724 if (peer_id == PEER_ID_INEXISTENT)
2725 m_clients.sendToAll(&pkt);
2730 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2732 // Lookup player name, to filter detached inventories just after
2733 std::string peer_name;
2734 if (peer_id != PEER_ID_INEXISTENT) {
2735 peer_name = getClient(peer_id, CS_Created)->getName();
2738 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2739 sendDetachedInventory(inv, name, peer_id);
2742 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2749 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2751 PlayerSAO *playersao = getPlayerSAO(peer_id);
2754 infostream << "Server::DiePlayer(): Player "
2755 << playersao->getPlayer()->getName()
2756 << " dies" << std::endl;
2758 playersao->setHP(0, reason);
2759 playersao->clearParentAttachment();
2761 // Trigger scripted stuff
2762 m_script->on_dieplayer(playersao, reason);
2764 SendPlayerHP(peer_id);
2765 SendDeathscreen(peer_id, false, v3f(0,0,0));
2768 void Server::RespawnPlayer(session_t peer_id)
2770 PlayerSAO *playersao = getPlayerSAO(peer_id);
2773 infostream << "Server::RespawnPlayer(): Player "
2774 << playersao->getPlayer()->getName()
2775 << " respawns" << std::endl;
2777 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2778 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2779 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2781 bool repositioned = m_script->on_respawnplayer(playersao);
2782 if (!repositioned) {
2783 // setPos will send the new position to client
2784 playersao->setPos(findSpawnPos());
2787 SendPlayerHP(peer_id);
2791 void Server::DenySudoAccess(session_t peer_id)
2793 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2798 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2799 const std::string &str_reason, bool reconnect)
2801 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2803 m_clients.event(peer_id, CSE_SetDenied);
2804 DisconnectPeer(peer_id);
2808 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2809 const std::string &custom_reason)
2811 SendAccessDenied(peer_id, reason, custom_reason);
2812 m_clients.event(peer_id, CSE_SetDenied);
2813 DisconnectPeer(peer_id);
2816 // 13/03/15: remove this function when protocol version 25 will become
2817 // the minimum version for MT users, maybe in 1 year
2818 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2820 SendAccessDenied_Legacy(peer_id, reason);
2821 m_clients.event(peer_id, CSE_SetDenied);
2822 DisconnectPeer(peer_id);
2825 void Server::DisconnectPeer(session_t peer_id)
2827 m_modchannel_mgr->leaveAllChannels(peer_id);
2828 m_con->DisconnectPeer(peer_id);
2831 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2834 RemoteClient* client = getClient(peer_id, CS_Invalid);
2836 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2838 // Right now, the auth mechs don't change between login and sudo mode.
2839 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2840 client->allowed_sudo_mechs = sudo_auth_mechs;
2842 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2843 << g_settings->getFloat("dedicated_server_step")
2847 m_clients.event(peer_id, CSE_AuthAccept);
2849 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2851 // We only support SRP right now
2852 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2854 resp_pkt << sudo_auth_mechs;
2856 m_clients.event(peer_id, CSE_SudoSuccess);
2860 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2862 std::wstring message;
2865 Clear references to playing sounds
2867 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2868 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2869 ServerPlayingSound &psound = i->second;
2870 psound.clients.erase(peer_id);
2871 if (psound.clients.empty())
2872 m_playing_sounds.erase(i++);
2877 // clear formspec info so the next client can't abuse the current state
2878 m_formspec_state_data.erase(peer_id);
2880 RemotePlayer *player = m_env->getPlayer(peer_id);
2882 /* Run scripts and remove from environment */
2884 PlayerSAO *playersao = player->getPlayerSAO();
2887 playersao->clearChildAttachments();
2888 playersao->clearParentAttachment();
2890 // inform connected clients
2891 const std::string &player_name = player->getName();
2892 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2893 // (u16) 1 + std::string represents a vector serialization representation
2894 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2895 m_clients.sendToAll(¬ice);
2897 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2899 playersao->disconnected();
2906 if (player && reason != CDR_DENY) {
2907 std::ostringstream os(std::ios_base::binary);
2908 std::vector<session_t> clients = m_clients.getClientIDs();
2910 for (const session_t client_id : clients) {
2912 RemotePlayer *player = m_env->getPlayer(client_id);
2916 // Get name of player
2917 os << player->getName() << " ";
2920 std::string name = player->getName();
2921 actionstream << name << " "
2922 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2923 << " List of players: " << os.str() << std::endl;
2925 m_admin_chat->outgoing_queue.push_back(
2926 new ChatEventNick(CET_NICK_REMOVE, name));
2930 MutexAutoLock env_lock(m_env_mutex);
2931 m_clients.DeleteClient(peer_id);
2935 // Send leave chat message to all remaining clients
2936 if (!message.empty()) {
2937 SendChatMessage(PEER_ID_INEXISTENT,
2938 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2942 void Server::UpdateCrafting(RemotePlayer *player)
2944 InventoryList *clist = player->inventory.getList("craft");
2945 if (!clist || clist->getSize() == 0)
2948 if (!clist->checkModified())
2951 // Get a preview for crafting
2953 InventoryLocation loc;
2954 loc.setPlayer(player->getName());
2955 std::vector<ItemStack> output_replacements;
2956 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2957 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2960 InventoryList *plist = player->inventory.getList("craftpreview");
2961 if (plist && plist->getSize() >= 1) {
2962 // Put the new preview in
2963 plist->changeItem(0, preview);
2967 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2969 if (evt->type == CET_NICK_ADD) {
2970 // The terminal informed us of its nick choice
2971 m_admin_nick = ((ChatEventNick *)evt)->nick;
2972 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2973 errorstream << "You haven't set up an account." << std::endl
2974 << "Please log in using the client as '"
2975 << m_admin_nick << "' with a secure password." << std::endl
2976 << "Until then, you can't execute admin tasks via the console," << std::endl
2977 << "and everybody can claim the user account instead of you," << std::endl
2978 << "giving them full control over this server." << std::endl;
2981 assert(evt->type == CET_CHAT);
2982 handleAdminChat((ChatEventChat *)evt);
2986 std::wstring Server::handleChat(const std::string &name,
2987 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2989 // If something goes wrong, this player is to blame
2990 RollbackScopeActor rollback_scope(m_rollback,
2991 std::string("player:") + name);
2993 if (g_settings->getBool("strip_color_codes"))
2994 wmessage = unescape_enriched(wmessage);
2997 switch (player->canSendChatMessage()) {
2998 case RPLAYER_CHATRESULT_FLOODING: {
2999 std::wstringstream ws;
3000 ws << L"You cannot send more messages. You are limited to "
3001 << g_settings->getFloat("chat_message_limit_per_10sec")
3002 << L" messages per 10 seconds.";
3005 case RPLAYER_CHATRESULT_KICK:
3006 DenyAccess_Legacy(player->getPeerId(),
3007 L"You have been kicked due to message flooding.");
3009 case RPLAYER_CHATRESULT_OK:
3012 FATAL_ERROR("Unhandled chat filtering result found.");
3016 if (m_max_chatmessage_length > 0
3017 && wmessage.length() > m_max_chatmessage_length) {
3018 return L"Your message exceed the maximum chat message limit set on the server. "
3019 L"It was refused. Send a shorter message";
3022 auto message = trim(wide_to_utf8(wmessage));
3023 if (message.empty())
3026 if (message.find_first_of("\n\r") != std::wstring::npos) {
3027 return L"Newlines are not permitted in chat messages";
3030 // Run script hook, exit if script ate the chat message
3031 if (m_script->on_chat_message(name, message))
3036 // Whether to send line to the player that sent the message, or to all players
3037 bool broadcast_line = true;
3039 if (check_shout_priv && !checkPriv(name, "shout")) {
3040 line += L"-!- You don't have permission to shout.";
3041 broadcast_line = false;
3044 Workaround for fixing chat on Android. Lua doesn't handle
3045 the Cyrillic alphabet and some characters on older Android devices
3048 line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
3050 line += utf8_to_wide(m_script->formatChatMessage(name,
3051 wide_to_utf8(wmessage)));
3056 Tell calling method to send the message to sender
3058 if (!broadcast_line)
3062 Send the message to others
3064 actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
3066 ChatMessage chatmsg(line);
3068 std::vector<session_t> clients = m_clients.getClientIDs();
3069 for (u16 cid : clients)
3070 SendChatMessage(cid, chatmsg);
3075 void Server::handleAdminChat(const ChatEventChat *evt)
3077 std::string name = evt->nick;
3078 std::wstring wmessage = evt->evt_msg;
3080 std::wstring answer = handleChat(name, wmessage);
3082 // If asked to send answer to sender
3083 if (!answer.empty()) {
3084 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3088 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3090 RemoteClient *client = getClientNoEx(peer_id,state_min);
3092 throw ClientNotFoundException("Client not found");
3096 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3098 return m_clients.getClientNoEx(peer_id, state_min);
3101 std::string Server::getPlayerName(session_t peer_id)
3103 RemotePlayer *player = m_env->getPlayer(peer_id);
3105 return "[id="+itos(peer_id)+"]";
3106 return player->getName();
3109 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3111 RemotePlayer *player = m_env->getPlayer(peer_id);
3114 return player->getPlayerSAO();
3117 std::string Server::getStatusString()
3119 std::ostringstream os(std::ios_base::binary);
3122 os << "version: " << g_version_string;
3124 os << " | uptime: " << duration_to_string((int) m_uptime_counter->get());
3126 os << " | max lag: " << std::setprecision(3);
3127 os << (m_env ? m_env->getMaxLagEstimate() : 0) << "s";
3129 // Information about clients
3131 os << " | clients: ";
3133 std::vector<session_t> clients = m_clients.getClientIDs();
3134 for (session_t client_id : clients) {
3135 RemotePlayer *player = m_env->getPlayer(client_id);
3137 // Get name of player
3138 const char *name = player ? player->getName() : "<unknown>";
3140 // Add name to information string
3149 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3150 os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
3152 if (!g_settings->get("motd").empty())
3153 os << std::endl << "# Server: " << g_settings->get("motd");
3158 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3160 std::set<std::string> privs;
3161 m_script->getAuth(name, NULL, &privs);
3165 bool Server::checkPriv(const std::string &name, const std::string &priv)
3167 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3168 return (privs.count(priv) != 0);
3171 void Server::reportPrivsModified(const std::string &name)
3174 std::vector<session_t> clients = m_clients.getClientIDs();
3175 for (const session_t client_id : clients) {
3176 RemotePlayer *player = m_env->getPlayer(client_id);
3177 reportPrivsModified(player->getName());
3180 RemotePlayer *player = m_env->getPlayer(name.c_str());
3183 SendPlayerPrivileges(player->getPeerId());
3184 PlayerSAO *sao = player->getPlayerSAO();
3187 sao->updatePrivileges(
3188 getPlayerEffectivePrivs(name),
3193 void Server::reportInventoryFormspecModified(const std::string &name)
3195 RemotePlayer *player = m_env->getPlayer(name.c_str());
3198 SendPlayerInventoryFormspec(player->getPeerId());
3201 void Server::reportFormspecPrependModified(const std::string &name)
3203 RemotePlayer *player = m_env->getPlayer(name.c_str());
3206 SendPlayerFormspecPrepend(player->getPeerId());
3209 void Server::setIpBanned(const std::string &ip, const std::string &name)
3211 m_banmanager->add(ip, name);
3214 void Server::unsetIpBanned(const std::string &ip_or_name)
3216 m_banmanager->remove(ip_or_name);
3219 std::string Server::getBanDescription(const std::string &ip_or_name)
3221 return m_banmanager->getBanDescription(ip_or_name);
3224 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3226 // m_env will be NULL if the server is initializing
3230 if (m_admin_nick == name && !m_admin_nick.empty()) {
3231 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3234 RemotePlayer *player = m_env->getPlayer(name);
3239 if (player->getPeerId() == PEER_ID_INEXISTENT)
3242 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3245 bool Server::showFormspec(const char *playername, const std::string &formspec,
3246 const std::string &formname)
3248 // m_env will be NULL if the server is initializing
3252 RemotePlayer *player = m_env->getPlayer(playername);
3256 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3260 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3265 u32 id = player->addHud(form);
3267 SendHUDAdd(player->getPeerId(), id, form);
3272 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3276 HudElement* todel = player->removeHud(id);
3283 SendHUDRemove(player->getPeerId(), id);
3287 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3292 SendHUDChange(player->getPeerId(), id, stat, data);
3296 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3301 SendHUDSetFlags(player->getPeerId(), flags, mask);
3302 player->hud_flags &= ~mask;
3303 player->hud_flags |= flags;
3305 PlayerSAO* playersao = player->getPlayerSAO();
3310 m_script->player_event(playersao, "hud_changed");
3314 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3319 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3322 player->setHotbarItemcount(hotbar_itemcount);
3323 std::ostringstream os(std::ios::binary);
3324 writeS32(os, hotbar_itemcount);
3325 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3329 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3334 player->setHotbarImage(name);
3335 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3338 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3343 player->setHotbarSelectedImage(name);
3344 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3347 Address Server::getPeerAddress(session_t peer_id)
3349 // Note that this is only set after Init was received in Server::handleCommand_Init
3350 return getClient(peer_id, CS_Invalid)->getAddress();
3353 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3354 v2s32 animation_frames[4], f32 frame_speed)
3356 sanity_check(player);
3357 player->setLocalAnimations(animation_frames, frame_speed);
3358 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3361 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3363 sanity_check(player);
3364 player->eye_offset_first = first;
3365 player->eye_offset_third = third;
3366 SendEyeOffset(player->getPeerId(), first, third);
3369 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3371 sanity_check(player);
3372 player->setSky(params);
3373 SendSetSky(player->getPeerId(), params);
3376 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3378 sanity_check(player);
3379 player->setSun(params);
3380 SendSetSun(player->getPeerId(), params);
3383 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3385 sanity_check(player);
3386 player->setMoon(params);
3387 SendSetMoon(player->getPeerId(), params);
3390 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3392 sanity_check(player);
3393 player->setStars(params);
3394 SendSetStars(player->getPeerId(), params);
3397 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3399 sanity_check(player);
3400 player->setCloudParams(params);
3401 SendCloudParams(player->getPeerId(), params);
3404 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3407 sanity_check(player);
3408 player->overrideDayNightRatio(do_override, ratio);
3409 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3412 void Server::notifyPlayers(const std::wstring &msg)
3414 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3417 void Server::spawnParticle(const std::string &playername,
3418 const ParticleParameters &p)
3420 // m_env will be NULL if the server is initializing
3424 session_t peer_id = PEER_ID_INEXISTENT;
3426 if (!playername.empty()) {
3427 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3430 peer_id = player->getPeerId();
3431 proto_ver = player->protocol_version;
3434 SendSpawnParticle(peer_id, proto_ver, p);
3437 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3438 ServerActiveObject *attached, const std::string &playername)
3440 // m_env will be NULL if the server is initializing
3444 session_t peer_id = PEER_ID_INEXISTENT;
3446 if (!playername.empty()) {
3447 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3450 peer_id = player->getPeerId();
3451 proto_ver = player->protocol_version;
3454 u16 attached_id = attached ? attached->getId() : 0;
3457 if (attached_id == 0)
3458 id = m_env->addParticleSpawner(p.time);
3460 id = m_env->addParticleSpawner(p.time, attached_id);
3462 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3466 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3468 // m_env will be NULL if the server is initializing
3470 throw ServerError("Can't delete particle spawners during initialisation!");
3472 session_t peer_id = PEER_ID_INEXISTENT;
3473 if (!playername.empty()) {
3474 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3477 peer_id = player->getPeerId();
3480 m_env->deleteParticleSpawner(id);
3481 SendDeleteParticleSpawner(peer_id, id);
3484 bool Server::dynamicAddMedia(std::string filepath,
3485 const u32 token, const std::string &to_player, bool ephemeral)
3487 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3488 auto it = m_media.find(filename);
3489 if (it != m_media.end()) {
3490 // Allow the same path to be "added" again in certain conditions
3491 if (ephemeral || it->second.path != filepath) {
3492 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3493 << "\" already exists in media cache" << std::endl;
3498 // Load the file and add it to our media cache
3499 std::string filedata, raw_hash;
3500 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3505 // Create a copy of the file and swap out the path, this removes the
3506 // requirement that mods keep the file accessible at the original path.
3507 filepath = fs::CreateTempFile();
3508 bool ok = ([&] () -> bool {
3509 if (filepath.empty())
3511 std::ofstream os(filepath.c_str(), std::ios::binary);
3519 errorstream << "Server: failed to create a copy of media file "
3520 << "\"" << filename << "\"" << std::endl;
3521 m_media.erase(filename);
3524 verbosestream << "Server: \"" << filename << "\" temporarily copied to "
3525 << filepath << std::endl;
3527 m_media[filename].path = filepath;
3528 m_media[filename].no_announce = true;
3529 // stepPendingDynMediaCallbacks will clean this up later.
3530 } else if (!to_player.empty()) {
3531 m_media[filename].no_announce = true;
3534 // Push file to existing clients
3535 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3536 pkt << raw_hash << filename << (bool)ephemeral;
3538 NetworkPacket legacy_pkt = pkt;
3540 // Newer clients get asked to fetch the file (asynchronous)
3542 // Older clients have an awful hack that just throws the data at them
3543 legacy_pkt.putLongString(filedata);
3545 std::unordered_set<session_t> delivered, waiting;
3547 for (auto &pair : m_clients.getClientList()) {
3548 if (pair.second->getState() < CS_DefinitionsSent)
3550 const auto proto_ver = pair.second->net_proto_version;
3554 const session_t peer_id = pair.second->peer_id;
3555 if (!to_player.empty() && getPlayerName(peer_id) != to_player)
3558 if (proto_ver < 40) {
3559 delivered.emplace(peer_id);
3561 The network layer only guarantees ordered delivery inside a channel.
3562 Since the very next packet could be one that uses the media, we have
3563 to push the media over ALL channels to ensure it is processed before
3564 it is used. In practice this means channels 1 and 0.
3566 m_clients.send(peer_id, 1, &legacy_pkt, true);
3567 m_clients.send(peer_id, 0, &legacy_pkt, true);
3569 waiting.emplace(peer_id);
3570 Send(peer_id, &pkt);
3575 // Run callback for players that already had the file delivered (legacy-only)
3576 for (session_t peer_id : delivered) {
3577 if (auto player = m_env->getPlayer(peer_id))
3578 getScriptIface()->on_dynamic_media_added(token, player->getName());
3581 // Save all others in our pending state
3582 auto &state = m_pending_dyn_media[token];
3583 state.waiting_players = std::move(waiting);
3584 // regardless of success throw away the callback after a while
3585 state.expiry_timer = 60.0f;
3587 state.filename = filename;
3592 // actions: time-reversed list
3593 // Return value: success/failure
3594 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3595 std::list<std::string> *log)
3597 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3598 ServerMap *map = (ServerMap*)(&m_env->getMap());
3600 // Fail if no actions to handle
3601 if (actions.empty()) {
3603 log->push_back("Nothing to do.");
3610 for (const RollbackAction &action : actions) {
3612 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3615 std::ostringstream os;
3616 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3617 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3619 log->push_back(os.str());
3621 std::ostringstream os;
3622 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3623 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3625 log->push_back(os.str());
3629 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3630 <<" failed"<<std::endl;
3632 // Call it done if less than half failed
3633 return num_failed <= num_tried/2;
3636 // IGameDef interface
3638 IItemDefManager *Server::getItemDefManager()
3643 const NodeDefManager *Server::getNodeDefManager()
3648 ICraftDefManager *Server::getCraftDefManager()
3653 u16 Server::allocateUnknownNodeId(const std::string &name)
3655 return m_nodedef->allocateDummy(name);
3658 IWritableItemDefManager *Server::getWritableItemDefManager()
3663 NodeDefManager *Server::getWritableNodeDefManager()
3668 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3673 const std::vector<ModSpec> & Server::getMods() const
3675 return m_modmgr->getMods();
3678 const ModSpec *Server::getModSpec(const std::string &modname) const
3680 return m_modmgr->getModSpec(modname);
3683 void Server::getModNames(std::vector<std::string> &modlist)
3685 m_modmgr->getModNames(modlist);
3688 std::string Server::getBuiltinLuaPath()
3690 return porting::path_share + DIR_DELIM + "builtin";
3693 std::string Server::getModStoragePath() const
3695 return m_path_world + DIR_DELIM + "mod_storage";
3698 v3f Server::findSpawnPos()
3700 ServerMap &map = m_env->getServerMap();
3702 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3703 return nodeposf * BS;
3705 bool is_good = false;
3706 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3707 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3709 // Try to find a good place a few times
3710 for (s32 i = 0; i < 4000 && !is_good; i++) {
3711 s32 range = MYMIN(1 + i, range_max);
3712 // We're going to try to throw the player to this position
3713 v2s16 nodepos2d = v2s16(
3714 -range + (myrand() % (range * 2)),
3715 -range + (myrand() % (range * 2)));
3716 // Get spawn level at point
3717 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3718 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3719 // signify an unsuitable spawn position, or if outside limits.
3720 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3721 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3724 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3725 // Consecutive empty nodes
3728 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3729 // avoid obstructions in already-generated mapblocks.
3730 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3731 // no obstructions, but mapgen decorations are generated after spawn so
3732 // the player may end up inside one.
3733 for (s32 i = 0; i < 8; i++) {
3734 v3s16 blockpos = getNodeBlockPos(nodepos);
3735 map.emergeBlock(blockpos, true);
3736 content_t c = map.getNode(nodepos).getContent();
3738 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3739 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3740 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3742 if (air_count >= 2) {
3743 // Spawn in lower empty node
3745 nodeposf = intToFloat(nodepos, BS);
3746 // Don't spawn the player outside map boundaries
3747 if (objectpos_over_limit(nodeposf))
3748 // Exit this loop, positions above are probably over limit
3751 // Good position found, cause an exit from main loop
3765 // No suitable spawn point found, return fallback 0,0,0
3766 return v3f(0.0f, 0.0f, 0.0f);
3769 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3771 if (delay == 0.0f) {
3772 // No delay, shutdown immediately
3773 m_shutdown_state.is_requested = true;
3774 // only print to the infostream, a chat message saying
3775 // "Server Shutting Down" is sent when the server destructs.
3776 infostream << "*** Immediate Server shutdown requested." << std::endl;
3777 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3778 // Negative delay, cancel shutdown if requested
3779 m_shutdown_state.reset();
3780 std::wstringstream ws;
3782 ws << L"*** Server shutdown canceled.";
3784 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3785 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3786 // m_shutdown_* are already handled, skip.
3788 } else if (delay > 0.0f) {
3789 // Positive delay, tell the clients when the server will shut down
3790 std::wstringstream ws;
3792 ws << L"*** Server shutting down in "
3793 << duration_to_string(myround(delay)).c_str()
3796 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3797 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3800 m_shutdown_state.trigger(delay, msg, reconnect);
3803 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3806 Try to get an existing player
3808 RemotePlayer *player = m_env->getPlayer(name);
3810 // If player is already connected, cancel
3811 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3812 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3817 If player with the wanted peer_id already exists, cancel.
3819 if (m_env->getPlayer(peer_id)) {
3820 infostream<<"emergePlayer(): Player with wrong name but same"
3821 " peer_id already exists"<<std::endl;
3826 player = new RemotePlayer(name, idef());
3829 bool newplayer = false;
3832 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3834 // Complete init with server parts
3835 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3836 player->protocol_version = proto_version;
3840 m_script->on_newplayer(playersao);
3846 bool Server::registerModStorage(ModMetadata *storage)
3848 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3849 errorstream << "Unable to register same mod storage twice. Storage name: "
3850 << storage->getModName() << std::endl;
3854 m_mod_storages[storage->getModName()] = storage;
3858 void Server::unregisterModStorage(const std::string &name)
3860 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3861 if (it != m_mod_storages.end()) {
3862 // Save unconditionaly on unregistration
3863 it->second->save(getModStoragePath());
3864 m_mod_storages.erase(name);
3868 void dedicated_server_loop(Server &server, bool &kill)
3870 verbosestream<<"dedicated_server_loop()"<<std::endl;
3872 IntervalLimiter m_profiler_interval;
3874 static thread_local const float steplen =
3875 g_settings->getFloat("dedicated_server_step");
3876 static thread_local const float profiler_print_interval =
3877 g_settings->getFloat("profiler_print_interval");
3880 * The dedicated server loop only does time-keeping (in Server::step) and
3881 * provides a way to main.cpp to kill the server externally (bool &kill).
3885 // This is kind of a hack but can be done like this
3886 // because server.step() is very light
3887 sleep_ms((int)(steplen*1000.0));
3888 server.step(steplen);
3890 if (server.isShutdownRequested() || kill)
3896 if (profiler_print_interval != 0) {
3897 if(m_profiler_interval.step(steplen, profiler_print_interval))
3899 infostream<<"Profiler:"<<std::endl;
3900 g_profiler->print(infostream);
3901 g_profiler->clear();
3906 infostream << "Dedicated server quitting" << std::endl;
3908 if (g_settings->getBool("server_announce"))
3909 ServerList::sendAnnounce(ServerList::AA_DELETE,
3910 server.m_bind_addr.getPort());
3919 bool Server::joinModChannel(const std::string &channel)
3921 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3922 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3925 bool Server::leaveModChannel(const std::string &channel)
3927 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3930 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3932 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3935 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3939 ModChannel* Server::getModChannel(const std::string &channel)
3941 return m_modchannel_mgr->getModChannel(channel);
3944 void Server::broadcastModChannelMessage(const std::string &channel,
3945 const std::string &message, session_t from_peer)
3947 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3951 if (message.size() > STRING_MAX_LEN) {
3952 warningstream << "ModChannel message too long, dropping before sending "
3953 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3954 << channel << ")" << std::endl;
3959 if (from_peer != PEER_ID_SERVER) {
3960 sender = getPlayerName(from_peer);
3963 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3964 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3965 resp_pkt << channel << sender << message;
3966 for (session_t peer_id : peers) {
3968 if (peer_id == from_peer)
3971 Send(peer_id, &resp_pkt);
3974 if (from_peer != PEER_ID_SERVER) {
3975 m_script->on_modchannel_message(channel, sender, message);
3979 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3981 if (lang_code.empty())
3984 auto it = server_translations.find(lang_code);
3985 if (it != server_translations.end())
3986 return &it->second; // Already loaded
3988 // [] will create an entry
3989 auto *translations = &server_translations[lang_code];
3991 std::string suffix = "." + lang_code + ".tr";
3992 for (const auto &i : m_media) {
3993 if (str_ends_with(i.first, suffix)) {
3995 if (fs::ReadFile(i.second.path, data)) {
3996 translations->loadTranslation(data);
4001 return translations;