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(session_t peer_id, ClientInfo &ret)
1248 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1255 ret.state = client->getState();
1256 ret.addr = client->getAddress();
1257 ret.uptime = client->uptime();
1258 ret.ser_vers = client->serialization_version;
1259 ret.prot_vers = client->net_proto_version;
1261 ret.major = client->getMajor();
1262 ret.minor = client->getMinor();
1263 ret.patch = client->getPatch();
1264 ret.vers_string = client->getFullVer();
1266 ret.lang_code = client->getLangCode();
1273 void Server::handlePeerChanges()
1275 while(!m_peer_change_queue.empty())
1277 con::PeerChange c = m_peer_change_queue.front();
1278 m_peer_change_queue.pop();
1280 verbosestream<<"Server: Handling peer change: "
1281 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1286 case con::PEER_ADDED:
1287 m_clients.CreateClient(c.peer_id);
1290 case con::PEER_REMOVED:
1291 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1295 FATAL_ERROR("Invalid peer change event received!");
1301 void Server::printToConsoleOnly(const std::string &text)
1304 m_admin_chat->outgoing_queue.push_back(
1305 new ChatEventChat("", utf8_to_wide(text)));
1307 std::cout << text << std::endl;
1311 void Server::Send(NetworkPacket *pkt)
1313 Send(pkt->getPeerId(), pkt);
1316 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1318 m_clients.send(peer_id,
1319 clientCommandFactoryTable[pkt->getCommand()].channel,
1321 clientCommandFactoryTable[pkt->getCommand()].reliable);
1324 void Server::SendMovement(session_t peer_id)
1326 std::ostringstream os(std::ios_base::binary);
1328 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1330 pkt << g_settings->getFloat("movement_acceleration_default");
1331 pkt << g_settings->getFloat("movement_acceleration_air");
1332 pkt << g_settings->getFloat("movement_acceleration_fast");
1333 pkt << g_settings->getFloat("movement_speed_walk");
1334 pkt << g_settings->getFloat("movement_speed_crouch");
1335 pkt << g_settings->getFloat("movement_speed_fast");
1336 pkt << g_settings->getFloat("movement_speed_climb");
1337 pkt << g_settings->getFloat("movement_speed_jump");
1338 pkt << g_settings->getFloat("movement_liquid_fluidity");
1339 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1340 pkt << g_settings->getFloat("movement_liquid_sink");
1341 pkt << g_settings->getFloat("movement_gravity");
1346 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1348 if (playersao->isImmortal())
1351 session_t peer_id = playersao->getPeerID();
1352 bool is_alive = !playersao->isDead();
1355 SendPlayerHP(peer_id);
1357 DiePlayer(peer_id, reason);
1360 void Server::SendHP(session_t peer_id, u16 hp)
1362 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1367 void Server::SendBreath(session_t peer_id, u16 breath)
1369 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1370 pkt << (u16) breath;
1374 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1375 const std::string &custom_reason, bool reconnect)
1377 assert(reason < SERVER_ACCESSDENIED_MAX);
1379 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1381 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1382 pkt << custom_reason;
1383 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1384 reason == SERVER_ACCESSDENIED_CRASH)
1385 pkt << custom_reason << (u8)reconnect;
1389 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1391 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1396 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1397 v3f camera_point_target)
1399 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1400 pkt << set_camera_point_target << camera_point_target;
1404 void Server::SendItemDef(session_t peer_id,
1405 IItemDefManager *itemdef, u16 protocol_version)
1407 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1411 u32 length of the next item
1412 zlib-compressed serialized ItemDefManager
1414 std::ostringstream tmp_os(std::ios::binary);
1415 itemdef->serialize(tmp_os, protocol_version);
1416 std::ostringstream tmp_os2(std::ios::binary);
1417 compressZlib(tmp_os.str(), tmp_os2);
1418 pkt.putLongString(tmp_os2.str());
1421 verbosestream << "Server: Sending item definitions to id(" << peer_id
1422 << "): size=" << pkt.getSize() << std::endl;
1427 void Server::SendNodeDef(session_t peer_id,
1428 const NodeDefManager *nodedef, u16 protocol_version)
1430 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1434 u32 length of the next item
1435 zlib-compressed serialized NodeDefManager
1437 std::ostringstream tmp_os(std::ios::binary);
1438 nodedef->serialize(tmp_os, protocol_version);
1439 std::ostringstream tmp_os2(std::ios::binary);
1440 compressZlib(tmp_os.str(), tmp_os2);
1442 pkt.putLongString(tmp_os2.str());
1445 verbosestream << "Server: Sending node definitions to id(" << peer_id
1446 << "): size=" << pkt.getSize() << std::endl;
1452 Non-static send methods
1455 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1457 RemotePlayer *player = sao->getPlayer();
1459 // Do not send new format to old clients
1460 incremental &= player->protocol_version >= 38;
1462 UpdateCrafting(player);
1468 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1470 std::ostringstream os(std::ios::binary);
1471 sao->getInventory()->serialize(os, incremental);
1472 sao->getInventory()->setModified(false);
1473 player->setModified(true);
1475 const std::string &s = os.str();
1476 pkt.putRawString(s.c_str(), s.size());
1480 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1482 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1484 u8 type = message.type;
1485 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1487 if (peer_id != PEER_ID_INEXISTENT) {
1488 RemotePlayer *player = m_env->getPlayer(peer_id);
1494 m_clients.sendToAll(&pkt);
1498 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1499 const std::string &formname)
1501 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1502 if (formspec.empty()){
1503 //the client should close the formspec
1504 //but make sure there wasn't another one open in meantime
1505 const auto it = m_formspec_state_data.find(peer_id);
1506 if (it != m_formspec_state_data.end() && it->second == formname) {
1507 m_formspec_state_data.erase(peer_id);
1509 pkt.putLongString("");
1511 m_formspec_state_data[peer_id] = formname;
1512 pkt.putLongString(formspec);
1519 // Spawns a particle on peer with peer_id
1520 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1521 const ParticleParameters &p)
1523 static thread_local const float radius =
1524 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1526 if (peer_id == PEER_ID_INEXISTENT) {
1527 std::vector<session_t> clients = m_clients.getClientIDs();
1528 const v3f pos = p.pos * BS;
1529 const float radius_sq = radius * radius;
1531 for (const session_t client_id : clients) {
1532 RemotePlayer *player = m_env->getPlayer(client_id);
1536 PlayerSAO *sao = player->getPlayerSAO();
1540 // Do not send to distant clients
1541 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1544 SendSpawnParticle(client_id, player->protocol_version, p);
1548 assert(protocol_version != 0);
1550 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1553 // NetworkPacket and iostreams are incompatible...
1554 std::ostringstream oss(std::ios_base::binary);
1555 p.serialize(oss, protocol_version);
1556 pkt.putRawString(oss.str());
1562 // Adds a ParticleSpawner on peer with peer_id
1563 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1564 const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1566 static thread_local const float radius =
1567 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1569 if (peer_id == PEER_ID_INEXISTENT) {
1570 std::vector<session_t> clients = m_clients.getClientIDs();
1571 const v3f pos = (p.minpos + p.maxpos) / 2.0f * BS;
1572 const float radius_sq = radius * radius;
1573 /* Don't send short-lived spawners to distant players.
1574 * This could be replaced with proper tracking at some point. */
1575 const bool distance_check = !attached_id && p.time <= 1.0f;
1577 for (const session_t client_id : clients) {
1578 RemotePlayer *player = m_env->getPlayer(client_id);
1582 if (distance_check) {
1583 PlayerSAO *sao = player->getPlayerSAO();
1586 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1590 SendAddParticleSpawner(client_id, player->protocol_version,
1591 p, attached_id, id);
1595 assert(protocol_version != 0);
1597 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1599 pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
1600 << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
1601 << p.minsize << p.maxsize << p.collisiondetection;
1603 pkt.putLongString(p.texture);
1605 pkt << id << p.vertical << p.collision_removal << attached_id;
1607 std::ostringstream os(std::ios_base::binary);
1608 p.animation.serialize(os, protocol_version);
1609 pkt.putRawString(os.str());
1611 pkt << p.glow << p.object_collision;
1612 pkt << p.node.param0 << p.node.param2 << p.node_tile;
1617 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1619 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1623 if (peer_id != PEER_ID_INEXISTENT)
1626 m_clients.sendToAll(&pkt);
1630 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1632 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1634 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1635 << form->text << form->number << form->item << form->dir
1636 << form->align << form->offset << form->world_pos << form->size
1637 << form->z_index << form->text2;
1642 void Server::SendHUDRemove(session_t peer_id, u32 id)
1644 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1649 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1651 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1652 pkt << id << (u8) stat;
1656 case HUD_STAT_SCALE:
1657 case HUD_STAT_ALIGN:
1658 case HUD_STAT_OFFSET:
1659 pkt << *(v2f *) value;
1663 case HUD_STAT_TEXT2:
1664 pkt << *(std::string *) value;
1666 case HUD_STAT_WORLD_POS:
1667 pkt << *(v3f *) value;
1670 pkt << *(v2s32 *) value;
1672 case HUD_STAT_NUMBER:
1676 pkt << *(u32 *) value;
1683 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1685 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1687 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1689 pkt << flags << mask;
1694 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1696 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1697 pkt << param << value;
1701 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1703 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1705 // Handle prior clients here
1706 if (m_clients.getProtocolVersion(peer_id) < 39) {
1707 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1709 for (const std::string& texture : params.textures)
1712 pkt << params.clouds;
1713 } else { // Handle current clients and future clients
1714 pkt << params.bgcolor << params.type
1715 << params.clouds << params.fog_sun_tint
1716 << params.fog_moon_tint << params.fog_tint_type;
1718 if (params.type == "skybox") {
1719 pkt << (u16) params.textures.size();
1720 for (const std::string &texture : params.textures)
1722 } else if (params.type == "regular") {
1723 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1724 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1725 << params.sky_color.night_sky << params.sky_color.night_horizon
1726 << params.sky_color.indoors;
1733 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1735 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1736 pkt << params.visible << params.texture
1737 << params.tonemap << params.sunrise
1738 << params.sunrise_visible << params.scale;
1742 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1744 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1746 pkt << params.visible << params.texture
1747 << params.tonemap << params.scale;
1751 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1753 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1755 pkt << params.visible << params.count
1756 << params.starcolor << params.scale;
1761 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1763 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1764 pkt << params.density << params.color_bright << params.color_ambient
1765 << params.height << params.thickness << params.speed;
1769 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1772 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1775 pkt << do_override << (u16) (ratio * 65535);
1780 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1782 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1783 pkt << time << time_speed;
1785 if (peer_id == PEER_ID_INEXISTENT) {
1786 m_clients.sendToAll(&pkt);
1793 void Server::SendPlayerHP(session_t peer_id)
1795 PlayerSAO *playersao = getPlayerSAO(peer_id);
1798 SendHP(peer_id, playersao->getHP());
1799 m_script->player_event(playersao,"health_changed");
1801 // Send to other clients
1802 playersao->sendPunchCommand();
1805 void Server::SendPlayerBreath(PlayerSAO *sao)
1809 m_script->player_event(sao, "breath_changed");
1810 SendBreath(sao->getPeerID(), sao->getBreath());
1813 void Server::SendMovePlayer(session_t peer_id)
1815 RemotePlayer *player = m_env->getPlayer(peer_id);
1817 PlayerSAO *sao = player->getPlayerSAO();
1820 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1821 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1824 v3f pos = sao->getBasePosition();
1825 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1826 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1827 << " pitch=" << sao->getLookPitch()
1828 << " yaw=" << sao->getRotation().Y
1835 void Server::SendPlayerFov(session_t peer_id)
1837 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1839 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1840 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1845 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1846 f32 animation_speed)
1848 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1851 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1852 << animation_frames[3] << animation_speed;
1857 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1859 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1860 pkt << first << third;
1864 void Server::SendPlayerPrivileges(session_t peer_id)
1866 RemotePlayer *player = m_env->getPlayer(peer_id);
1868 if(player->getPeerId() == PEER_ID_INEXISTENT)
1871 std::set<std::string> privs;
1872 m_script->getAuth(player->getName(), NULL, &privs);
1874 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1875 pkt << (u16) privs.size();
1877 for (const std::string &priv : privs) {
1884 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1886 RemotePlayer *player = m_env->getPlayer(peer_id);
1888 if (player->getPeerId() == PEER_ID_INEXISTENT)
1891 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1892 pkt.putLongString(player->inventory_formspec);
1897 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1899 RemotePlayer *player = m_env->getPlayer(peer_id);
1901 if (player->getPeerId() == PEER_ID_INEXISTENT)
1904 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1905 pkt << player->formspec_prepend;
1909 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1911 // Radius inside which objects are active
1912 static thread_local const s16 radius =
1913 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1915 // Radius inside which players are active
1916 static thread_local const bool is_transfer_limited =
1917 g_settings->exists("unlimited_player_transfer_distance") &&
1918 !g_settings->getBool("unlimited_player_transfer_distance");
1920 static thread_local const s16 player_transfer_dist =
1921 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1923 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1924 radius : player_transfer_dist;
1926 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1930 std::queue<u16> removed_objects, added_objects;
1931 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1932 client->m_known_objects, removed_objects);
1933 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1934 client->m_known_objects, added_objects);
1936 int removed_count = removed_objects.size();
1937 int added_count = added_objects.size();
1939 if (removed_objects.empty() && added_objects.empty())
1945 // Handle removed objects
1946 writeU16((u8*)buf, removed_objects.size());
1947 data.append(buf, 2);
1948 while (!removed_objects.empty()) {
1950 u16 id = removed_objects.front();
1951 ServerActiveObject* obj = m_env->getActiveObject(id);
1953 // Add to data buffer for sending
1954 writeU16((u8*)buf, id);
1955 data.append(buf, 2);
1957 // Remove from known objects
1958 client->m_known_objects.erase(id);
1960 if (obj && obj->m_known_by_count > 0)
1961 obj->m_known_by_count--;
1963 removed_objects.pop();
1966 // Handle added objects
1967 writeU16((u8*)buf, added_objects.size());
1968 data.append(buf, 2);
1969 while (!added_objects.empty()) {
1971 u16 id = added_objects.front();
1972 ServerActiveObject *obj = m_env->getActiveObject(id);
1973 added_objects.pop();
1976 warningstream << FUNCTION_NAME << ": NULL object id="
1977 << (int)id << std::endl;
1982 u8 type = obj->getSendType();
1984 // Add to data buffer for sending
1985 writeU16((u8*)buf, id);
1986 data.append(buf, 2);
1987 writeU8((u8*)buf, type);
1988 data.append(buf, 1);
1990 data.append(serializeString32(
1991 obj->getClientInitializationData(client->net_proto_version)));
1993 // Add to known objects
1994 client->m_known_objects.insert(id);
1996 obj->m_known_by_count++;
1999 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2000 pkt.putRawString(data.c_str(), data.size());
2003 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2004 << removed_count << " removed, " << added_count << " added, "
2005 << "packet size is " << pkt.getSize() << std::endl;
2008 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2011 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2012 datas.size(), peer_id);
2014 pkt.putRawString(datas.c_str(), datas.size());
2016 m_clients.send(pkt.getPeerId(),
2017 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2021 void Server::SendCSMRestrictionFlags(session_t peer_id)
2023 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2024 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2025 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2029 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2031 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2036 inline s32 Server::nextSoundId()
2038 s32 ret = m_next_sound_id;
2039 if (m_next_sound_id == INT32_MAX)
2040 m_next_sound_id = 0; // signed overflow is undefined
2046 s32 Server::playSound(const SimpleSoundSpec &spec,
2047 const ServerSoundParams ¶ms, bool ephemeral)
2049 // Find out initial position of sound
2050 bool pos_exists = false;
2051 v3f pos = params.getPos(m_env, &pos_exists);
2052 // If position is not found while it should be, cancel sound
2053 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2056 // Filter destination clients
2057 std::vector<session_t> dst_clients;
2058 if (!params.to_player.empty()) {
2059 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2061 infostream<<"Server::playSound: Player \""<<params.to_player
2062 <<"\" not found"<<std::endl;
2065 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2066 infostream<<"Server::playSound: Player \""<<params.to_player
2067 <<"\" not connected"<<std::endl;
2070 dst_clients.push_back(player->getPeerId());
2072 std::vector<session_t> clients = m_clients.getClientIDs();
2074 for (const session_t client_id : clients) {
2075 RemotePlayer *player = m_env->getPlayer(client_id);
2078 if (!params.exclude_player.empty() &&
2079 params.exclude_player == player->getName())
2082 PlayerSAO *sao = player->getPlayerSAO();
2087 if(sao->getBasePosition().getDistanceFrom(pos) >
2088 params.max_hear_distance)
2091 dst_clients.push_back(client_id);
2095 if(dst_clients.empty())
2100 ServerPlayingSound *psound = nullptr;
2102 id = -1; // old clients will still use this, so pick a reserved ID
2105 // The sound will exist as a reference in m_playing_sounds
2106 m_playing_sounds[id] = ServerPlayingSound();
2107 psound = &m_playing_sounds[id];
2108 psound->params = params;
2109 psound->spec = spec;
2112 float gain = params.gain * spec.gain;
2113 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2114 pkt << id << spec.name << gain
2115 << (u8) params.type << pos << params.object
2116 << params.loop << params.fade << params.pitch
2119 bool as_reliable = !ephemeral;
2121 for (const u16 dst_client : dst_clients) {
2123 psound->clients.insert(dst_client);
2124 m_clients.send(dst_client, 0, &pkt, as_reliable);
2128 void Server::stopSound(s32 handle)
2130 // Get sound reference
2131 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2132 m_playing_sounds.find(handle);
2133 if (i == m_playing_sounds.end())
2135 ServerPlayingSound &psound = i->second;
2137 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2140 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2141 si != psound.clients.end(); ++si) {
2143 m_clients.send(*si, 0, &pkt, true);
2145 // Remove sound reference
2146 m_playing_sounds.erase(i);
2149 void Server::fadeSound(s32 handle, float step, float gain)
2151 // Get sound reference
2152 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2153 m_playing_sounds.find(handle);
2154 if (i == m_playing_sounds.end())
2157 ServerPlayingSound &psound = i->second;
2158 psound.params.gain = gain;
2160 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2161 pkt << handle << step << gain;
2163 // Backwards compability
2164 bool play_sound = gain > 0;
2165 ServerPlayingSound compat_psound = psound;
2166 compat_psound.clients.clear();
2168 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2169 compat_pkt << handle;
2171 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2172 it != psound.clients.end();) {
2173 if (m_clients.getProtocolVersion(*it) >= 32) {
2175 m_clients.send(*it, 0, &pkt, true);
2178 compat_psound.clients.insert(*it);
2180 m_clients.send(*it, 0, &compat_pkt, true);
2181 psound.clients.erase(it++);
2185 // Remove sound reference
2186 if (!play_sound || psound.clients.empty())
2187 m_playing_sounds.erase(i);
2189 if (play_sound && !compat_psound.clients.empty()) {
2190 // Play new sound volume on older clients
2191 playSound(compat_psound.spec, compat_psound.params);
2195 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2198 float maxd = far_d_nodes * BS;
2199 v3f p_f = intToFloat(p, BS);
2200 v3s16 block_pos = getNodeBlockPos(p);
2202 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2205 std::vector<session_t> clients = m_clients.getClientIDs();
2208 for (session_t client_id : clients) {
2209 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2213 RemotePlayer *player = m_env->getPlayer(client_id);
2214 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2216 // If player is far away, only set modified blocks not sent
2217 if (!client->isBlockSent(block_pos) || (sao &&
2218 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2220 far_players->emplace(client_id);
2222 client->SetBlockNotSent(block_pos);
2227 m_clients.send(client_id, 0, &pkt, true);
2233 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2234 float far_d_nodes, bool remove_metadata)
2236 float maxd = far_d_nodes * BS;
2237 v3f p_f = intToFloat(p, BS);
2238 v3s16 block_pos = getNodeBlockPos(p);
2240 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2241 pkt << p << n.param0 << n.param1 << n.param2
2242 << (u8) (remove_metadata ? 0 : 1);
2244 std::vector<session_t> clients = m_clients.getClientIDs();
2247 for (session_t client_id : clients) {
2248 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2252 RemotePlayer *player = m_env->getPlayer(client_id);
2253 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2255 // If player is far away, only set modified blocks not sent
2256 if (!client->isBlockSent(block_pos) || (sao &&
2257 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2259 far_players->emplace(client_id);
2261 client->SetBlockNotSent(block_pos);
2266 m_clients.send(client_id, 0, &pkt, true);
2272 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2274 float maxd = far_d_nodes * BS;
2275 NodeMetadataList meta_updates_list(false);
2276 std::vector<session_t> clients = m_clients.getClientIDs();
2280 for (session_t i : clients) {
2281 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2285 ServerActiveObject *player = m_env->getActiveObject(i);
2286 v3f player_pos = player ? player->getBasePosition() : v3f();
2288 for (const v3s16 &pos : meta_updates) {
2289 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2294 v3s16 block_pos = getNodeBlockPos(pos);
2295 if (!client->isBlockSent(block_pos) || (player &&
2296 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2297 client->SetBlockNotSent(block_pos);
2301 // Add the change to send list
2302 meta_updates_list.set(pos, meta);
2304 if (meta_updates_list.size() == 0)
2307 // Send the meta changes
2308 std::ostringstream os(std::ios::binary);
2309 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2310 std::ostringstream oss(std::ios::binary);
2311 compressZlib(os.str(), oss);
2313 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2314 pkt.putLongString(oss.str());
2315 m_clients.send(i, 0, &pkt, true);
2317 meta_updates_list.clear();
2323 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2324 u16 net_proto_version)
2327 Create a packet with the block in the right format
2329 thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
2330 std::ostringstream os(std::ios_base::binary);
2331 block->serialize(os, ver, false, net_compression_level);
2332 block->serializeNetworkSpecific(os);
2333 std::string s = os.str();
2335 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + s.size(), peer_id);
2337 pkt << block->getPos();
2338 pkt.putRawString(s.c_str(), s.size());
2342 void Server::SendBlocks(float dtime)
2344 MutexAutoLock envlock(m_env_mutex);
2345 //TODO check if one big lock could be faster then multiple small ones
2347 std::vector<PrioritySortedBlockTransfer> queue;
2349 u32 total_sending = 0;
2352 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2354 std::vector<session_t> clients = m_clients.getClientIDs();
2357 for (const session_t client_id : clients) {
2358 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2363 total_sending += client->getSendingCount();
2364 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2370 // Lowest priority number comes first.
2371 // Lowest is most important.
2372 std::sort(queue.begin(), queue.end());
2376 // Maximal total count calculation
2377 // The per-client block sends is halved with the maximal online users
2378 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2379 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2381 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2382 Map &map = m_env->getMap();
2384 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2385 if (total_sending >= max_blocks_to_send)
2388 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2392 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2397 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2398 client->net_proto_version);
2400 client->SentBlock(block_to_send.pos);
2406 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2408 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2413 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2414 if (!client || client->isBlockSent(blockpos)) {
2418 SendBlockNoLock(peer_id, block, client->serialization_version,
2419 client->net_proto_version);
2425 bool Server::addMediaFile(const std::string &filename,
2426 const std::string &filepath, std::string *filedata_to,
2427 std::string *digest_to)
2429 // If name contains illegal characters, ignore the file
2430 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2431 infostream << "Server: ignoring illegal file name: \""
2432 << filename << "\"" << std::endl;
2435 // If name is not in a supported format, ignore it
2436 const char *supported_ext[] = {
2437 ".png", ".jpg", ".bmp", ".tga",
2438 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2440 ".x", ".b3d", ".md2", ".obj",
2441 // Custom translation file format
2445 if (removeStringEnd(filename, supported_ext).empty()) {
2446 infostream << "Server: ignoring unsupported file extension: \""
2447 << filename << "\"" << std::endl;
2450 // Ok, attempt to load the file and add to cache
2453 std::string filedata;
2454 if (!fs::ReadFile(filepath, filedata)) {
2455 errorstream << "Server::addMediaFile(): Failed to open \""
2456 << filename << "\" for reading" << std::endl;
2460 if (filedata.empty()) {
2461 errorstream << "Server::addMediaFile(): Empty file \""
2462 << filepath << "\"" << std::endl;
2467 sha1.addBytes(filedata.c_str(), filedata.length());
2469 unsigned char *digest = sha1.getDigest();
2470 std::string sha1_base64 = base64_encode(digest, 20);
2471 std::string sha1_hex = hex_encode((char*) digest, 20);
2473 *digest_to = std::string((char*) digest, 20);
2477 m_media[filename] = MediaInfo(filepath, sha1_base64);
2478 verbosestream << "Server: " << sha1_hex << " is " << filename
2482 *filedata_to = std::move(filedata);
2486 void Server::fillMediaCache()
2488 infostream << "Server: Calculating media file checksums" << std::endl;
2490 // Collect all media file paths
2491 std::vector<std::string> paths;
2492 // The paths are ordered in descending priority
2493 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2494 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2495 m_modmgr->getModsMediaPaths(paths);
2497 // Collect media file information from paths into cache
2498 for (const std::string &mediapath : paths) {
2499 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2500 for (const fs::DirListNode &dln : dirlist) {
2501 if (dln.dir) // Ignore dirs (already in paths)
2504 const std::string &filename = dln.name;
2505 if (m_media.find(filename) != m_media.end()) // Do not override
2508 std::string filepath = mediapath;
2509 filepath.append(DIR_DELIM).append(filename);
2510 addMediaFile(filename, filepath);
2514 infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2517 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2520 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2523 std::string lang_suffix;
2524 lang_suffix.append(".").append(lang_code).append(".tr");
2525 for (const auto &i : m_media) {
2526 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2533 for (const auto &i : m_media) {
2534 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2536 pkt << i.first << i.second.sha1_digest;
2539 pkt << g_settings->get("remote_media");
2542 verbosestream << "Server: Announcing files to id(" << peer_id
2543 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2546 struct SendableMedia
2552 SendableMedia(const std::string &name_="", const std::string &path_="",
2553 const std::string &data_=""):
2560 void Server::sendRequestedMedia(session_t peer_id,
2561 const std::vector<std::string> &tosend)
2563 verbosestream<<"Server::sendRequestedMedia(): "
2564 <<"Sending files to client"<<std::endl;
2568 // Put 5kB in one bunch (this is not accurate)
2569 u32 bytes_per_bunch = 5000;
2571 std::vector< std::vector<SendableMedia> > file_bunches;
2572 file_bunches.emplace_back();
2574 u32 file_size_bunch_total = 0;
2576 for (const std::string &name : tosend) {
2577 if (m_media.find(name) == m_media.end()) {
2578 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2579 <<"unknown file \""<<(name)<<"\""<<std::endl;
2583 //TODO get path + name
2584 std::string tpath = m_media[name].path;
2587 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2589 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2590 <<tpath<<"\" for reading"<<std::endl;
2593 std::ostringstream tmp_os(std::ios_base::binary);
2597 fis.read(buf, 1024);
2598 std::streamsize len = fis.gcount();
2599 tmp_os.write(buf, len);
2600 file_size_bunch_total += len;
2609 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2610 <<name<<"\""<<std::endl;
2613 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2614 <<tname<<"\""<<std::endl;*/
2616 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2618 // Start next bunch if got enough data
2619 if(file_size_bunch_total >= bytes_per_bunch) {
2620 file_bunches.emplace_back();
2621 file_size_bunch_total = 0;
2626 /* Create and send packets */
2628 u16 num_bunches = file_bunches.size();
2629 for (u16 i = 0; i < num_bunches; i++) {
2632 u16 total number of texture bunches
2633 u16 index of this bunch
2634 u32 number of files in this bunch
2643 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2644 pkt << num_bunches << i << (u32) file_bunches[i].size();
2646 for (const SendableMedia &j : file_bunches[i]) {
2648 pkt.putLongString(j.data);
2651 verbosestream << "Server::sendRequestedMedia(): bunch "
2652 << i << "/" << num_bunches
2653 << " files=" << file_bunches[i].size()
2654 << " size=" << pkt.getSize() << std::endl;
2659 void Server::SendMinimapModes(session_t peer_id,
2660 std::vector<MinimapMode> &modes, size_t wanted_mode)
2662 RemotePlayer *player = m_env->getPlayer(peer_id);
2664 if (player->getPeerId() == PEER_ID_INEXISTENT)
2667 NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2668 pkt << (u16)modes.size() << (u16)wanted_mode;
2670 for (auto &mode : modes)
2671 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2676 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2678 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2682 pkt << false; // Remove inventory
2684 pkt << true; // Update inventory
2686 // Serialization & NetworkPacket isn't a love story
2687 std::ostringstream os(std::ios_base::binary);
2688 inventory->serialize(os);
2689 inventory->setModified(false);
2691 const std::string &os_str = os.str();
2692 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2693 pkt.putRawString(os_str);
2696 if (peer_id == PEER_ID_INEXISTENT)
2697 m_clients.sendToAll(&pkt);
2702 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2704 // Lookup player name, to filter detached inventories just after
2705 std::string peer_name;
2706 if (peer_id != PEER_ID_INEXISTENT) {
2707 peer_name = getClient(peer_id, CS_Created)->getName();
2710 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2711 sendDetachedInventory(inv, name, peer_id);
2714 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2721 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2723 PlayerSAO *playersao = getPlayerSAO(peer_id);
2726 infostream << "Server::DiePlayer(): Player "
2727 << playersao->getPlayer()->getName()
2728 << " dies" << std::endl;
2730 playersao->setHP(0, reason);
2731 playersao->clearParentAttachment();
2733 // Trigger scripted stuff
2734 m_script->on_dieplayer(playersao, reason);
2736 SendPlayerHP(peer_id);
2737 SendDeathscreen(peer_id, false, v3f(0,0,0));
2740 void Server::RespawnPlayer(session_t peer_id)
2742 PlayerSAO *playersao = getPlayerSAO(peer_id);
2745 infostream << "Server::RespawnPlayer(): Player "
2746 << playersao->getPlayer()->getName()
2747 << " respawns" << std::endl;
2749 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2750 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2751 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2753 bool repositioned = m_script->on_respawnplayer(playersao);
2754 if (!repositioned) {
2755 // setPos will send the new position to client
2756 playersao->setPos(findSpawnPos());
2759 SendPlayerHP(peer_id);
2763 void Server::DenySudoAccess(session_t peer_id)
2765 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2770 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2771 const std::string &str_reason, bool reconnect)
2773 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2775 m_clients.event(peer_id, CSE_SetDenied);
2776 DisconnectPeer(peer_id);
2780 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2781 const std::string &custom_reason)
2783 SendAccessDenied(peer_id, reason, custom_reason);
2784 m_clients.event(peer_id, CSE_SetDenied);
2785 DisconnectPeer(peer_id);
2788 // 13/03/15: remove this function when protocol version 25 will become
2789 // the minimum version for MT users, maybe in 1 year
2790 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2792 SendAccessDenied_Legacy(peer_id, reason);
2793 m_clients.event(peer_id, CSE_SetDenied);
2794 DisconnectPeer(peer_id);
2797 void Server::DisconnectPeer(session_t peer_id)
2799 m_modchannel_mgr->leaveAllChannels(peer_id);
2800 m_con->DisconnectPeer(peer_id);
2803 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2806 RemoteClient* client = getClient(peer_id, CS_Invalid);
2808 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2810 // Right now, the auth mechs don't change between login and sudo mode.
2811 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2812 client->allowed_sudo_mechs = sudo_auth_mechs;
2814 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2815 << g_settings->getFloat("dedicated_server_step")
2819 m_clients.event(peer_id, CSE_AuthAccept);
2821 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2823 // We only support SRP right now
2824 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2826 resp_pkt << sudo_auth_mechs;
2828 m_clients.event(peer_id, CSE_SudoSuccess);
2832 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2834 std::wstring message;
2837 Clear references to playing sounds
2839 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2840 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2841 ServerPlayingSound &psound = i->second;
2842 psound.clients.erase(peer_id);
2843 if (psound.clients.empty())
2844 m_playing_sounds.erase(i++);
2849 // clear formspec info so the next client can't abuse the current state
2850 m_formspec_state_data.erase(peer_id);
2852 RemotePlayer *player = m_env->getPlayer(peer_id);
2854 /* Run scripts and remove from environment */
2856 PlayerSAO *playersao = player->getPlayerSAO();
2859 playersao->clearChildAttachments();
2860 playersao->clearParentAttachment();
2862 // inform connected clients
2863 const std::string &player_name = player->getName();
2864 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2865 // (u16) 1 + std::string represents a vector serialization representation
2866 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2867 m_clients.sendToAll(¬ice);
2869 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2871 playersao->disconnected();
2878 if (player && reason != CDR_DENY) {
2879 std::ostringstream os(std::ios_base::binary);
2880 std::vector<session_t> clients = m_clients.getClientIDs();
2882 for (const session_t client_id : clients) {
2884 RemotePlayer *player = m_env->getPlayer(client_id);
2888 // Get name of player
2889 os << player->getName() << " ";
2892 std::string name = player->getName();
2893 actionstream << name << " "
2894 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2895 << " List of players: " << os.str() << std::endl;
2897 m_admin_chat->outgoing_queue.push_back(
2898 new ChatEventNick(CET_NICK_REMOVE, name));
2902 MutexAutoLock env_lock(m_env_mutex);
2903 m_clients.DeleteClient(peer_id);
2907 // Send leave chat message to all remaining clients
2908 if (!message.empty()) {
2909 SendChatMessage(PEER_ID_INEXISTENT,
2910 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2914 void Server::UpdateCrafting(RemotePlayer *player)
2916 InventoryList *clist = player->inventory.getList("craft");
2917 if (!clist || clist->getSize() == 0)
2920 if (!clist->checkModified())
2923 // Get a preview for crafting
2925 InventoryLocation loc;
2926 loc.setPlayer(player->getName());
2927 std::vector<ItemStack> output_replacements;
2928 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2929 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2932 InventoryList *plist = player->inventory.getList("craftpreview");
2933 if (plist && plist->getSize() >= 1) {
2934 // Put the new preview in
2935 plist->changeItem(0, preview);
2939 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2941 if (evt->type == CET_NICK_ADD) {
2942 // The terminal informed us of its nick choice
2943 m_admin_nick = ((ChatEventNick *)evt)->nick;
2944 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2945 errorstream << "You haven't set up an account." << std::endl
2946 << "Please log in using the client as '"
2947 << m_admin_nick << "' with a secure password." << std::endl
2948 << "Until then, you can't execute admin tasks via the console," << std::endl
2949 << "and everybody can claim the user account instead of you," << std::endl
2950 << "giving them full control over this server." << std::endl;
2953 assert(evt->type == CET_CHAT);
2954 handleAdminChat((ChatEventChat *)evt);
2958 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2959 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2961 // If something goes wrong, this player is to blame
2962 RollbackScopeActor rollback_scope(m_rollback,
2963 std::string("player:") + name);
2965 if (g_settings->getBool("strip_color_codes"))
2966 wmessage = unescape_enriched(wmessage);
2969 switch (player->canSendChatMessage()) {
2970 case RPLAYER_CHATRESULT_FLOODING: {
2971 std::wstringstream ws;
2972 ws << L"You cannot send more messages. You are limited to "
2973 << g_settings->getFloat("chat_message_limit_per_10sec")
2974 << L" messages per 10 seconds.";
2977 case RPLAYER_CHATRESULT_KICK:
2978 DenyAccess_Legacy(player->getPeerId(),
2979 L"You have been kicked due to message flooding.");
2981 case RPLAYER_CHATRESULT_OK:
2984 FATAL_ERROR("Unhandled chat filtering result found.");
2988 if (m_max_chatmessage_length > 0
2989 && wmessage.length() > m_max_chatmessage_length) {
2990 return L"Your message exceed the maximum chat message limit set on the server. "
2991 L"It was refused. Send a shorter message";
2994 auto message = trim(wide_to_utf8(wmessage));
2995 if (message.find_first_of("\n\r") != std::wstring::npos) {
2996 return L"New lines are not permitted in chat messages";
2999 // Run script hook, exit if script ate the chat message
3000 if (m_script->on_chat_message(name, message))
3005 // Whether to send line to the player that sent the message, or to all players
3006 bool broadcast_line = true;
3008 if (check_shout_priv && !checkPriv(name, "shout")) {
3009 line += L"-!- You don't have permission to shout.";
3010 broadcast_line = false;
3013 Workaround for fixing chat on Android. Lua doesn't handle
3014 the Cyrillic alphabet and some characters on older Android devices
3017 line += L"<" + wname + L"> " + wmessage;
3019 line += narrow_to_wide(m_script->formatChatMessage(name,
3020 wide_to_narrow(wmessage)));
3025 Tell calling method to send the message to sender
3027 if (!broadcast_line)
3031 Send the message to others
3033 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
3035 std::vector<session_t> clients = m_clients.getClientIDs();
3038 Send the message back to the inital sender
3039 if they are using protocol version >= 29
3042 session_t peer_id_to_avoid_sending =
3043 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
3045 if (player && player->protocol_version >= 29)
3046 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
3048 for (u16 cid : clients) {
3049 if (cid != peer_id_to_avoid_sending)
3050 SendChatMessage(cid, ChatMessage(line));
3055 void Server::handleAdminChat(const ChatEventChat *evt)
3057 std::string name = evt->nick;
3058 std::wstring wname = utf8_to_wide(name);
3059 std::wstring wmessage = evt->evt_msg;
3061 std::wstring answer = handleChat(name, wname, wmessage);
3063 // If asked to send answer to sender
3064 if (!answer.empty()) {
3065 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3069 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3071 RemoteClient *client = getClientNoEx(peer_id,state_min);
3073 throw ClientNotFoundException("Client not found");
3077 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3079 return m_clients.getClientNoEx(peer_id, state_min);
3082 std::string Server::getPlayerName(session_t peer_id)
3084 RemotePlayer *player = m_env->getPlayer(peer_id);
3086 return "[id="+itos(peer_id)+"]";
3087 return player->getName();
3090 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3092 RemotePlayer *player = m_env->getPlayer(peer_id);
3095 return player->getPlayerSAO();
3098 std::wstring Server::getStatusString()
3100 std::wostringstream os(std::ios_base::binary);
3101 os << L"# Server: ";
3103 os << L"version=" << narrow_to_wide(g_version_string);
3105 os << L", uptime=" << m_uptime_counter->get();
3107 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3109 // Information about clients
3111 os << L", clients={";
3113 std::vector<session_t> clients = m_clients.getClientIDs();
3114 for (session_t client_id : clients) {
3115 RemotePlayer *player = m_env->getPlayer(client_id);
3117 // Get name of player
3118 std::wstring name = L"unknown";
3120 name = narrow_to_wide(player->getName());
3122 // Add name to information string
3133 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3134 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3136 if (!g_settings->get("motd").empty())
3137 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3142 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3144 std::set<std::string> privs;
3145 m_script->getAuth(name, NULL, &privs);
3149 bool Server::checkPriv(const std::string &name, const std::string &priv)
3151 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3152 return (privs.count(priv) != 0);
3155 void Server::reportPrivsModified(const std::string &name)
3158 std::vector<session_t> clients = m_clients.getClientIDs();
3159 for (const session_t client_id : clients) {
3160 RemotePlayer *player = m_env->getPlayer(client_id);
3161 reportPrivsModified(player->getName());
3164 RemotePlayer *player = m_env->getPlayer(name.c_str());
3167 SendPlayerPrivileges(player->getPeerId());
3168 PlayerSAO *sao = player->getPlayerSAO();
3171 sao->updatePrivileges(
3172 getPlayerEffectivePrivs(name),
3177 void Server::reportInventoryFormspecModified(const std::string &name)
3179 RemotePlayer *player = m_env->getPlayer(name.c_str());
3182 SendPlayerInventoryFormspec(player->getPeerId());
3185 void Server::reportFormspecPrependModified(const std::string &name)
3187 RemotePlayer *player = m_env->getPlayer(name.c_str());
3190 SendPlayerFormspecPrepend(player->getPeerId());
3193 void Server::setIpBanned(const std::string &ip, const std::string &name)
3195 m_banmanager->add(ip, name);
3198 void Server::unsetIpBanned(const std::string &ip_or_name)
3200 m_banmanager->remove(ip_or_name);
3203 std::string Server::getBanDescription(const std::string &ip_or_name)
3205 return m_banmanager->getBanDescription(ip_or_name);
3208 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3210 // m_env will be NULL if the server is initializing
3214 if (m_admin_nick == name && !m_admin_nick.empty()) {
3215 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3218 RemotePlayer *player = m_env->getPlayer(name);
3223 if (player->getPeerId() == PEER_ID_INEXISTENT)
3226 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3229 bool Server::showFormspec(const char *playername, const std::string &formspec,
3230 const std::string &formname)
3232 // m_env will be NULL if the server is initializing
3236 RemotePlayer *player = m_env->getPlayer(playername);
3240 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3244 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3249 u32 id = player->addHud(form);
3251 SendHUDAdd(player->getPeerId(), id, form);
3256 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3260 HudElement* todel = player->removeHud(id);
3267 SendHUDRemove(player->getPeerId(), id);
3271 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3276 SendHUDChange(player->getPeerId(), id, stat, data);
3280 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3285 SendHUDSetFlags(player->getPeerId(), flags, mask);
3286 player->hud_flags &= ~mask;
3287 player->hud_flags |= flags;
3289 PlayerSAO* playersao = player->getPlayerSAO();
3294 m_script->player_event(playersao, "hud_changed");
3298 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3303 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3306 player->setHotbarItemcount(hotbar_itemcount);
3307 std::ostringstream os(std::ios::binary);
3308 writeS32(os, hotbar_itemcount);
3309 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3313 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3318 player->setHotbarImage(name);
3319 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3322 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3327 player->setHotbarSelectedImage(name);
3328 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3331 Address Server::getPeerAddress(session_t peer_id)
3333 // Note that this is only set after Init was received in Server::handleCommand_Init
3334 return getClient(peer_id, CS_Invalid)->getAddress();
3337 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3338 v2s32 animation_frames[4], f32 frame_speed)
3340 sanity_check(player);
3341 player->setLocalAnimations(animation_frames, frame_speed);
3342 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3345 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3347 sanity_check(player);
3348 player->eye_offset_first = first;
3349 player->eye_offset_third = third;
3350 SendEyeOffset(player->getPeerId(), first, third);
3353 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3355 sanity_check(player);
3356 player->setSky(params);
3357 SendSetSky(player->getPeerId(), params);
3360 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3362 sanity_check(player);
3363 player->setSun(params);
3364 SendSetSun(player->getPeerId(), params);
3367 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3369 sanity_check(player);
3370 player->setMoon(params);
3371 SendSetMoon(player->getPeerId(), params);
3374 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3376 sanity_check(player);
3377 player->setStars(params);
3378 SendSetStars(player->getPeerId(), params);
3381 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3383 sanity_check(player);
3384 player->setCloudParams(params);
3385 SendCloudParams(player->getPeerId(), params);
3388 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3391 sanity_check(player);
3392 player->overrideDayNightRatio(do_override, ratio);
3393 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3396 void Server::notifyPlayers(const std::wstring &msg)
3398 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3401 void Server::spawnParticle(const std::string &playername,
3402 const ParticleParameters &p)
3404 // m_env will be NULL if the server is initializing
3408 session_t peer_id = PEER_ID_INEXISTENT;
3410 if (!playername.empty()) {
3411 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3414 peer_id = player->getPeerId();
3415 proto_ver = player->protocol_version;
3418 SendSpawnParticle(peer_id, proto_ver, p);
3421 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3422 ServerActiveObject *attached, const std::string &playername)
3424 // m_env will be NULL if the server is initializing
3428 session_t peer_id = PEER_ID_INEXISTENT;
3430 if (!playername.empty()) {
3431 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3434 peer_id = player->getPeerId();
3435 proto_ver = player->protocol_version;
3438 u16 attached_id = attached ? attached->getId() : 0;
3441 if (attached_id == 0)
3442 id = m_env->addParticleSpawner(p.time);
3444 id = m_env->addParticleSpawner(p.time, attached_id);
3446 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3450 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3452 // m_env will be NULL if the server is initializing
3454 throw ServerError("Can't delete particle spawners during initialisation!");
3456 session_t peer_id = PEER_ID_INEXISTENT;
3457 if (!playername.empty()) {
3458 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3461 peer_id = player->getPeerId();
3464 m_env->deleteParticleSpawner(id);
3465 SendDeleteParticleSpawner(peer_id, id);
3468 bool Server::dynamicAddMedia(const std::string &filepath,
3469 std::vector<RemotePlayer*> &sent_to)
3471 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3472 if (m_media.find(filename) != m_media.end()) {
3473 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3474 << "\" already exists in media cache" << std::endl;
3478 // Load the file and add it to our media cache
3479 std::string filedata, raw_hash;
3480 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3484 // Push file to existing clients
3485 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3486 pkt << raw_hash << filename << (bool) true;
3487 pkt.putLongString(filedata);
3490 for (auto &pair : m_clients.getClientList()) {
3491 if (pair.second->getState() < CS_DefinitionsSent)
3493 if (pair.second->net_proto_version < 39)
3496 if (auto player = m_env->getPlayer(pair.second->peer_id))
3497 sent_to.emplace_back(player);
3499 FIXME: this is a very awful hack
3500 The network layer only guarantees ordered delivery inside a channel.
3501 Since the very next packet could be one that uses the media, we have
3502 to push the media over ALL channels to ensure it is processed before
3504 In practice this means we have to send it twice:
3506 - channel 0 (everything else: e.g. play_sound, object messages)
3508 m_clients.send(pair.second->peer_id, 1, &pkt, true);
3509 m_clients.send(pair.second->peer_id, 0, &pkt, true);
3516 // actions: time-reversed list
3517 // Return value: success/failure
3518 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3519 std::list<std::string> *log)
3521 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3522 ServerMap *map = (ServerMap*)(&m_env->getMap());
3524 // Fail if no actions to handle
3525 if (actions.empty()) {
3527 log->push_back("Nothing to do.");
3534 for (const RollbackAction &action : actions) {
3536 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3539 std::ostringstream os;
3540 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3541 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3543 log->push_back(os.str());
3545 std::ostringstream os;
3546 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3547 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3549 log->push_back(os.str());
3553 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3554 <<" failed"<<std::endl;
3556 // Call it done if less than half failed
3557 return num_failed <= num_tried/2;
3560 // IGameDef interface
3562 IItemDefManager *Server::getItemDefManager()
3567 const NodeDefManager *Server::getNodeDefManager()
3572 ICraftDefManager *Server::getCraftDefManager()
3577 u16 Server::allocateUnknownNodeId(const std::string &name)
3579 return m_nodedef->allocateDummy(name);
3582 IWritableItemDefManager *Server::getWritableItemDefManager()
3587 NodeDefManager *Server::getWritableNodeDefManager()
3592 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3597 const std::vector<ModSpec> & Server::getMods() const
3599 return m_modmgr->getMods();
3602 const ModSpec *Server::getModSpec(const std::string &modname) const
3604 return m_modmgr->getModSpec(modname);
3607 void Server::getModNames(std::vector<std::string> &modlist)
3609 m_modmgr->getModNames(modlist);
3612 std::string Server::getBuiltinLuaPath()
3614 return porting::path_share + DIR_DELIM + "builtin";
3617 std::string Server::getModStoragePath() const
3619 return m_path_world + DIR_DELIM + "mod_storage";
3622 v3f Server::findSpawnPos()
3624 ServerMap &map = m_env->getServerMap();
3626 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3627 return nodeposf * BS;
3629 bool is_good = false;
3630 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3631 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3633 // Try to find a good place a few times
3634 for (s32 i = 0; i < 4000 && !is_good; i++) {
3635 s32 range = MYMIN(1 + i, range_max);
3636 // We're going to try to throw the player to this position
3637 v2s16 nodepos2d = v2s16(
3638 -range + (myrand() % (range * 2)),
3639 -range + (myrand() % (range * 2)));
3640 // Get spawn level at point
3641 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3642 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3643 // signify an unsuitable spawn position, or if outside limits.
3644 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3645 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3648 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3649 // Consecutive empty nodes
3652 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3653 // avoid obstructions in already-generated mapblocks.
3654 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3655 // no obstructions, but mapgen decorations are generated after spawn so
3656 // the player may end up inside one.
3657 for (s32 i = 0; i < 8; i++) {
3658 v3s16 blockpos = getNodeBlockPos(nodepos);
3659 map.emergeBlock(blockpos, true);
3660 content_t c = map.getNode(nodepos).getContent();
3662 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3663 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3664 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3666 if (air_count >= 2) {
3667 // Spawn in lower empty node
3669 nodeposf = intToFloat(nodepos, BS);
3670 // Don't spawn the player outside map boundaries
3671 if (objectpos_over_limit(nodeposf))
3672 // Exit this loop, positions above are probably over limit
3675 // Good position found, cause an exit from main loop
3689 // No suitable spawn point found, return fallback 0,0,0
3690 return v3f(0.0f, 0.0f, 0.0f);
3693 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3695 if (delay == 0.0f) {
3696 // No delay, shutdown immediately
3697 m_shutdown_state.is_requested = true;
3698 // only print to the infostream, a chat message saying
3699 // "Server Shutting Down" is sent when the server destructs.
3700 infostream << "*** Immediate Server shutdown requested." << std::endl;
3701 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3702 // Negative delay, cancel shutdown if requested
3703 m_shutdown_state.reset();
3704 std::wstringstream ws;
3706 ws << L"*** Server shutdown canceled.";
3708 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3709 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3710 // m_shutdown_* are already handled, skip.
3712 } else if (delay > 0.0f) {
3713 // Positive delay, tell the clients when the server will shut down
3714 std::wstringstream ws;
3716 ws << L"*** Server shutting down in "
3717 << duration_to_string(myround(delay)).c_str()
3720 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3721 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3724 m_shutdown_state.trigger(delay, msg, reconnect);
3727 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3730 Try to get an existing player
3732 RemotePlayer *player = m_env->getPlayer(name);
3734 // If player is already connected, cancel
3735 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3736 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3741 If player with the wanted peer_id already exists, cancel.
3743 if (m_env->getPlayer(peer_id)) {
3744 infostream<<"emergePlayer(): Player with wrong name but same"
3745 " peer_id already exists"<<std::endl;
3750 player = new RemotePlayer(name, idef());
3753 bool newplayer = false;
3756 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3758 // Complete init with server parts
3759 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3760 player->protocol_version = proto_version;
3764 m_script->on_newplayer(playersao);
3770 bool Server::registerModStorage(ModMetadata *storage)
3772 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3773 errorstream << "Unable to register same mod storage twice. Storage name: "
3774 << storage->getModName() << std::endl;
3778 m_mod_storages[storage->getModName()] = storage;
3782 void Server::unregisterModStorage(const std::string &name)
3784 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3785 if (it != m_mod_storages.end()) {
3786 // Save unconditionaly on unregistration
3787 it->second->save(getModStoragePath());
3788 m_mod_storages.erase(name);
3792 void dedicated_server_loop(Server &server, bool &kill)
3794 verbosestream<<"dedicated_server_loop()"<<std::endl;
3796 IntervalLimiter m_profiler_interval;
3798 static thread_local const float steplen =
3799 g_settings->getFloat("dedicated_server_step");
3800 static thread_local const float profiler_print_interval =
3801 g_settings->getFloat("profiler_print_interval");
3804 * The dedicated server loop only does time-keeping (in Server::step) and
3805 * provides a way to main.cpp to kill the server externally (bool &kill).
3809 // This is kind of a hack but can be done like this
3810 // because server.step() is very light
3811 sleep_ms((int)(steplen*1000.0));
3812 server.step(steplen);
3814 if (server.isShutdownRequested() || kill)
3820 if (profiler_print_interval != 0) {
3821 if(m_profiler_interval.step(steplen, profiler_print_interval))
3823 infostream<<"Profiler:"<<std::endl;
3824 g_profiler->print(infostream);
3825 g_profiler->clear();
3830 infostream << "Dedicated server quitting" << std::endl;
3832 if (g_settings->getBool("server_announce"))
3833 ServerList::sendAnnounce(ServerList::AA_DELETE,
3834 server.m_bind_addr.getPort());
3843 bool Server::joinModChannel(const std::string &channel)
3845 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3846 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3849 bool Server::leaveModChannel(const std::string &channel)
3851 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3854 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3856 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3859 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3863 ModChannel* Server::getModChannel(const std::string &channel)
3865 return m_modchannel_mgr->getModChannel(channel);
3868 void Server::broadcastModChannelMessage(const std::string &channel,
3869 const std::string &message, session_t from_peer)
3871 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3875 if (message.size() > STRING_MAX_LEN) {
3876 warningstream << "ModChannel message too long, dropping before sending "
3877 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3878 << channel << ")" << std::endl;
3883 if (from_peer != PEER_ID_SERVER) {
3884 sender = getPlayerName(from_peer);
3887 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3888 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3889 resp_pkt << channel << sender << message;
3890 for (session_t peer_id : peers) {
3892 if (peer_id == from_peer)
3895 Send(peer_id, &resp_pkt);
3898 if (from_peer != PEER_ID_SERVER) {
3899 m_script->on_modchannel_message(channel, sender, message);
3903 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3905 if (lang_code.empty())
3908 auto it = server_translations.find(lang_code);
3909 if (it != server_translations.end())
3910 return &it->second; // Already loaded
3912 // [] will create an entry
3913 auto *translations = &server_translations[lang_code];
3915 std::string suffix = "." + lang_code + ".tr";
3916 for (const auto &i : m_media) {
3917 if (str_ends_with(i.first, suffix)) {
3919 if (fs::ReadFile(i.second.path, data)) {
3920 translations->loadTranslation(data);
3925 return translations;