3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "server/serveractiveobject.h"
41 #include "scripting_server.h"
46 #include "mapgen/mapgen.h"
47 #include "mapgen/mg_biome.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content/mods.h"
51 #include "modchannels.h"
52 #include "serverlist.h"
53 #include "util/string.h"
55 #include "util/serialize.h"
56 #include "util/thread.h"
57 #include "defaultsettings.h"
58 #include "server/mods.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
62 #include "database/database.h"
63 #include "chatmessage.h"
64 #include "chat_interface.h"
65 #include "remoteplayer.h"
66 #include "server/player_sao.h"
67 #include "server/serverinventorymgr.h"
68 #include "translation.h"
70 class ClientNotFoundException : public BaseException
73 ClientNotFoundException(const char *s):
78 class ServerThread : public Thread
82 ServerThread(Server *server):
93 void *ServerThread::run()
95 BEGIN_DEBUG_EXCEPTION_HANDLER
98 * The real business of the server happens on the ServerThread.
100 * AsyncRunStep() runs an actual server step as soon as enough time has
101 * passed (dedicated_server_loop keeps track of that).
102 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
103 * doesn't busy wait) and will process any remaining packets.
106 m_server->AsyncRunStep(true);
108 while (!stopRequested()) {
110 m_server->AsyncRunStep();
114 } catch (con::PeerNotFoundException &e) {
115 infostream<<"Server: PeerNotFoundException"<<std::endl;
116 } catch (ClientNotFoundException &e) {
117 } catch (con::ConnectionBindFailed &e) {
118 m_server->setAsyncFatalError(e.what());
119 } catch (LuaError &e) {
120 m_server->setAsyncFatalError(
121 "ServerThread::run Lua: " + std::string(e.what()));
125 END_DEBUG_EXCEPTION_HANDLER
130 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
132 if(pos_exists) *pos_exists = false;
137 if(pos_exists) *pos_exists = true;
142 ServerActiveObject *sao = env->getActiveObject(object);
145 if(pos_exists) *pos_exists = true;
146 return sao->getBasePosition(); }
151 void Server::ShutdownState::reset()
155 should_reconnect = false;
156 is_requested = false;
159 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
163 should_reconnect = reconnect;
166 void Server::ShutdownState::tick(float dtime, Server *server)
172 static const float shutdown_msg_times[] =
174 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
177 // Automated messages
178 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
179 for (float t : shutdown_msg_times) {
180 // If shutdown timer matches an automessage, shot it
181 if (m_timer > t && m_timer - dtime < t) {
182 std::wstring periodicMsg = getShutdownTimerMessage();
184 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
185 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
192 if (m_timer < 0.0f) {
198 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
200 std::wstringstream ws;
201 ws << L"*** Server shutting down in "
202 << duration_to_string(myround(m_timer)).c_str() << ".";
211 const std::string &path_world,
212 const SubgameSpec &gamespec,
213 bool simple_singleplayer_mode,
216 ChatInterface *iface,
217 std::string *on_shutdown_errmsg
219 m_bind_addr(bind_addr),
220 m_path_world(path_world),
221 m_gamespec(gamespec),
222 m_simple_singleplayer_mode(simple_singleplayer_mode),
223 m_dedicated(dedicated),
224 m_async_fatal_error(""),
225 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
228 m_bind_addr.isIPv6(),
230 m_itemdef(createItemDefManager()),
231 m_nodedef(createNodeDefManager()),
232 m_craftdef(createCraftDefManager()),
233 m_thread(new ServerThread(this)),
236 m_on_shutdown_errmsg(on_shutdown_errmsg),
237 m_modchannel_mgr(new ModChannelMgr())
239 if (m_path_world.empty())
240 throw ServerError("Supplied empty world path");
242 if (!gamespec.isValid())
243 throw ServerError("Supplied invalid gamespec");
246 m_metrics_backend = std::unique_ptr<MetricsBackend>(createPrometheusMetricsBackend());
248 m_metrics_backend = std::unique_ptr<MetricsBackend>(new MetricsBackend());
251 m_uptime_counter = m_metrics_backend->addCounter("minetest_core_server_uptime", "Server uptime (in seconds)");
252 m_player_gauge = m_metrics_backend->addGauge("minetest_core_player_number", "Number of connected players");
254 m_timeofday_gauge = m_metrics_backend->addGauge(
255 "minetest_core_timeofday",
256 "Time of day value");
258 m_lag_gauge = m_metrics_backend->addGauge(
259 "minetest_core_latency",
260 "Latency value (in seconds)");
262 m_aom_buffer_counter = m_metrics_backend->addCounter(
263 "minetest_core_aom_generated_count",
264 "Number of active object messages generated");
266 m_packet_recv_counter = m_metrics_backend->addCounter(
267 "minetest_core_server_packet_recv",
268 "Processable packets received");
270 m_packet_recv_processed_counter = m_metrics_backend->addCounter(
271 "minetest_core_server_packet_recv_processed",
272 "Valid received packets processed");
274 m_lag_gauge->set(g_settings->getFloat("dedicated_server_step"));
280 // Send shutdown message
281 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
282 L"*** Server shutting down"));
285 MutexAutoLock envlock(m_env_mutex);
287 infostream << "Server: Saving players" << std::endl;
288 m_env->saveLoadedPlayers();
290 infostream << "Server: Kicking players" << std::endl;
291 std::string kick_msg;
292 bool reconnect = false;
293 if (isShutdownRequested()) {
294 reconnect = m_shutdown_state.should_reconnect;
295 kick_msg = m_shutdown_state.message;
297 if (kick_msg.empty()) {
298 kick_msg = g_settings->get("kick_msg_shutdown");
300 m_env->saveLoadedPlayers(true);
301 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
302 kick_msg, reconnect);
305 actionstream << "Server: Shutting down" << std::endl;
307 // Do this before stopping the server in case mapgen callbacks need to access
308 // server-controlled resources (like ModStorages). Also do them before
309 // shutdown callbacks since they may modify state that is finalized in a
312 m_emerge->stopThreads();
315 MutexAutoLock envlock(m_env_mutex);
317 // Execute script shutdown hooks
318 infostream << "Executing shutdown hooks" << std::endl;
320 m_script->on_shutdown();
321 } catch (ModError &e) {
322 errorstream << "ModError: " << e.what() << std::endl;
323 if (m_on_shutdown_errmsg) {
324 if (m_on_shutdown_errmsg->empty()) {
325 *m_on_shutdown_errmsg = std::string("ModError: ") + e.what();
327 *m_on_shutdown_errmsg += std::string("\nModError: ") + e.what();
332 infostream << "Server: Saving environment metadata" << std::endl;
342 // Delete things in the reverse order of creation
351 // Deinitialize scripting
352 infostream << "Server: Deinitializing scripting" << std::endl;
354 delete m_game_settings;
356 while (!m_unsent_map_edit_queue.empty()) {
357 delete m_unsent_map_edit_queue.front();
358 m_unsent_map_edit_queue.pop();
364 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
365 if (m_simple_singleplayer_mode)
366 infostream << " in simple singleplayer mode" << std::endl;
368 infostream << std::endl;
369 infostream << "- world: " << m_path_world << std::endl;
370 infostream << "- game: " << m_gamespec.path << std::endl;
372 m_game_settings = Settings::createLayer(SL_GAME);
374 // Create world if it doesn't exist
376 loadGameConfAndInitWorld(m_path_world,
377 fs::GetFilenameFromPath(m_path_world.c_str()),
379 } catch (const BaseException &e) {
380 throw ServerError(std::string("Failed to initialize world: ") + e.what());
383 // Create emerge manager
384 m_emerge = new EmergeManager(this);
386 // Create ban manager
387 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
388 m_banmanager = new BanManager(ban_path);
390 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
391 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
392 // complain about mods with unsatisfied dependencies
393 if (!m_modmgr->isConsistent()) {
394 m_modmgr->printUnsatisfiedModsError();
398 MutexAutoLock envlock(m_env_mutex);
400 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
401 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge, m_metrics_backend.get());
403 // Initialize scripting
404 infostream << "Server: Initializing Lua" << std::endl;
406 m_script = new ServerScripting(this);
408 // Must be created before mod loading because we have some inventory creation
409 m_inventory_mgr = std::unique_ptr<ServerInventoryManager>(new ServerInventoryManager());
411 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
413 m_modmgr->loadMods(m_script);
415 // Read Textures and calculate sha1 sums
418 // Apply item aliases in the node definition manager
419 m_nodedef->updateAliases(m_itemdef);
421 // Apply texture overrides from texturepack/override.txt
422 std::vector<std::string> paths;
423 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
424 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
425 for (const std::string &path : paths) {
426 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
427 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
428 m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
431 m_nodedef->setNodeRegistrationStatus(true);
433 // Perform pending node name resolutions
434 m_nodedef->runNodeResolveCallbacks();
436 // unmap node names in cross-references
437 m_nodedef->resolveCrossrefs();
439 // init the recipe hashes to speed up crafting
440 m_craftdef->initHashes(this);
442 // Initialize Environment
443 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
445 m_inventory_mgr->setEnv(m_env);
446 m_clients.setEnv(m_env);
448 if (!servermap->settings_mgr.makeMapgenParams())
449 FATAL_ERROR("Couldn't create any mapgen type");
451 // Initialize mapgens
452 m_emerge->initMapgens(servermap->getMapgenParams());
454 if (g_settings->getBool("enable_rollback_recording")) {
455 // Create rollback manager
456 m_rollback = new RollbackManager(m_path_world, this);
459 // Give environment reference to scripting api
460 m_script->initializeEnvironment(m_env);
462 // Register us to receive map edit events
463 servermap->addEventReceiver(this);
467 // Those settings can be overwritten in world.mt, they are
468 // intended to be cached after environment loading.
469 m_liquid_transform_every = g_settings->getFloat("liquid_update");
470 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
471 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
472 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
479 infostream << "Starting server on " << m_bind_addr.serializeString()
480 << "..." << std::endl;
482 // Stop thread if already running
485 // Initialize connection
486 m_con->SetTimeoutMs(30);
487 m_con->Serve(m_bind_addr);
492 // ASCII art for the win!
494 << " .__ __ __ " << std::endl
495 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
496 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
497 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
498 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
499 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
500 actionstream << "World at [" << m_path_world << "]" << std::endl;
501 actionstream << "Server for gameid=\"" << m_gamespec.id
502 << "\" listening on " << m_bind_addr.serializeString() << ":"
503 << m_bind_addr.getPort() << "." << std::endl;
508 infostream<<"Server: Stopping and waiting threads"<<std::endl;
510 // Stop threads (set run=false first so both start stopping)
512 //m_emergethread.setRun(false);
514 //m_emergethread.stop();
516 infostream<<"Server: Threads stopped"<<std::endl;
519 void Server::step(float dtime)
525 MutexAutoLock lock(m_step_dtime_mutex);
526 m_step_dtime += dtime;
528 // Throw if fatal error occurred in thread
529 std::string async_err = m_async_fatal_error.get();
530 if (!async_err.empty()) {
531 if (!m_simple_singleplayer_mode) {
532 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
533 g_settings->get("kick_msg_crash"),
534 g_settings->getBool("ask_reconnect_on_crash"));
536 throw ServerError("AsyncErr: " + async_err);
540 void Server::AsyncRunStep(bool initial_step)
545 MutexAutoLock lock1(m_step_dtime_mutex);
546 dtime = m_step_dtime;
550 // Send blocks to clients
554 if((dtime < 0.001) && !initial_step)
557 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
560 MutexAutoLock lock1(m_step_dtime_mutex);
561 m_step_dtime -= dtime;
567 m_uptime_counter->increment(dtime);
572 Update time of day and overall game time
574 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
577 Send to clients at constant intervals
580 m_time_of_day_send_timer -= dtime;
581 if (m_time_of_day_send_timer < 0.0) {
582 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
583 u16 time = m_env->getTimeOfDay();
584 float time_speed = g_settings->getFloat("time_speed");
585 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
587 m_timeofday_gauge->set(time);
591 MutexAutoLock lock(m_env_mutex);
592 // Figure out and report maximum lag to environment
593 float max_lag = m_env->getMaxLagEstimate();
594 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
596 if(dtime > 0.1 && dtime > max_lag * 2.0)
597 infostream<<"Server: Maximum lag peaked to "<<dtime
601 m_env->reportMaxLagEstimate(max_lag);
606 static const float map_timer_and_unload_dtime = 2.92;
607 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
609 MutexAutoLock lock(m_env_mutex);
610 // Run Map's timers and unload unused data
611 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
612 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
613 g_settings->getFloat("server_unload_unused_data_timeout"),
618 Listen to the admin chat, if available
621 if (!m_admin_chat->command_queue.empty()) {
622 MutexAutoLock lock(m_env_mutex);
623 while (!m_admin_chat->command_queue.empty()) {
624 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
625 handleChatInterfaceEvent(evt);
629 m_admin_chat->outgoing_queue.push_back(
630 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
637 /* Transform liquids */
638 m_liquid_transform_timer += dtime;
639 if(m_liquid_transform_timer >= m_liquid_transform_every)
641 m_liquid_transform_timer -= m_liquid_transform_every;
643 MutexAutoLock lock(m_env_mutex);
645 ScopeProfiler sp(g_profiler, "Server: liquid transform");
647 std::map<v3s16, MapBlock*> modified_blocks;
648 m_env->getMap().transformLiquids(modified_blocks, m_env);
651 Set the modified blocks unsent for all the clients
653 if (!modified_blocks.empty()) {
654 SetBlocksNotSent(modified_blocks);
657 m_clients.step(dtime);
659 // increase/decrease lag gauge gradually
660 if (m_lag_gauge->get() > dtime) {
661 m_lag_gauge->decrement(dtime/100);
663 m_lag_gauge->increment(dtime/100);
666 // send masterserver announce
668 float &counter = m_masterserver_timer;
669 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
670 g_settings->getBool("server_announce")) {
671 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
672 ServerList::AA_START,
673 m_bind_addr.getPort(),
674 m_clients.getPlayerNames(),
675 m_uptime_counter->get(),
676 m_env->getGameTime(),
679 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
689 Check added and deleted active objects
692 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
693 MutexAutoLock envlock(m_env_mutex);
696 const RemoteClientMap &clients = m_clients.getClientList();
697 ScopeProfiler sp(g_profiler, "Server: update objects within range");
699 m_player_gauge->set(clients.size());
700 for (const auto &client_it : clients) {
701 RemoteClient *client = client_it.second;
703 if (client->getState() < CS_DefinitionsSent)
706 // This can happen if the client times out somehow
707 if (!m_env->getPlayer(client->peer_id))
710 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
714 SendActiveObjectRemoveAdd(client, playersao);
718 // Save mod storages if modified
719 m_mod_storage_save_timer -= dtime;
720 if (m_mod_storage_save_timer <= 0.0f) {
721 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
723 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
724 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
725 if (it->second->isModified()) {
726 it->second->save(getModStoragePath());
731 infostream << "Saved " << n << " modified mod storages." << std::endl;
739 MutexAutoLock envlock(m_env_mutex);
740 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
743 // Value = data sent by object
744 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
746 // Get active object messages from environment
747 ActiveObjectMessage aom(0);
750 if (!m_env->getActiveObjectMessage(&aom))
753 std::vector<ActiveObjectMessage>* message_list = nullptr;
754 auto n = buffered_messages.find(aom.id);
755 if (n == buffered_messages.end()) {
756 message_list = new std::vector<ActiveObjectMessage>;
757 buffered_messages[aom.id] = message_list;
759 message_list = n->second;
761 message_list->push_back(std::move(aom));
765 m_aom_buffer_counter->increment(aom_count);
768 const RemoteClientMap &clients = m_clients.getClientList();
769 // Route data to every client
770 std::string reliable_data, unreliable_data;
771 for (const auto &client_it : clients) {
772 reliable_data.clear();
773 unreliable_data.clear();
774 RemoteClient *client = client_it.second;
775 PlayerSAO *player = getPlayerSAO(client->peer_id);
776 // Go through all objects in message buffer
777 for (const auto &buffered_message : buffered_messages) {
778 // If object does not exist or is not known by client, skip it
779 u16 id = buffered_message.first;
780 ServerActiveObject *sao = m_env->getActiveObject(id);
781 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
784 // Get message list of object
785 std::vector<ActiveObjectMessage>* list = buffered_message.second;
786 // Go through every message
787 for (const ActiveObjectMessage &aom : *list) {
788 // Send position updates to players who do not see the attachment
789 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
790 if (sao->getId() == player->getId())
793 // Do not send position updates for attached players
794 // as long the parent is known to the client
795 ServerActiveObject *parent = sao->getParent();
796 if (parent && client->m_known_objects.find(parent->getId()) !=
797 client->m_known_objects.end())
801 // Add full new data to appropriate buffer
802 std::string &buffer = aom.reliable ? reliable_data : unreliable_data;
804 writeU16((u8*) idbuf, aom.id);
807 buffer.append(idbuf, sizeof(idbuf));
808 buffer.append(serializeString16(aom.datastring));
812 reliable_data and unreliable_data are now ready.
815 if (!reliable_data.empty()) {
816 SendActiveObjectMessages(client->peer_id, reliable_data);
819 if (!unreliable_data.empty()) {
820 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
825 // Clear buffered_messages
826 for (auto &buffered_message : buffered_messages) {
827 delete buffered_message.second;
832 Send queued-for-sending map edit events.
835 // We will be accessing the environment
836 MutexAutoLock lock(m_env_mutex);
838 // Don't send too many at a time
841 // Single change sending is disabled if queue size is not small
842 bool disable_single_change_sending = false;
843 if(m_unsent_map_edit_queue.size() >= 4)
844 disable_single_change_sending = true;
846 int event_count = m_unsent_map_edit_queue.size();
848 // We'll log the amount of each
851 std::list<v3s16> node_meta_updates;
853 while (!m_unsent_map_edit_queue.empty()) {
854 MapEditEvent* event = m_unsent_map_edit_queue.front();
855 m_unsent_map_edit_queue.pop();
857 // Players far away from the change are stored here.
858 // Instead of sending the changes, MapBlocks are set not sent
860 std::unordered_set<u16> far_players;
862 switch (event->type) {
865 prof.add("MEET_ADDNODE", 1);
866 sendAddNode(event->p, event->n, &far_players,
867 disable_single_change_sending ? 5 : 30,
868 event->type == MEET_ADDNODE);
870 case MEET_REMOVENODE:
871 prof.add("MEET_REMOVENODE", 1);
872 sendRemoveNode(event->p, &far_players,
873 disable_single_change_sending ? 5 : 30);
875 case MEET_BLOCK_NODE_METADATA_CHANGED: {
876 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
877 if (!event->is_private_change) {
878 // Don't send the change yet. Collect them to eliminate dupes.
879 node_meta_updates.remove(event->p);
880 node_meta_updates.push_back(event->p);
883 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
884 getNodeBlockPos(event->p))) {
885 block->raiseModified(MOD_STATE_WRITE_NEEDED,
886 MOD_REASON_REPORT_META_CHANGE);
891 prof.add("MEET_OTHER", 1);
892 for (const v3s16 &modified_block : event->modified_blocks) {
893 m_clients.markBlockposAsNotSent(modified_block);
897 prof.add("unknown", 1);
898 warningstream << "Server: Unknown MapEditEvent "
899 << ((u32)event->type) << std::endl;
904 Set blocks not sent to far players
906 if (!far_players.empty()) {
907 // Convert list format to that wanted by SetBlocksNotSent
908 std::map<v3s16, MapBlock*> modified_blocks2;
909 for (const v3s16 &modified_block : event->modified_blocks) {
910 modified_blocks2[modified_block] =
911 m_env->getMap().getBlockNoCreateNoEx(modified_block);
914 // Set blocks not sent
915 for (const u16 far_player : far_players) {
916 if (RemoteClient *client = getClient(far_player))
917 client->SetBlocksNotSent(modified_blocks2);
924 if (event_count >= 5) {
925 infostream << "Server: MapEditEvents:" << std::endl;
926 prof.print(infostream);
927 } else if (event_count != 0) {
928 verbosestream << "Server: MapEditEvents:" << std::endl;
929 prof.print(verbosestream);
932 // Send all metadata updates
933 if (node_meta_updates.size())
934 sendMetadataChanged(node_meta_updates);
938 Trigger emergethread (it somehow gets to a non-triggered but
939 bysy state sometimes)
942 float &counter = m_emergethread_trigger_timer;
944 if (counter >= 2.0) {
947 m_emerge->startThreads();
951 // Save map, players and auth stuff
953 float &counter = m_savemap_timer;
955 static thread_local const float save_interval =
956 g_settings->getFloat("server_map_save_interval");
957 if (counter >= save_interval) {
959 MutexAutoLock lock(m_env_mutex);
961 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
964 if (m_banmanager->isModified()) {
965 m_banmanager->save();
968 // Save changed parts of map
969 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
972 m_env->saveLoadedPlayers();
974 // Save environment metadata
979 m_shutdown_state.tick(dtime, this);
982 void Server::Receive()
992 In the first iteration *wait* for a packet, afterwards process
993 all packets that are immediately available (no waiting).
996 m_con->Receive(&pkt);
999 if (!m_con->TryReceive(&pkt))
1003 peer_id = pkt.getPeerId();
1004 m_packet_recv_counter->increment();
1006 m_packet_recv_processed_counter->increment();
1007 } catch (const con::InvalidIncomingDataException &e) {
1008 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1009 << e.what() << std::endl;
1010 } catch (const SerializationError &e) {
1011 infostream << "Server::Receive(): SerializationError: what()="
1012 << e.what() << std::endl;
1013 } catch (const ClientStateError &e) {
1014 errorstream << "ProcessData: peer=" << peer_id << " what()="
1015 << e.what() << std::endl;
1016 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1017 L"Try reconnecting or updating your client");
1018 } catch (const con::PeerNotFoundException &e) {
1020 } catch (const con::NoIncomingDataException &e) {
1026 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1028 std::string playername;
1029 PlayerSAO *playersao = NULL;
1032 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1034 playername = client->getName();
1035 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1037 } catch (std::exception &e) {
1043 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1045 // If failed, cancel
1046 if (!playersao || !player) {
1047 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1048 actionstream << "Server: Failed to emerge player \"" << playername
1049 << "\" (player allocated to an another client)" << std::endl;
1050 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1051 L"name. If your client closed unexpectedly, try again in "
1054 errorstream << "Server: " << playername << ": Failed to emerge player"
1056 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1062 Send complete position information
1064 SendMovePlayer(peer_id);
1067 SendPlayerPrivileges(peer_id);
1069 // Send inventory formspec
1070 SendPlayerInventoryFormspec(peer_id);
1073 SendInventory(playersao, false);
1075 // Send HP or death screen
1076 if (playersao->isDead())
1077 SendDeathscreen(peer_id, false, v3f(0,0,0));
1079 SendPlayerHPOrDie(playersao,
1080 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1083 SendPlayerBreath(playersao);
1089 Address addr = getPeerAddress(player->getPeerId());
1090 std::string ip_str = addr.serializeString();
1091 const std::vector<std::string> &names = m_clients.getPlayerNames();
1093 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1095 for (const std::string &name : names) {
1096 actionstream << name << " ";
1099 actionstream << player->getName() <<std::endl;
1104 inline void Server::handleCommand(NetworkPacket *pkt)
1106 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1107 (this->*opHandle.handler)(pkt);
1110 void Server::ProcessData(NetworkPacket *pkt)
1112 // Environment is locked first.
1113 MutexAutoLock envlock(m_env_mutex);
1115 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1116 u32 peer_id = pkt->getPeerId();
1119 Address address = getPeerAddress(peer_id);
1120 std::string addr_s = address.serializeString();
1122 if(m_banmanager->isIpBanned(addr_s)) {
1123 std::string ban_name = m_banmanager->getBanName(addr_s);
1124 infostream << "Server: A banned client tried to connect from "
1125 << addr_s << "; banned name was "
1126 << ban_name << std::endl;
1127 // This actually doesn't seem to transfer to the client
1128 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1129 + utf8_to_wide(ban_name));
1133 catch(con::PeerNotFoundException &e) {
1135 * no peer for this packet found
1136 * most common reason is peer timeout, e.g. peer didn't
1137 * respond for some time, your server was overloaded or
1140 infostream << "Server::ProcessData(): Canceling: peer "
1141 << peer_id << " not found" << std::endl;
1146 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1148 // Command must be handled into ToServerCommandHandler
1149 if (command >= TOSERVER_NUM_MSG_TYPES) {
1150 infostream << "Server: Ignoring unknown command "
1151 << command << std::endl;
1155 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1160 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1162 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1163 errorstream << "Server::ProcessData(): Cancelling: Peer"
1164 " serialization format invalid or not initialized."
1165 " Skipping incoming command=" << command << std::endl;
1169 /* Handle commands related to client startup */
1170 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1175 if (m_clients.getClientState(peer_id) < CS_Active) {
1176 if (command == TOSERVER_PLAYERPOS) return;
1178 errorstream << "Got packet command: " << command << " for peer id "
1179 << peer_id << " but client isn't active yet. Dropping packet "
1185 } catch (SendFailedException &e) {
1186 errorstream << "Server::ProcessData(): SendFailedException: "
1187 << "what=" << e.what()
1189 } catch (PacketError &e) {
1190 actionstream << "Server::ProcessData(): PacketError: "
1191 << "what=" << e.what()
1196 void Server::setTimeOfDay(u32 time)
1198 m_env->setTimeOfDay(time);
1199 m_time_of_day_send_timer = 0;
1202 void Server::onMapEditEvent(const MapEditEvent &event)
1204 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1207 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1210 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1212 std::vector<session_t> clients = m_clients.getClientIDs();
1214 // Set the modified blocks unsent for all the clients
1215 for (const session_t client_id : clients) {
1216 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1217 client->SetBlocksNotSent(block);
1222 void Server::peerAdded(con::Peer *peer)
1224 verbosestream<<"Server::peerAdded(): peer->id="
1225 <<peer->id<<std::endl;
1227 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1230 void Server::deletingPeer(con::Peer *peer, bool timeout)
1232 verbosestream<<"Server::deletingPeer(): peer->id="
1233 <<peer->id<<", timeout="<<timeout<<std::endl;
1235 m_clients.event(peer->id, CSE_Disconnect);
1236 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1239 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1241 *retval = m_con->getPeerStat(peer_id,type);
1242 return *retval != -1;
1245 bool Server::getClientInfo(
1254 std::string* vers_string,
1255 std::string* lang_code
1258 *state = m_clients.getClientState(peer_id);
1260 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1267 *uptime = client->uptime();
1268 *ser_vers = client->serialization_version;
1269 *prot_vers = client->net_proto_version;
1271 *major = client->getMajor();
1272 *minor = client->getMinor();
1273 *patch = client->getPatch();
1274 *vers_string = client->getFull();
1275 *lang_code = client->getLangCode();
1282 void Server::handlePeerChanges()
1284 while(!m_peer_change_queue.empty())
1286 con::PeerChange c = m_peer_change_queue.front();
1287 m_peer_change_queue.pop();
1289 verbosestream<<"Server: Handling peer change: "
1290 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1295 case con::PEER_ADDED:
1296 m_clients.CreateClient(c.peer_id);
1299 case con::PEER_REMOVED:
1300 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1304 FATAL_ERROR("Invalid peer change event received!");
1310 void Server::printToConsoleOnly(const std::string &text)
1313 m_admin_chat->outgoing_queue.push_back(
1314 new ChatEventChat("", utf8_to_wide(text)));
1316 std::cout << text << std::endl;
1320 void Server::Send(NetworkPacket *pkt)
1322 Send(pkt->getPeerId(), pkt);
1325 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1327 m_clients.send(peer_id,
1328 clientCommandFactoryTable[pkt->getCommand()].channel,
1330 clientCommandFactoryTable[pkt->getCommand()].reliable);
1333 void Server::SendMovement(session_t peer_id)
1335 std::ostringstream os(std::ios_base::binary);
1337 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1339 pkt << g_settings->getFloat("movement_acceleration_default");
1340 pkt << g_settings->getFloat("movement_acceleration_air");
1341 pkt << g_settings->getFloat("movement_acceleration_fast");
1342 pkt << g_settings->getFloat("movement_speed_walk");
1343 pkt << g_settings->getFloat("movement_speed_crouch");
1344 pkt << g_settings->getFloat("movement_speed_fast");
1345 pkt << g_settings->getFloat("movement_speed_climb");
1346 pkt << g_settings->getFloat("movement_speed_jump");
1347 pkt << g_settings->getFloat("movement_liquid_fluidity");
1348 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1349 pkt << g_settings->getFloat("movement_liquid_sink");
1350 pkt << g_settings->getFloat("movement_gravity");
1355 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1357 if (playersao->isImmortal())
1360 session_t peer_id = playersao->getPeerID();
1361 bool is_alive = playersao->getHP() > 0;
1364 SendPlayerHP(peer_id);
1366 DiePlayer(peer_id, reason);
1369 void Server::SendHP(session_t peer_id, u16 hp)
1371 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1376 void Server::SendBreath(session_t peer_id, u16 breath)
1378 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1379 pkt << (u16) breath;
1383 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1384 const std::string &custom_reason, bool reconnect)
1386 assert(reason < SERVER_ACCESSDENIED_MAX);
1388 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1390 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1391 pkt << custom_reason;
1392 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1393 reason == SERVER_ACCESSDENIED_CRASH)
1394 pkt << custom_reason << (u8)reconnect;
1398 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1400 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1405 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1406 v3f camera_point_target)
1408 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1409 pkt << set_camera_point_target << camera_point_target;
1413 void Server::SendItemDef(session_t peer_id,
1414 IItemDefManager *itemdef, u16 protocol_version)
1416 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1420 u32 length of the next item
1421 zlib-compressed serialized ItemDefManager
1423 std::ostringstream tmp_os(std::ios::binary);
1424 itemdef->serialize(tmp_os, protocol_version);
1425 std::ostringstream tmp_os2(std::ios::binary);
1426 compressZlib(tmp_os.str(), tmp_os2);
1427 pkt.putLongString(tmp_os2.str());
1430 verbosestream << "Server: Sending item definitions to id(" << peer_id
1431 << "): size=" << pkt.getSize() << std::endl;
1436 void Server::SendNodeDef(session_t peer_id,
1437 const NodeDefManager *nodedef, u16 protocol_version)
1439 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1443 u32 length of the next item
1444 zlib-compressed serialized NodeDefManager
1446 std::ostringstream tmp_os(std::ios::binary);
1447 nodedef->serialize(tmp_os, protocol_version);
1448 std::ostringstream tmp_os2(std::ios::binary);
1449 compressZlib(tmp_os.str(), tmp_os2);
1451 pkt.putLongString(tmp_os2.str());
1454 verbosestream << "Server: Sending node definitions to id(" << peer_id
1455 << "): size=" << pkt.getSize() << std::endl;
1461 Non-static send methods
1464 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1466 RemotePlayer *player = sao->getPlayer();
1468 // Do not send new format to old clients
1469 incremental &= player->protocol_version >= 38;
1471 UpdateCrafting(player);
1477 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1479 std::ostringstream os(std::ios::binary);
1480 sao->getInventory()->serialize(os, incremental);
1481 sao->getInventory()->setModified(false);
1482 player->setModified(true);
1484 const std::string &s = os.str();
1485 pkt.putRawString(s.c_str(), s.size());
1489 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1491 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1493 u8 type = message.type;
1494 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1496 if (peer_id != PEER_ID_INEXISTENT) {
1497 RemotePlayer *player = m_env->getPlayer(peer_id);
1503 m_clients.sendToAll(&pkt);
1507 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1508 const std::string &formname)
1510 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1511 if (formspec.empty()){
1512 //the client should close the formspec
1513 //but make sure there wasn't another one open in meantime
1514 const auto it = m_formspec_state_data.find(peer_id);
1515 if (it != m_formspec_state_data.end() && it->second == formname) {
1516 m_formspec_state_data.erase(peer_id);
1518 pkt.putLongString("");
1520 m_formspec_state_data[peer_id] = formname;
1521 pkt.putLongString(formspec);
1528 // Spawns a particle on peer with peer_id
1529 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1530 const ParticleParameters &p)
1532 static thread_local const float radius =
1533 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1535 if (peer_id == PEER_ID_INEXISTENT) {
1536 std::vector<session_t> clients = m_clients.getClientIDs();
1537 const v3f pos = p.pos * BS;
1538 const float radius_sq = radius * radius;
1540 for (const session_t client_id : clients) {
1541 RemotePlayer *player = m_env->getPlayer(client_id);
1545 PlayerSAO *sao = player->getPlayerSAO();
1549 // Do not send to distant clients
1550 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1553 SendSpawnParticle(client_id, player->protocol_version, p);
1557 assert(protocol_version != 0);
1559 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1562 // NetworkPacket and iostreams are incompatible...
1563 std::ostringstream oss(std::ios_base::binary);
1564 p.serialize(oss, protocol_version);
1565 pkt.putRawString(oss.str());
1571 // Adds a ParticleSpawner on peer with peer_id
1572 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1573 const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1575 static thread_local const float radius =
1576 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1578 if (peer_id == PEER_ID_INEXISTENT) {
1579 std::vector<session_t> clients = m_clients.getClientIDs();
1580 const v3f pos = (p.minpos + p.maxpos) / 2.0f * BS;
1581 const float radius_sq = radius * radius;
1582 /* Don't send short-lived spawners to distant players.
1583 * This could be replaced with proper tracking at some point. */
1584 const bool distance_check = !attached_id && p.time <= 1.0f;
1586 for (const session_t client_id : clients) {
1587 RemotePlayer *player = m_env->getPlayer(client_id);
1591 if (distance_check) {
1592 PlayerSAO *sao = player->getPlayerSAO();
1595 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1599 SendAddParticleSpawner(client_id, player->protocol_version,
1600 p, attached_id, id);
1604 assert(protocol_version != 0);
1606 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1608 pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
1609 << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
1610 << p.minsize << p.maxsize << p.collisiondetection;
1612 pkt.putLongString(p.texture);
1614 pkt << id << p.vertical << p.collision_removal << attached_id;
1616 std::ostringstream os(std::ios_base::binary);
1617 p.animation.serialize(os, protocol_version);
1618 pkt.putRawString(os.str());
1620 pkt << p.glow << p.object_collision;
1621 pkt << p.node.param0 << p.node.param2 << p.node_tile;
1626 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1628 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1632 if (peer_id != PEER_ID_INEXISTENT)
1635 m_clients.sendToAll(&pkt);
1639 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1641 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1643 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1644 << form->text << form->number << form->item << form->dir
1645 << form->align << form->offset << form->world_pos << form->size
1646 << form->z_index << form->text2;
1651 void Server::SendHUDRemove(session_t peer_id, u32 id)
1653 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1658 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1660 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1661 pkt << id << (u8) stat;
1665 case HUD_STAT_SCALE:
1666 case HUD_STAT_ALIGN:
1667 case HUD_STAT_OFFSET:
1668 pkt << *(v2f *) value;
1672 case HUD_STAT_TEXT2:
1673 pkt << *(std::string *) value;
1675 case HUD_STAT_WORLD_POS:
1676 pkt << *(v3f *) value;
1679 pkt << *(v2s32 *) value;
1681 case HUD_STAT_NUMBER:
1685 pkt << *(u32 *) value;
1692 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1694 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1696 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1698 pkt << flags << mask;
1703 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1705 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1706 pkt << param << value;
1710 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1712 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1714 // Handle prior clients here
1715 if (m_clients.getProtocolVersion(peer_id) < 39) {
1716 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1718 for (const std::string& texture : params.textures)
1721 pkt << params.clouds;
1722 } else { // Handle current clients and future clients
1723 pkt << params.bgcolor << params.type
1724 << params.clouds << params.fog_sun_tint
1725 << params.fog_moon_tint << params.fog_tint_type;
1727 if (params.type == "skybox") {
1728 pkt << (u16) params.textures.size();
1729 for (const std::string &texture : params.textures)
1731 } else if (params.type == "regular") {
1732 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1733 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1734 << params.sky_color.night_sky << params.sky_color.night_horizon
1735 << params.sky_color.indoors;
1742 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1744 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1745 pkt << params.visible << params.texture
1746 << params.tonemap << params.sunrise
1747 << params.sunrise_visible << params.scale;
1751 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1753 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1755 pkt << params.visible << params.texture
1756 << params.tonemap << params.scale;
1760 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1762 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1764 pkt << params.visible << params.count
1765 << params.starcolor << params.scale;
1770 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1772 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1773 pkt << params.density << params.color_bright << params.color_ambient
1774 << params.height << params.thickness << params.speed;
1778 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1781 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1784 pkt << do_override << (u16) (ratio * 65535);
1789 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1791 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1792 pkt << time << time_speed;
1794 if (peer_id == PEER_ID_INEXISTENT) {
1795 m_clients.sendToAll(&pkt);
1802 void Server::SendPlayerHP(session_t peer_id)
1804 PlayerSAO *playersao = getPlayerSAO(peer_id);
1807 SendHP(peer_id, playersao->getHP());
1808 m_script->player_event(playersao,"health_changed");
1810 // Send to other clients
1811 playersao->sendPunchCommand();
1814 void Server::SendPlayerBreath(PlayerSAO *sao)
1818 m_script->player_event(sao, "breath_changed");
1819 SendBreath(sao->getPeerID(), sao->getBreath());
1822 void Server::SendMovePlayer(session_t peer_id)
1824 RemotePlayer *player = m_env->getPlayer(peer_id);
1826 PlayerSAO *sao = player->getPlayerSAO();
1829 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1830 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1833 v3f pos = sao->getBasePosition();
1834 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1835 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1836 << " pitch=" << sao->getLookPitch()
1837 << " yaw=" << sao->getRotation().Y
1844 void Server::SendPlayerFov(session_t peer_id)
1846 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1848 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1849 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1854 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1855 f32 animation_speed)
1857 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1860 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1861 << animation_frames[3] << animation_speed;
1866 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1868 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1869 pkt << first << third;
1873 void Server::SendPlayerPrivileges(session_t peer_id)
1875 RemotePlayer *player = m_env->getPlayer(peer_id);
1877 if(player->getPeerId() == PEER_ID_INEXISTENT)
1880 std::set<std::string> privs;
1881 m_script->getAuth(player->getName(), NULL, &privs);
1883 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1884 pkt << (u16) privs.size();
1886 for (const std::string &priv : privs) {
1893 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1895 RemotePlayer *player = m_env->getPlayer(peer_id);
1897 if (player->getPeerId() == PEER_ID_INEXISTENT)
1900 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1901 pkt.putLongString(player->inventory_formspec);
1906 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1908 RemotePlayer *player = m_env->getPlayer(peer_id);
1910 if (player->getPeerId() == PEER_ID_INEXISTENT)
1913 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1914 pkt << player->formspec_prepend;
1918 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1920 // Radius inside which objects are active
1921 static thread_local const s16 radius =
1922 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1924 // Radius inside which players are active
1925 static thread_local const bool is_transfer_limited =
1926 g_settings->exists("unlimited_player_transfer_distance") &&
1927 !g_settings->getBool("unlimited_player_transfer_distance");
1929 static thread_local const s16 player_transfer_dist =
1930 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1932 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1933 radius : player_transfer_dist;
1935 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1939 std::queue<u16> removed_objects, added_objects;
1940 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1941 client->m_known_objects, removed_objects);
1942 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1943 client->m_known_objects, added_objects);
1945 int removed_count = removed_objects.size();
1946 int added_count = added_objects.size();
1948 if (removed_objects.empty() && added_objects.empty())
1954 // Handle removed objects
1955 writeU16((u8*)buf, removed_objects.size());
1956 data.append(buf, 2);
1957 while (!removed_objects.empty()) {
1959 u16 id = removed_objects.front();
1960 ServerActiveObject* obj = m_env->getActiveObject(id);
1962 // Add to data buffer for sending
1963 writeU16((u8*)buf, id);
1964 data.append(buf, 2);
1966 // Remove from known objects
1967 client->m_known_objects.erase(id);
1969 if (obj && obj->m_known_by_count > 0)
1970 obj->m_known_by_count--;
1972 removed_objects.pop();
1975 // Handle added objects
1976 writeU16((u8*)buf, added_objects.size());
1977 data.append(buf, 2);
1978 while (!added_objects.empty()) {
1980 u16 id = added_objects.front();
1981 ServerActiveObject *obj = m_env->getActiveObject(id);
1982 added_objects.pop();
1985 warningstream << FUNCTION_NAME << ": NULL object id="
1986 << (int)id << std::endl;
1991 u8 type = obj->getSendType();
1993 // Add to data buffer for sending
1994 writeU16((u8*)buf, id);
1995 data.append(buf, 2);
1996 writeU8((u8*)buf, type);
1997 data.append(buf, 1);
1999 data.append(serializeString32(
2000 obj->getClientInitializationData(client->net_proto_version)));
2002 // Add to known objects
2003 client->m_known_objects.insert(id);
2005 obj->m_known_by_count++;
2008 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2009 pkt.putRawString(data.c_str(), data.size());
2012 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2013 << removed_count << " removed, " << added_count << " added, "
2014 << "packet size is " << pkt.getSize() << std::endl;
2017 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2020 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2021 datas.size(), peer_id);
2023 pkt.putRawString(datas.c_str(), datas.size());
2025 m_clients.send(pkt.getPeerId(),
2026 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2030 void Server::SendCSMRestrictionFlags(session_t peer_id)
2032 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2033 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2034 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2038 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2040 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2045 inline s32 Server::nextSoundId()
2047 s32 ret = m_next_sound_id;
2048 if (m_next_sound_id == INT32_MAX)
2049 m_next_sound_id = 0; // signed overflow is undefined
2055 s32 Server::playSound(const SimpleSoundSpec &spec,
2056 const ServerSoundParams ¶ms, bool ephemeral)
2058 // Find out initial position of sound
2059 bool pos_exists = false;
2060 v3f pos = params.getPos(m_env, &pos_exists);
2061 // If position is not found while it should be, cancel sound
2062 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2065 // Filter destination clients
2066 std::vector<session_t> dst_clients;
2067 if (!params.to_player.empty()) {
2068 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2070 infostream<<"Server::playSound: Player \""<<params.to_player
2071 <<"\" not found"<<std::endl;
2074 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2075 infostream<<"Server::playSound: Player \""<<params.to_player
2076 <<"\" not connected"<<std::endl;
2079 dst_clients.push_back(player->getPeerId());
2081 std::vector<session_t> clients = m_clients.getClientIDs();
2083 for (const session_t client_id : clients) {
2084 RemotePlayer *player = m_env->getPlayer(client_id);
2087 if (!params.exclude_player.empty() &&
2088 params.exclude_player == player->getName())
2091 PlayerSAO *sao = player->getPlayerSAO();
2096 if(sao->getBasePosition().getDistanceFrom(pos) >
2097 params.max_hear_distance)
2100 dst_clients.push_back(client_id);
2104 if(dst_clients.empty())
2109 ServerPlayingSound *psound = nullptr;
2111 id = -1; // old clients will still use this, so pick a reserved ID
2114 // The sound will exist as a reference in m_playing_sounds
2115 m_playing_sounds[id] = ServerPlayingSound();
2116 psound = &m_playing_sounds[id];
2117 psound->params = params;
2118 psound->spec = spec;
2121 float gain = params.gain * spec.gain;
2122 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2123 pkt << id << spec.name << gain
2124 << (u8) params.type << pos << params.object
2125 << params.loop << params.fade << params.pitch
2128 bool as_reliable = !ephemeral;
2130 for (const u16 dst_client : dst_clients) {
2132 psound->clients.insert(dst_client);
2133 m_clients.send(dst_client, 0, &pkt, as_reliable);
2137 void Server::stopSound(s32 handle)
2139 // Get sound reference
2140 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2141 m_playing_sounds.find(handle);
2142 if (i == m_playing_sounds.end())
2144 ServerPlayingSound &psound = i->second;
2146 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2149 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2150 si != psound.clients.end(); ++si) {
2152 m_clients.send(*si, 0, &pkt, true);
2154 // Remove sound reference
2155 m_playing_sounds.erase(i);
2158 void Server::fadeSound(s32 handle, float step, float gain)
2160 // Get sound reference
2161 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2162 m_playing_sounds.find(handle);
2163 if (i == m_playing_sounds.end())
2166 ServerPlayingSound &psound = i->second;
2167 psound.params.gain = gain;
2169 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2170 pkt << handle << step << gain;
2172 // Backwards compability
2173 bool play_sound = gain > 0;
2174 ServerPlayingSound compat_psound = psound;
2175 compat_psound.clients.clear();
2177 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2178 compat_pkt << handle;
2180 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2181 it != psound.clients.end();) {
2182 if (m_clients.getProtocolVersion(*it) >= 32) {
2184 m_clients.send(*it, 0, &pkt, true);
2187 compat_psound.clients.insert(*it);
2189 m_clients.send(*it, 0, &compat_pkt, true);
2190 psound.clients.erase(it++);
2194 // Remove sound reference
2195 if (!play_sound || psound.clients.empty())
2196 m_playing_sounds.erase(i);
2198 if (play_sound && !compat_psound.clients.empty()) {
2199 // Play new sound volume on older clients
2200 playSound(compat_psound.spec, compat_psound.params);
2204 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2207 float maxd = far_d_nodes * BS;
2208 v3f p_f = intToFloat(p, BS);
2209 v3s16 block_pos = getNodeBlockPos(p);
2211 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2214 std::vector<session_t> clients = m_clients.getClientIDs();
2217 for (session_t client_id : clients) {
2218 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2222 RemotePlayer *player = m_env->getPlayer(client_id);
2223 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2225 // If player is far away, only set modified blocks not sent
2226 if (!client->isBlockSent(block_pos) || (sao &&
2227 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2229 far_players->emplace(client_id);
2231 client->SetBlockNotSent(block_pos);
2236 m_clients.send(client_id, 0, &pkt, true);
2242 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2243 float far_d_nodes, bool remove_metadata)
2245 float maxd = far_d_nodes * BS;
2246 v3f p_f = intToFloat(p, BS);
2247 v3s16 block_pos = getNodeBlockPos(p);
2249 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2250 pkt << p << n.param0 << n.param1 << n.param2
2251 << (u8) (remove_metadata ? 0 : 1);
2253 std::vector<session_t> clients = m_clients.getClientIDs();
2256 for (session_t client_id : clients) {
2257 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2261 RemotePlayer *player = m_env->getPlayer(client_id);
2262 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2264 // If player is far away, only set modified blocks not sent
2265 if (!client->isBlockSent(block_pos) || (sao &&
2266 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2268 far_players->emplace(client_id);
2270 client->SetBlockNotSent(block_pos);
2275 m_clients.send(client_id, 0, &pkt, true);
2281 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2283 float maxd = far_d_nodes * BS;
2284 NodeMetadataList meta_updates_list(false);
2285 std::vector<session_t> clients = m_clients.getClientIDs();
2289 for (session_t i : clients) {
2290 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2294 ServerActiveObject *player = m_env->getActiveObject(i);
2295 v3f player_pos = player ? player->getBasePosition() : v3f();
2297 for (const v3s16 &pos : meta_updates) {
2298 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2303 v3s16 block_pos = getNodeBlockPos(pos);
2304 if (!client->isBlockSent(block_pos) || (player &&
2305 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2306 client->SetBlockNotSent(block_pos);
2310 // Add the change to send list
2311 meta_updates_list.set(pos, meta);
2313 if (meta_updates_list.size() == 0)
2316 // Send the meta changes
2317 std::ostringstream os(std::ios::binary);
2318 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2319 std::ostringstream oss(std::ios::binary);
2320 compressZlib(os.str(), oss);
2322 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2323 pkt.putLongString(oss.str());
2324 m_clients.send(i, 0, &pkt, true);
2326 meta_updates_list.clear();
2332 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2333 u16 net_proto_version)
2336 Create a packet with the block in the right format
2338 thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
2339 std::ostringstream os(std::ios_base::binary);
2340 block->serialize(os, ver, false, net_compression_level);
2341 block->serializeNetworkSpecific(os);
2342 std::string s = os.str();
2344 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + s.size(), peer_id);
2346 pkt << block->getPos();
2347 pkt.putRawString(s.c_str(), s.size());
2351 void Server::SendBlocks(float dtime)
2353 MutexAutoLock envlock(m_env_mutex);
2354 //TODO check if one big lock could be faster then multiple small ones
2356 std::vector<PrioritySortedBlockTransfer> queue;
2358 u32 total_sending = 0;
2361 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2363 std::vector<session_t> clients = m_clients.getClientIDs();
2366 for (const session_t client_id : clients) {
2367 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2372 total_sending += client->getSendingCount();
2373 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2379 // Lowest priority number comes first.
2380 // Lowest is most important.
2381 std::sort(queue.begin(), queue.end());
2385 // Maximal total count calculation
2386 // The per-client block sends is halved with the maximal online users
2387 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2388 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2390 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2391 Map &map = m_env->getMap();
2393 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2394 if (total_sending >= max_blocks_to_send)
2397 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2401 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2406 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2407 client->net_proto_version);
2409 client->SentBlock(block_to_send.pos);
2415 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2417 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2422 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2423 if (!client || client->isBlockSent(blockpos)) {
2427 SendBlockNoLock(peer_id, block, client->serialization_version,
2428 client->net_proto_version);
2434 bool Server::addMediaFile(const std::string &filename,
2435 const std::string &filepath, std::string *filedata_to,
2436 std::string *digest_to)
2438 // If name contains illegal characters, ignore the file
2439 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2440 infostream << "Server: ignoring illegal file name: \""
2441 << filename << "\"" << std::endl;
2444 // If name is not in a supported format, ignore it
2445 const char *supported_ext[] = {
2446 ".png", ".jpg", ".bmp", ".tga",
2447 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2449 ".x", ".b3d", ".md2", ".obj",
2450 // Custom translation file format
2454 if (removeStringEnd(filename, supported_ext).empty()) {
2455 infostream << "Server: ignoring unsupported file extension: \""
2456 << filename << "\"" << std::endl;
2459 // Ok, attempt to load the file and add to cache
2462 std::string filedata;
2463 if (!fs::ReadFile(filepath, filedata)) {
2464 errorstream << "Server::addMediaFile(): Failed to open \""
2465 << filename << "\" for reading" << std::endl;
2469 if (filedata.empty()) {
2470 errorstream << "Server::addMediaFile(): Empty file \""
2471 << filepath << "\"" << std::endl;
2476 sha1.addBytes(filedata.c_str(), filedata.length());
2478 unsigned char *digest = sha1.getDigest();
2479 std::string sha1_base64 = base64_encode(digest, 20);
2480 std::string sha1_hex = hex_encode((char*) digest, 20);
2482 *digest_to = std::string((char*) digest, 20);
2486 m_media[filename] = MediaInfo(filepath, sha1_base64);
2487 verbosestream << "Server: " << sha1_hex << " is " << filename
2491 *filedata_to = std::move(filedata);
2495 void Server::fillMediaCache()
2497 infostream << "Server: Calculating media file checksums" << std::endl;
2499 // Collect all media file paths
2500 std::vector<std::string> paths;
2501 // The paths are ordered in descending priority
2502 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2503 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2504 m_modmgr->getModsMediaPaths(paths);
2506 // Collect media file information from paths into cache
2507 for (const std::string &mediapath : paths) {
2508 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2509 for (const fs::DirListNode &dln : dirlist) {
2510 if (dln.dir) // Ignore dirs (already in paths)
2513 const std::string &filename = dln.name;
2514 if (m_media.find(filename) != m_media.end()) // Do not override
2517 std::string filepath = mediapath;
2518 filepath.append(DIR_DELIM).append(filename);
2519 addMediaFile(filename, filepath);
2523 infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2526 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2529 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2532 std::string lang_suffix;
2533 lang_suffix.append(".").append(lang_code).append(".tr");
2534 for (const auto &i : m_media) {
2535 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2542 for (const auto &i : m_media) {
2543 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2545 pkt << i.first << i.second.sha1_digest;
2548 pkt << g_settings->get("remote_media");
2551 verbosestream << "Server: Announcing files to id(" << peer_id
2552 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2555 struct SendableMedia
2561 SendableMedia(const std::string &name_="", const std::string &path_="",
2562 const std::string &data_=""):
2569 void Server::sendRequestedMedia(session_t peer_id,
2570 const std::vector<std::string> &tosend)
2572 verbosestream<<"Server::sendRequestedMedia(): "
2573 <<"Sending files to client"<<std::endl;
2577 // Put 5kB in one bunch (this is not accurate)
2578 u32 bytes_per_bunch = 5000;
2580 std::vector< std::vector<SendableMedia> > file_bunches;
2581 file_bunches.emplace_back();
2583 u32 file_size_bunch_total = 0;
2585 for (const std::string &name : tosend) {
2586 if (m_media.find(name) == m_media.end()) {
2587 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2588 <<"unknown file \""<<(name)<<"\""<<std::endl;
2592 //TODO get path + name
2593 std::string tpath = m_media[name].path;
2596 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2598 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2599 <<tpath<<"\" for reading"<<std::endl;
2602 std::ostringstream tmp_os(std::ios_base::binary);
2606 fis.read(buf, 1024);
2607 std::streamsize len = fis.gcount();
2608 tmp_os.write(buf, len);
2609 file_size_bunch_total += len;
2618 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2619 <<name<<"\""<<std::endl;
2622 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2623 <<tname<<"\""<<std::endl;*/
2625 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2627 // Start next bunch if got enough data
2628 if(file_size_bunch_total >= bytes_per_bunch) {
2629 file_bunches.emplace_back();
2630 file_size_bunch_total = 0;
2635 /* Create and send packets */
2637 u16 num_bunches = file_bunches.size();
2638 for (u16 i = 0; i < num_bunches; i++) {
2641 u16 total number of texture bunches
2642 u16 index of this bunch
2643 u32 number of files in this bunch
2652 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2653 pkt << num_bunches << i << (u32) file_bunches[i].size();
2655 for (const SendableMedia &j : file_bunches[i]) {
2657 pkt.putLongString(j.data);
2660 verbosestream << "Server::sendRequestedMedia(): bunch "
2661 << i << "/" << num_bunches
2662 << " files=" << file_bunches[i].size()
2663 << " size=" << pkt.getSize() << std::endl;
2668 void Server::SendMinimapModes(session_t peer_id,
2669 std::vector<MinimapMode> &modes, size_t wanted_mode)
2671 RemotePlayer *player = m_env->getPlayer(peer_id);
2673 if (player->getPeerId() == PEER_ID_INEXISTENT)
2676 NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2677 pkt << (u16)modes.size() << (u16)wanted_mode;
2679 for (auto &mode : modes)
2680 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2685 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2687 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2691 pkt << false; // Remove inventory
2693 pkt << true; // Update inventory
2695 // Serialization & NetworkPacket isn't a love story
2696 std::ostringstream os(std::ios_base::binary);
2697 inventory->serialize(os);
2698 inventory->setModified(false);
2700 const std::string &os_str = os.str();
2701 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2702 pkt.putRawString(os_str);
2705 if (peer_id == PEER_ID_INEXISTENT)
2706 m_clients.sendToAll(&pkt);
2711 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2713 // Lookup player name, to filter detached inventories just after
2714 std::string peer_name;
2715 if (peer_id != PEER_ID_INEXISTENT) {
2716 peer_name = getClient(peer_id, CS_Created)->getName();
2719 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2720 sendDetachedInventory(inv, name, peer_id);
2723 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2730 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2732 PlayerSAO *playersao = getPlayerSAO(peer_id);
2735 infostream << "Server::DiePlayer(): Player "
2736 << playersao->getPlayer()->getName()
2737 << " dies" << std::endl;
2739 playersao->setHP(0, reason);
2740 playersao->clearParentAttachment();
2742 // Trigger scripted stuff
2743 m_script->on_dieplayer(playersao, reason);
2745 SendPlayerHP(peer_id);
2746 SendDeathscreen(peer_id, false, v3f(0,0,0));
2749 void Server::RespawnPlayer(session_t peer_id)
2751 PlayerSAO *playersao = getPlayerSAO(peer_id);
2754 infostream << "Server::RespawnPlayer(): Player "
2755 << playersao->getPlayer()->getName()
2756 << " respawns" << std::endl;
2758 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2759 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2760 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2762 bool repositioned = m_script->on_respawnplayer(playersao);
2763 if (!repositioned) {
2764 // setPos will send the new position to client
2765 playersao->setPos(findSpawnPos());
2768 SendPlayerHP(peer_id);
2772 void Server::DenySudoAccess(session_t peer_id)
2774 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2779 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2780 const std::string &str_reason, bool reconnect)
2782 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2784 m_clients.event(peer_id, CSE_SetDenied);
2785 DisconnectPeer(peer_id);
2789 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2790 const std::string &custom_reason)
2792 SendAccessDenied(peer_id, reason, custom_reason);
2793 m_clients.event(peer_id, CSE_SetDenied);
2794 DisconnectPeer(peer_id);
2797 // 13/03/15: remove this function when protocol version 25 will become
2798 // the minimum version for MT users, maybe in 1 year
2799 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2801 SendAccessDenied_Legacy(peer_id, reason);
2802 m_clients.event(peer_id, CSE_SetDenied);
2803 DisconnectPeer(peer_id);
2806 void Server::DisconnectPeer(session_t peer_id)
2808 m_modchannel_mgr->leaveAllChannels(peer_id);
2809 m_con->DisconnectPeer(peer_id);
2812 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2815 RemoteClient* client = getClient(peer_id, CS_Invalid);
2817 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2819 // Right now, the auth mechs don't change between login and sudo mode.
2820 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2821 client->allowed_sudo_mechs = sudo_auth_mechs;
2823 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2824 << g_settings->getFloat("dedicated_server_step")
2828 m_clients.event(peer_id, CSE_AuthAccept);
2830 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2832 // We only support SRP right now
2833 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2835 resp_pkt << sudo_auth_mechs;
2837 m_clients.event(peer_id, CSE_SudoSuccess);
2841 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2843 std::wstring message;
2846 Clear references to playing sounds
2848 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2849 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2850 ServerPlayingSound &psound = i->second;
2851 psound.clients.erase(peer_id);
2852 if (psound.clients.empty())
2853 m_playing_sounds.erase(i++);
2858 // clear formspec info so the next client can't abuse the current state
2859 m_formspec_state_data.erase(peer_id);
2861 RemotePlayer *player = m_env->getPlayer(peer_id);
2863 /* Run scripts and remove from environment */
2865 PlayerSAO *playersao = player->getPlayerSAO();
2868 playersao->clearChildAttachments();
2869 playersao->clearParentAttachment();
2871 // inform connected clients
2872 const std::string &player_name = player->getName();
2873 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2874 // (u16) 1 + std::string represents a vector serialization representation
2875 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2876 m_clients.sendToAll(¬ice);
2878 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2880 playersao->disconnected();
2887 if (player && reason != CDR_DENY) {
2888 std::ostringstream os(std::ios_base::binary);
2889 std::vector<session_t> clients = m_clients.getClientIDs();
2891 for (const session_t client_id : clients) {
2893 RemotePlayer *player = m_env->getPlayer(client_id);
2897 // Get name of player
2898 os << player->getName() << " ";
2901 std::string name = player->getName();
2902 actionstream << name << " "
2903 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2904 << " List of players: " << os.str() << std::endl;
2906 m_admin_chat->outgoing_queue.push_back(
2907 new ChatEventNick(CET_NICK_REMOVE, name));
2911 MutexAutoLock env_lock(m_env_mutex);
2912 m_clients.DeleteClient(peer_id);
2916 // Send leave chat message to all remaining clients
2917 if (!message.empty()) {
2918 SendChatMessage(PEER_ID_INEXISTENT,
2919 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2923 void Server::UpdateCrafting(RemotePlayer *player)
2925 InventoryList *clist = player->inventory.getList("craft");
2926 if (!clist || clist->getSize() == 0)
2929 if (!clist->checkModified())
2932 // Get a preview for crafting
2934 InventoryLocation loc;
2935 loc.setPlayer(player->getName());
2936 std::vector<ItemStack> output_replacements;
2937 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2938 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2941 InventoryList *plist = player->inventory.getList("craftpreview");
2942 if (plist && plist->getSize() >= 1) {
2943 // Put the new preview in
2944 plist->changeItem(0, preview);
2948 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2950 if (evt->type == CET_NICK_ADD) {
2951 // The terminal informed us of its nick choice
2952 m_admin_nick = ((ChatEventNick *)evt)->nick;
2953 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2954 errorstream << "You haven't set up an account." << std::endl
2955 << "Please log in using the client as '"
2956 << m_admin_nick << "' with a secure password." << std::endl
2957 << "Until then, you can't execute admin tasks via the console," << std::endl
2958 << "and everybody can claim the user account instead of you," << std::endl
2959 << "giving them full control over this server." << std::endl;
2962 assert(evt->type == CET_CHAT);
2963 handleAdminChat((ChatEventChat *)evt);
2967 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2968 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2970 // If something goes wrong, this player is to blame
2971 RollbackScopeActor rollback_scope(m_rollback,
2972 std::string("player:") + name);
2974 if (g_settings->getBool("strip_color_codes"))
2975 wmessage = unescape_enriched(wmessage);
2978 switch (player->canSendChatMessage()) {
2979 case RPLAYER_CHATRESULT_FLOODING: {
2980 std::wstringstream ws;
2981 ws << L"You cannot send more messages. You are limited to "
2982 << g_settings->getFloat("chat_message_limit_per_10sec")
2983 << L" messages per 10 seconds.";
2986 case RPLAYER_CHATRESULT_KICK:
2987 DenyAccess_Legacy(player->getPeerId(),
2988 L"You have been kicked due to message flooding.");
2990 case RPLAYER_CHATRESULT_OK:
2993 FATAL_ERROR("Unhandled chat filtering result found.");
2997 if (m_max_chatmessage_length > 0
2998 && wmessage.length() > m_max_chatmessage_length) {
2999 return L"Your message exceed the maximum chat message limit set on the server. "
3000 L"It was refused. Send a shorter message";
3003 auto message = trim(wide_to_utf8(wmessage));
3004 if (message.find_first_of("\n\r") != std::wstring::npos) {
3005 return L"New lines are not permitted in chat messages";
3008 // Run script hook, exit if script ate the chat message
3009 if (m_script->on_chat_message(name, message))
3014 // Whether to send line to the player that sent the message, or to all players
3015 bool broadcast_line = true;
3017 if (check_shout_priv && !checkPriv(name, "shout")) {
3018 line += L"-!- You don't have permission to shout.";
3019 broadcast_line = false;
3022 Workaround for fixing chat on Android. Lua doesn't handle
3023 the Cyrillic alphabet and some characters on older Android devices
3026 line += L"<" + wname + L"> " + wmessage;
3028 line += narrow_to_wide(m_script->formatChatMessage(name,
3029 wide_to_narrow(wmessage)));
3034 Tell calling method to send the message to sender
3036 if (!broadcast_line)
3040 Send the message to others
3042 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
3044 std::vector<session_t> clients = m_clients.getClientIDs();
3047 Send the message back to the inital sender
3048 if they are using protocol version >= 29
3051 session_t peer_id_to_avoid_sending =
3052 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
3054 if (player && player->protocol_version >= 29)
3055 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
3057 for (u16 cid : clients) {
3058 if (cid != peer_id_to_avoid_sending)
3059 SendChatMessage(cid, ChatMessage(line));
3064 void Server::handleAdminChat(const ChatEventChat *evt)
3066 std::string name = evt->nick;
3067 std::wstring wname = utf8_to_wide(name);
3068 std::wstring wmessage = evt->evt_msg;
3070 std::wstring answer = handleChat(name, wname, wmessage);
3072 // If asked to send answer to sender
3073 if (!answer.empty()) {
3074 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3078 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3080 RemoteClient *client = getClientNoEx(peer_id,state_min);
3082 throw ClientNotFoundException("Client not found");
3086 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3088 return m_clients.getClientNoEx(peer_id, state_min);
3091 std::string Server::getPlayerName(session_t peer_id)
3093 RemotePlayer *player = m_env->getPlayer(peer_id);
3095 return "[id="+itos(peer_id)+"]";
3096 return player->getName();
3099 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3101 RemotePlayer *player = m_env->getPlayer(peer_id);
3104 return player->getPlayerSAO();
3107 std::wstring Server::getStatusString()
3109 std::wostringstream os(std::ios_base::binary);
3110 os << L"# Server: ";
3112 os << L"version=" << narrow_to_wide(g_version_string);
3114 os << L", uptime=" << m_uptime_counter->get();
3116 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3118 // Information about clients
3120 os << L", clients={";
3122 std::vector<session_t> clients = m_clients.getClientIDs();
3123 for (session_t client_id : clients) {
3124 RemotePlayer *player = m_env->getPlayer(client_id);
3126 // Get name of player
3127 std::wstring name = L"unknown";
3129 name = narrow_to_wide(player->getName());
3131 // Add name to information string
3142 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3143 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3145 if (!g_settings->get("motd").empty())
3146 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3151 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3153 std::set<std::string> privs;
3154 m_script->getAuth(name, NULL, &privs);
3158 bool Server::checkPriv(const std::string &name, const std::string &priv)
3160 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3161 return (privs.count(priv) != 0);
3164 void Server::reportPrivsModified(const std::string &name)
3167 std::vector<session_t> clients = m_clients.getClientIDs();
3168 for (const session_t client_id : clients) {
3169 RemotePlayer *player = m_env->getPlayer(client_id);
3170 reportPrivsModified(player->getName());
3173 RemotePlayer *player = m_env->getPlayer(name.c_str());
3176 SendPlayerPrivileges(player->getPeerId());
3177 PlayerSAO *sao = player->getPlayerSAO();
3180 sao->updatePrivileges(
3181 getPlayerEffectivePrivs(name),
3186 void Server::reportInventoryFormspecModified(const std::string &name)
3188 RemotePlayer *player = m_env->getPlayer(name.c_str());
3191 SendPlayerInventoryFormspec(player->getPeerId());
3194 void Server::reportFormspecPrependModified(const std::string &name)
3196 RemotePlayer *player = m_env->getPlayer(name.c_str());
3199 SendPlayerFormspecPrepend(player->getPeerId());
3202 void Server::setIpBanned(const std::string &ip, const std::string &name)
3204 m_banmanager->add(ip, name);
3207 void Server::unsetIpBanned(const std::string &ip_or_name)
3209 m_banmanager->remove(ip_or_name);
3212 std::string Server::getBanDescription(const std::string &ip_or_name)
3214 return m_banmanager->getBanDescription(ip_or_name);
3217 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3219 // m_env will be NULL if the server is initializing
3223 if (m_admin_nick == name && !m_admin_nick.empty()) {
3224 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3227 RemotePlayer *player = m_env->getPlayer(name);
3232 if (player->getPeerId() == PEER_ID_INEXISTENT)
3235 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3238 bool Server::showFormspec(const char *playername, const std::string &formspec,
3239 const std::string &formname)
3241 // m_env will be NULL if the server is initializing
3245 RemotePlayer *player = m_env->getPlayer(playername);
3249 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3253 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3258 u32 id = player->addHud(form);
3260 SendHUDAdd(player->getPeerId(), id, form);
3265 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3269 HudElement* todel = player->removeHud(id);
3276 SendHUDRemove(player->getPeerId(), id);
3280 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3285 SendHUDChange(player->getPeerId(), id, stat, data);
3289 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3294 SendHUDSetFlags(player->getPeerId(), flags, mask);
3295 player->hud_flags &= ~mask;
3296 player->hud_flags |= flags;
3298 PlayerSAO* playersao = player->getPlayerSAO();
3303 m_script->player_event(playersao, "hud_changed");
3307 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3312 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3315 player->setHotbarItemcount(hotbar_itemcount);
3316 std::ostringstream os(std::ios::binary);
3317 writeS32(os, hotbar_itemcount);
3318 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3322 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3327 player->setHotbarImage(name);
3328 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3331 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3336 player->setHotbarSelectedImage(name);
3337 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3340 Address Server::getPeerAddress(session_t peer_id)
3342 return m_con->GetPeerAddress(peer_id);
3345 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3346 v2s32 animation_frames[4], f32 frame_speed)
3348 sanity_check(player);
3349 player->setLocalAnimations(animation_frames, frame_speed);
3350 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3353 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3355 sanity_check(player);
3356 player->eye_offset_first = first;
3357 player->eye_offset_third = third;
3358 SendEyeOffset(player->getPeerId(), first, third);
3361 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3363 sanity_check(player);
3364 player->setSky(params);
3365 SendSetSky(player->getPeerId(), params);
3368 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3370 sanity_check(player);
3371 player->setSun(params);
3372 SendSetSun(player->getPeerId(), params);
3375 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3377 sanity_check(player);
3378 player->setMoon(params);
3379 SendSetMoon(player->getPeerId(), params);
3382 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3384 sanity_check(player);
3385 player->setStars(params);
3386 SendSetStars(player->getPeerId(), params);
3389 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3391 sanity_check(player);
3392 player->setCloudParams(params);
3393 SendCloudParams(player->getPeerId(), params);
3396 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3399 sanity_check(player);
3400 player->overrideDayNightRatio(do_override, ratio);
3401 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3404 void Server::notifyPlayers(const std::wstring &msg)
3406 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3409 void Server::spawnParticle(const std::string &playername,
3410 const ParticleParameters &p)
3412 // m_env will be NULL if the server is initializing
3416 session_t peer_id = PEER_ID_INEXISTENT;
3418 if (!playername.empty()) {
3419 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3422 peer_id = player->getPeerId();
3423 proto_ver = player->protocol_version;
3426 SendSpawnParticle(peer_id, proto_ver, p);
3429 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3430 ServerActiveObject *attached, const std::string &playername)
3432 // m_env will be NULL if the server is initializing
3436 session_t peer_id = PEER_ID_INEXISTENT;
3438 if (!playername.empty()) {
3439 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3442 peer_id = player->getPeerId();
3443 proto_ver = player->protocol_version;
3446 u16 attached_id = attached ? attached->getId() : 0;
3449 if (attached_id == 0)
3450 id = m_env->addParticleSpawner(p.time);
3452 id = m_env->addParticleSpawner(p.time, attached_id);
3454 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3458 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3460 // m_env will be NULL if the server is initializing
3462 throw ServerError("Can't delete particle spawners during initialisation!");
3464 session_t peer_id = PEER_ID_INEXISTENT;
3465 if (!playername.empty()) {
3466 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3469 peer_id = player->getPeerId();
3472 m_env->deleteParticleSpawner(id);
3473 SendDeleteParticleSpawner(peer_id, id);
3476 bool Server::dynamicAddMedia(const std::string &filepath)
3478 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3479 if (m_media.find(filename) != m_media.end()) {
3480 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3481 << "\" already exists in media cache" << std::endl;
3485 // Load the file and add it to our media cache
3486 std::string filedata, raw_hash;
3487 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3491 // Push file to existing clients
3492 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3493 pkt << raw_hash << filename << (bool) true;
3494 pkt.putLongString(filedata);
3496 auto client_ids = m_clients.getClientIDs(CS_DefinitionsSent);
3497 for (session_t client_id : client_ids) {
3499 The network layer only guarantees ordered delivery inside a channel.
3500 Since the very next packet could be one that uses the media, we have
3501 to push the media over ALL channels to ensure it is processed before
3503 In practice this means we have to send it twice:
3505 - channel 0 (everything else: e.g. play_sound, object messages)
3507 m_clients.send(client_id, 1, &pkt, true);
3508 m_clients.send(client_id, 0, &pkt, true);
3514 // actions: time-reversed list
3515 // Return value: success/failure
3516 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3517 std::list<std::string> *log)
3519 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3520 ServerMap *map = (ServerMap*)(&m_env->getMap());
3522 // Fail if no actions to handle
3523 if (actions.empty()) {
3525 log->push_back("Nothing to do.");
3532 for (const RollbackAction &action : actions) {
3534 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3537 std::ostringstream os;
3538 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3539 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3541 log->push_back(os.str());
3543 std::ostringstream os;
3544 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3545 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3547 log->push_back(os.str());
3551 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3552 <<" failed"<<std::endl;
3554 // Call it done if less than half failed
3555 return num_failed <= num_tried/2;
3558 // IGameDef interface
3560 IItemDefManager *Server::getItemDefManager()
3565 const NodeDefManager *Server::getNodeDefManager()
3570 ICraftDefManager *Server::getCraftDefManager()
3575 u16 Server::allocateUnknownNodeId(const std::string &name)
3577 return m_nodedef->allocateDummy(name);
3580 IWritableItemDefManager *Server::getWritableItemDefManager()
3585 NodeDefManager *Server::getWritableNodeDefManager()
3590 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3595 const std::vector<ModSpec> & Server::getMods() const
3597 return m_modmgr->getMods();
3600 const ModSpec *Server::getModSpec(const std::string &modname) const
3602 return m_modmgr->getModSpec(modname);
3605 void Server::getModNames(std::vector<std::string> &modlist)
3607 m_modmgr->getModNames(modlist);
3610 std::string Server::getBuiltinLuaPath()
3612 return porting::path_share + DIR_DELIM + "builtin";
3615 std::string Server::getModStoragePath() const
3617 return m_path_world + DIR_DELIM + "mod_storage";
3620 v3f Server::findSpawnPos()
3622 ServerMap &map = m_env->getServerMap();
3624 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3625 return nodeposf * BS;
3627 bool is_good = false;
3628 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3629 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3631 // Try to find a good place a few times
3632 for (s32 i = 0; i < 4000 && !is_good; i++) {
3633 s32 range = MYMIN(1 + i, range_max);
3634 // We're going to try to throw the player to this position
3635 v2s16 nodepos2d = v2s16(
3636 -range + (myrand() % (range * 2)),
3637 -range + (myrand() % (range * 2)));
3638 // Get spawn level at point
3639 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3640 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3641 // signify an unsuitable spawn position, or if outside limits.
3642 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3643 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3646 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3647 // Consecutive empty nodes
3650 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3651 // avoid obstructions in already-generated mapblocks.
3652 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3653 // no obstructions, but mapgen decorations are generated after spawn so
3654 // the player may end up inside one.
3655 for (s32 i = 0; i < 8; i++) {
3656 v3s16 blockpos = getNodeBlockPos(nodepos);
3657 map.emergeBlock(blockpos, true);
3658 content_t c = map.getNode(nodepos).getContent();
3660 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3661 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3662 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3664 if (air_count >= 2) {
3665 // Spawn in lower empty node
3667 nodeposf = intToFloat(nodepos, BS);
3668 // Don't spawn the player outside map boundaries
3669 if (objectpos_over_limit(nodeposf))
3670 // Exit this loop, positions above are probably over limit
3673 // Good position found, cause an exit from main loop
3687 // No suitable spawn point found, return fallback 0,0,0
3688 return v3f(0.0f, 0.0f, 0.0f);
3691 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3693 if (delay == 0.0f) {
3694 // No delay, shutdown immediately
3695 m_shutdown_state.is_requested = true;
3696 // only print to the infostream, a chat message saying
3697 // "Server Shutting Down" is sent when the server destructs.
3698 infostream << "*** Immediate Server shutdown requested." << std::endl;
3699 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3700 // Negative delay, cancel shutdown if requested
3701 m_shutdown_state.reset();
3702 std::wstringstream ws;
3704 ws << L"*** Server shutdown canceled.";
3706 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3707 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3708 // m_shutdown_* are already handled, skip.
3710 } else if (delay > 0.0f) {
3711 // Positive delay, tell the clients when the server will shut down
3712 std::wstringstream ws;
3714 ws << L"*** Server shutting down in "
3715 << duration_to_string(myround(delay)).c_str()
3718 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3719 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3722 m_shutdown_state.trigger(delay, msg, reconnect);
3725 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3728 Try to get an existing player
3730 RemotePlayer *player = m_env->getPlayer(name);
3732 // If player is already connected, cancel
3733 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3734 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3739 If player with the wanted peer_id already exists, cancel.
3741 if (m_env->getPlayer(peer_id)) {
3742 infostream<<"emergePlayer(): Player with wrong name but same"
3743 " peer_id already exists"<<std::endl;
3748 player = new RemotePlayer(name, idef());
3751 bool newplayer = false;
3754 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3756 // Complete init with server parts
3757 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3758 player->protocol_version = proto_version;
3762 m_script->on_newplayer(playersao);
3768 bool Server::registerModStorage(ModMetadata *storage)
3770 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3771 errorstream << "Unable to register same mod storage twice. Storage name: "
3772 << storage->getModName() << std::endl;
3776 m_mod_storages[storage->getModName()] = storage;
3780 void Server::unregisterModStorage(const std::string &name)
3782 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3783 if (it != m_mod_storages.end()) {
3784 // Save unconditionaly on unregistration
3785 it->second->save(getModStoragePath());
3786 m_mod_storages.erase(name);
3790 void dedicated_server_loop(Server &server, bool &kill)
3792 verbosestream<<"dedicated_server_loop()"<<std::endl;
3794 IntervalLimiter m_profiler_interval;
3796 static thread_local const float steplen =
3797 g_settings->getFloat("dedicated_server_step");
3798 static thread_local const float profiler_print_interval =
3799 g_settings->getFloat("profiler_print_interval");
3802 * The dedicated server loop only does time-keeping (in Server::step) and
3803 * provides a way to main.cpp to kill the server externally (bool &kill).
3807 // This is kind of a hack but can be done like this
3808 // because server.step() is very light
3809 sleep_ms((int)(steplen*1000.0));
3810 server.step(steplen);
3812 if (server.isShutdownRequested() || kill)
3818 if (profiler_print_interval != 0) {
3819 if(m_profiler_interval.step(steplen, profiler_print_interval))
3821 infostream<<"Profiler:"<<std::endl;
3822 g_profiler->print(infostream);
3823 g_profiler->clear();
3828 infostream << "Dedicated server quitting" << std::endl;
3830 if (g_settings->getBool("server_announce"))
3831 ServerList::sendAnnounce(ServerList::AA_DELETE,
3832 server.m_bind_addr.getPort());
3841 bool Server::joinModChannel(const std::string &channel)
3843 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3844 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3847 bool Server::leaveModChannel(const std::string &channel)
3849 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3852 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3854 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3857 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3861 ModChannel* Server::getModChannel(const std::string &channel)
3863 return m_modchannel_mgr->getModChannel(channel);
3866 void Server::broadcastModChannelMessage(const std::string &channel,
3867 const std::string &message, session_t from_peer)
3869 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3873 if (message.size() > STRING_MAX_LEN) {
3874 warningstream << "ModChannel message too long, dropping before sending "
3875 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3876 << channel << ")" << std::endl;
3881 if (from_peer != PEER_ID_SERVER) {
3882 sender = getPlayerName(from_peer);
3885 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3886 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3887 resp_pkt << channel << sender << message;
3888 for (session_t peer_id : peers) {
3890 if (peer_id == from_peer)
3893 Send(peer_id, &resp_pkt);
3896 if (from_peer != PEER_ID_SERVER) {
3897 m_script->on_modchannel_message(channel, sender, message);
3901 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3903 if (lang_code.empty())
3906 auto it = server_translations.find(lang_code);
3907 if (it != server_translations.end())
3908 return &it->second; // Already loaded
3910 // [] will create an entry
3911 auto *translations = &server_translations[lang_code];
3913 std::string suffix = "." + lang_code + ".tr";
3914 for (const auto &i : m_media) {
3915 if (str_ends_with(i.first, suffix)) {
3917 if (fs::ReadFile(i.second.path, data)) {
3918 translations->loadTranslation(data);
3923 return translations;