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 << message.sender << message.message
1486 << static_cast<u64>(message.timestamp);
1488 if (peer_id != PEER_ID_INEXISTENT) {
1489 RemotePlayer *player = m_env->getPlayer(peer_id);
1495 m_clients.sendToAll(&pkt);
1499 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1500 const std::string &formname)
1502 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1503 if (formspec.empty()){
1504 //the client should close the formspec
1505 //but make sure there wasn't another one open in meantime
1506 const auto it = m_formspec_state_data.find(peer_id);
1507 if (it != m_formspec_state_data.end() && it->second == formname) {
1508 m_formspec_state_data.erase(peer_id);
1510 pkt.putLongString("");
1512 m_formspec_state_data[peer_id] = formname;
1513 pkt.putLongString(formspec);
1520 // Spawns a particle on peer with peer_id
1521 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1522 const ParticleParameters &p)
1524 static thread_local const float radius =
1525 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1527 if (peer_id == PEER_ID_INEXISTENT) {
1528 std::vector<session_t> clients = m_clients.getClientIDs();
1529 const v3f pos = p.pos * BS;
1530 const float radius_sq = radius * radius;
1532 for (const session_t client_id : clients) {
1533 RemotePlayer *player = m_env->getPlayer(client_id);
1537 PlayerSAO *sao = player->getPlayerSAO();
1541 // Do not send to distant clients
1542 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1545 SendSpawnParticle(client_id, player->protocol_version, p);
1549 assert(protocol_version != 0);
1551 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1554 // NetworkPacket and iostreams are incompatible...
1555 std::ostringstream oss(std::ios_base::binary);
1556 p.serialize(oss, protocol_version);
1557 pkt.putRawString(oss.str());
1563 // Adds a ParticleSpawner on peer with peer_id
1564 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1565 const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1567 static thread_local const float radius =
1568 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1570 if (peer_id == PEER_ID_INEXISTENT) {
1571 std::vector<session_t> clients = m_clients.getClientIDs();
1572 const v3f pos = (p.minpos + p.maxpos) / 2.0f * BS;
1573 const float radius_sq = radius * radius;
1574 /* Don't send short-lived spawners to distant players.
1575 * This could be replaced with proper tracking at some point. */
1576 const bool distance_check = !attached_id && p.time <= 1.0f;
1578 for (const session_t client_id : clients) {
1579 RemotePlayer *player = m_env->getPlayer(client_id);
1583 if (distance_check) {
1584 PlayerSAO *sao = player->getPlayerSAO();
1587 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1591 SendAddParticleSpawner(client_id, player->protocol_version,
1592 p, attached_id, id);
1596 assert(protocol_version != 0);
1598 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1600 pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
1601 << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
1602 << p.minsize << p.maxsize << p.collisiondetection;
1604 pkt.putLongString(p.texture);
1606 pkt << id << p.vertical << p.collision_removal << attached_id;
1608 std::ostringstream os(std::ios_base::binary);
1609 p.animation.serialize(os, protocol_version);
1610 pkt.putRawString(os.str());
1612 pkt << p.glow << p.object_collision;
1613 pkt << p.node.param0 << p.node.param2 << p.node_tile;
1618 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1620 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1624 if (peer_id != PEER_ID_INEXISTENT)
1627 m_clients.sendToAll(&pkt);
1631 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1633 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1635 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1636 << form->text << form->number << form->item << form->dir
1637 << form->align << form->offset << form->world_pos << form->size
1638 << form->z_index << form->text2;
1643 void Server::SendHUDRemove(session_t peer_id, u32 id)
1645 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1650 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1652 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1653 pkt << id << (u8) stat;
1657 case HUD_STAT_SCALE:
1658 case HUD_STAT_ALIGN:
1659 case HUD_STAT_OFFSET:
1660 pkt << *(v2f *) value;
1664 case HUD_STAT_TEXT2:
1665 pkt << *(std::string *) value;
1667 case HUD_STAT_WORLD_POS:
1668 pkt << *(v3f *) value;
1671 pkt << *(v2s32 *) value;
1673 case HUD_STAT_NUMBER:
1677 pkt << *(u32 *) value;
1684 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1686 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1688 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1690 pkt << flags << mask;
1695 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1697 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1698 pkt << param << value;
1702 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1704 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1706 // Handle prior clients here
1707 if (m_clients.getProtocolVersion(peer_id) < 39) {
1708 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1710 for (const std::string& texture : params.textures)
1713 pkt << params.clouds;
1714 } else { // Handle current clients and future clients
1715 pkt << params.bgcolor << params.type
1716 << params.clouds << params.fog_sun_tint
1717 << params.fog_moon_tint << params.fog_tint_type;
1719 if (params.type == "skybox") {
1720 pkt << (u16) params.textures.size();
1721 for (const std::string &texture : params.textures)
1723 } else if (params.type == "regular") {
1724 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1725 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1726 << params.sky_color.night_sky << params.sky_color.night_horizon
1727 << params.sky_color.indoors;
1734 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1736 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1737 pkt << params.visible << params.texture
1738 << params.tonemap << params.sunrise
1739 << params.sunrise_visible << params.scale;
1743 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1745 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1747 pkt << params.visible << params.texture
1748 << params.tonemap << params.scale;
1752 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1754 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1756 pkt << params.visible << params.count
1757 << params.starcolor << params.scale;
1762 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1764 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1765 pkt << params.density << params.color_bright << params.color_ambient
1766 << params.height << params.thickness << params.speed;
1770 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1773 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1776 pkt << do_override << (u16) (ratio * 65535);
1781 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1783 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1784 pkt << time << time_speed;
1786 if (peer_id == PEER_ID_INEXISTENT) {
1787 m_clients.sendToAll(&pkt);
1794 void Server::SendPlayerHP(session_t peer_id)
1796 PlayerSAO *playersao = getPlayerSAO(peer_id);
1799 SendHP(peer_id, playersao->getHP());
1800 m_script->player_event(playersao,"health_changed");
1802 // Send to other clients
1803 playersao->sendPunchCommand();
1806 void Server::SendPlayerBreath(PlayerSAO *sao)
1810 m_script->player_event(sao, "breath_changed");
1811 SendBreath(sao->getPeerID(), sao->getBreath());
1814 void Server::SendMovePlayer(session_t peer_id)
1816 RemotePlayer *player = m_env->getPlayer(peer_id);
1818 PlayerSAO *sao = player->getPlayerSAO();
1821 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1822 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1825 v3f pos = sao->getBasePosition();
1826 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1827 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1828 << " pitch=" << sao->getLookPitch()
1829 << " yaw=" << sao->getRotation().Y
1836 void Server::SendPlayerFov(session_t peer_id)
1838 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1840 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1841 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1846 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1847 f32 animation_speed)
1849 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1852 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1853 << animation_frames[3] << animation_speed;
1858 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1860 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1861 pkt << first << third;
1865 void Server::SendPlayerPrivileges(session_t peer_id)
1867 RemotePlayer *player = m_env->getPlayer(peer_id);
1869 if(player->getPeerId() == PEER_ID_INEXISTENT)
1872 std::set<std::string> privs;
1873 m_script->getAuth(player->getName(), NULL, &privs);
1875 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1876 pkt << (u16) privs.size();
1878 for (const std::string &priv : privs) {
1885 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1887 RemotePlayer *player = m_env->getPlayer(peer_id);
1889 if (player->getPeerId() == PEER_ID_INEXISTENT)
1892 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1893 pkt.putLongString(player->inventory_formspec);
1898 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1900 RemotePlayer *player = m_env->getPlayer(peer_id);
1902 if (player->getPeerId() == PEER_ID_INEXISTENT)
1905 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1906 pkt << player->formspec_prepend;
1910 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1912 // Radius inside which objects are active
1913 static thread_local const s16 radius =
1914 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1916 // Radius inside which players are active
1917 static thread_local const bool is_transfer_limited =
1918 g_settings->exists("unlimited_player_transfer_distance") &&
1919 !g_settings->getBool("unlimited_player_transfer_distance");
1921 static thread_local const s16 player_transfer_dist =
1922 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1924 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1925 radius : player_transfer_dist;
1927 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1931 std::queue<u16> removed_objects, added_objects;
1932 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1933 client->m_known_objects, removed_objects);
1934 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1935 client->m_known_objects, added_objects);
1937 int removed_count = removed_objects.size();
1938 int added_count = added_objects.size();
1940 if (removed_objects.empty() && added_objects.empty())
1946 // Handle removed objects
1947 writeU16((u8*)buf, removed_objects.size());
1948 data.append(buf, 2);
1949 while (!removed_objects.empty()) {
1951 u16 id = removed_objects.front();
1952 ServerActiveObject* obj = m_env->getActiveObject(id);
1954 // Add to data buffer for sending
1955 writeU16((u8*)buf, id);
1956 data.append(buf, 2);
1958 // Remove from known objects
1959 client->m_known_objects.erase(id);
1961 if (obj && obj->m_known_by_count > 0)
1962 obj->m_known_by_count--;
1964 removed_objects.pop();
1967 // Handle added objects
1968 writeU16((u8*)buf, added_objects.size());
1969 data.append(buf, 2);
1970 while (!added_objects.empty()) {
1972 u16 id = added_objects.front();
1973 ServerActiveObject *obj = m_env->getActiveObject(id);
1974 added_objects.pop();
1977 warningstream << FUNCTION_NAME << ": NULL object id="
1978 << (int)id << std::endl;
1983 u8 type = obj->getSendType();
1985 // Add to data buffer for sending
1986 writeU16((u8*)buf, id);
1987 data.append(buf, 2);
1988 writeU8((u8*)buf, type);
1989 data.append(buf, 1);
1991 data.append(serializeString32(
1992 obj->getClientInitializationData(client->net_proto_version)));
1994 // Add to known objects
1995 client->m_known_objects.insert(id);
1997 obj->m_known_by_count++;
2000 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2001 pkt.putRawString(data.c_str(), data.size());
2004 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2005 << removed_count << " removed, " << added_count << " added, "
2006 << "packet size is " << pkt.getSize() << std::endl;
2009 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2012 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2013 datas.size(), peer_id);
2015 pkt.putRawString(datas.c_str(), datas.size());
2017 m_clients.send(pkt.getPeerId(),
2018 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2022 void Server::SendCSMRestrictionFlags(session_t peer_id)
2024 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2025 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2026 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2030 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2032 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2037 inline s32 Server::nextSoundId()
2039 s32 ret = m_next_sound_id;
2040 if (m_next_sound_id == INT32_MAX)
2041 m_next_sound_id = 0; // signed overflow is undefined
2047 s32 Server::playSound(const SimpleSoundSpec &spec,
2048 const ServerSoundParams ¶ms, bool ephemeral)
2050 // Find out initial position of sound
2051 bool pos_exists = false;
2052 v3f pos = params.getPos(m_env, &pos_exists);
2053 // If position is not found while it should be, cancel sound
2054 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2057 // Filter destination clients
2058 std::vector<session_t> dst_clients;
2059 if (!params.to_player.empty()) {
2060 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2062 infostream<<"Server::playSound: Player \""<<params.to_player
2063 <<"\" not found"<<std::endl;
2066 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2067 infostream<<"Server::playSound: Player \""<<params.to_player
2068 <<"\" not connected"<<std::endl;
2071 dst_clients.push_back(player->getPeerId());
2073 std::vector<session_t> clients = m_clients.getClientIDs();
2075 for (const session_t client_id : clients) {
2076 RemotePlayer *player = m_env->getPlayer(client_id);
2079 if (!params.exclude_player.empty() &&
2080 params.exclude_player == player->getName())
2083 PlayerSAO *sao = player->getPlayerSAO();
2088 if(sao->getBasePosition().getDistanceFrom(pos) >
2089 params.max_hear_distance)
2092 dst_clients.push_back(client_id);
2096 if(dst_clients.empty())
2101 ServerPlayingSound *psound = nullptr;
2103 id = -1; // old clients will still use this, so pick a reserved ID
2106 // The sound will exist as a reference in m_playing_sounds
2107 m_playing_sounds[id] = ServerPlayingSound();
2108 psound = &m_playing_sounds[id];
2109 psound->params = params;
2110 psound->spec = spec;
2113 float gain = params.gain * spec.gain;
2114 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2115 pkt << id << spec.name << gain
2116 << (u8) params.type << pos << params.object
2117 << params.loop << params.fade << params.pitch
2120 bool as_reliable = !ephemeral;
2122 for (const u16 dst_client : dst_clients) {
2124 psound->clients.insert(dst_client);
2125 m_clients.send(dst_client, 0, &pkt, as_reliable);
2129 void Server::stopSound(s32 handle)
2131 // Get sound reference
2132 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2133 m_playing_sounds.find(handle);
2134 if (i == m_playing_sounds.end())
2136 ServerPlayingSound &psound = i->second;
2138 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2141 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2142 si != psound.clients.end(); ++si) {
2144 m_clients.send(*si, 0, &pkt, true);
2146 // Remove sound reference
2147 m_playing_sounds.erase(i);
2150 void Server::fadeSound(s32 handle, float step, float gain)
2152 // Get sound reference
2153 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2154 m_playing_sounds.find(handle);
2155 if (i == m_playing_sounds.end())
2158 ServerPlayingSound &psound = i->second;
2159 psound.params.gain = gain;
2161 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2162 pkt << handle << step << gain;
2164 // Backwards compability
2165 bool play_sound = gain > 0;
2166 ServerPlayingSound compat_psound = psound;
2167 compat_psound.clients.clear();
2169 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2170 compat_pkt << handle;
2172 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2173 it != psound.clients.end();) {
2174 if (m_clients.getProtocolVersion(*it) >= 32) {
2176 m_clients.send(*it, 0, &pkt, true);
2179 compat_psound.clients.insert(*it);
2181 m_clients.send(*it, 0, &compat_pkt, true);
2182 psound.clients.erase(it++);
2186 // Remove sound reference
2187 if (!play_sound || psound.clients.empty())
2188 m_playing_sounds.erase(i);
2190 if (play_sound && !compat_psound.clients.empty()) {
2191 // Play new sound volume on older clients
2192 playSound(compat_psound.spec, compat_psound.params);
2196 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2199 float maxd = far_d_nodes * BS;
2200 v3f p_f = intToFloat(p, BS);
2201 v3s16 block_pos = getNodeBlockPos(p);
2203 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2206 std::vector<session_t> clients = m_clients.getClientIDs();
2209 for (session_t client_id : clients) {
2210 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2214 RemotePlayer *player = m_env->getPlayer(client_id);
2215 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2217 // If player is far away, only set modified blocks not sent
2218 if (!client->isBlockSent(block_pos) || (sao &&
2219 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2221 far_players->emplace(client_id);
2223 client->SetBlockNotSent(block_pos);
2228 m_clients.send(client_id, 0, &pkt, true);
2234 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2235 float far_d_nodes, bool remove_metadata)
2237 float maxd = far_d_nodes * BS;
2238 v3f p_f = intToFloat(p, BS);
2239 v3s16 block_pos = getNodeBlockPos(p);
2241 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2242 pkt << p << n.param0 << n.param1 << n.param2
2243 << (u8) (remove_metadata ? 0 : 1);
2245 std::vector<session_t> clients = m_clients.getClientIDs();
2248 for (session_t client_id : clients) {
2249 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2253 RemotePlayer *player = m_env->getPlayer(client_id);
2254 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2256 // If player is far away, only set modified blocks not sent
2257 if (!client->isBlockSent(block_pos) || (sao &&
2258 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2260 far_players->emplace(client_id);
2262 client->SetBlockNotSent(block_pos);
2267 m_clients.send(client_id, 0, &pkt, true);
2273 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2275 float maxd = far_d_nodes * BS;
2276 NodeMetadataList meta_updates_list(false);
2277 std::vector<session_t> clients = m_clients.getClientIDs();
2281 for (session_t i : clients) {
2282 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2286 ServerActiveObject *player = m_env->getActiveObject(i);
2287 v3f player_pos = player ? player->getBasePosition() : v3f();
2289 for (const v3s16 &pos : meta_updates) {
2290 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2295 v3s16 block_pos = getNodeBlockPos(pos);
2296 if (!client->isBlockSent(block_pos) || (player &&
2297 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2298 client->SetBlockNotSent(block_pos);
2302 // Add the change to send list
2303 meta_updates_list.set(pos, meta);
2305 if (meta_updates_list.size() == 0)
2308 // Send the meta changes
2309 std::ostringstream os(std::ios::binary);
2310 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2311 std::ostringstream oss(std::ios::binary);
2312 compressZlib(os.str(), oss);
2314 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2315 pkt.putLongString(oss.str());
2316 m_clients.send(i, 0, &pkt, true);
2318 meta_updates_list.clear();
2324 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2325 u16 net_proto_version)
2328 Create a packet with the block in the right format
2330 thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
2331 std::ostringstream os(std::ios_base::binary);
2332 block->serialize(os, ver, false, net_compression_level);
2333 block->serializeNetworkSpecific(os);
2334 std::string s = os.str();
2336 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + s.size(), peer_id);
2338 pkt << block->getPos();
2339 pkt.putRawString(s.c_str(), s.size());
2343 void Server::SendBlocks(float dtime)
2345 MutexAutoLock envlock(m_env_mutex);
2346 //TODO check if one big lock could be faster then multiple small ones
2348 std::vector<PrioritySortedBlockTransfer> queue;
2350 u32 total_sending = 0;
2353 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2355 std::vector<session_t> clients = m_clients.getClientIDs();
2358 for (const session_t client_id : clients) {
2359 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2364 total_sending += client->getSendingCount();
2365 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2371 // Lowest priority number comes first.
2372 // Lowest is most important.
2373 std::sort(queue.begin(), queue.end());
2377 // Maximal total count calculation
2378 // The per-client block sends is halved with the maximal online users
2379 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2380 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2382 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2383 Map &map = m_env->getMap();
2385 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2386 if (total_sending >= max_blocks_to_send)
2389 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2393 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2398 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2399 client->net_proto_version);
2401 client->SentBlock(block_to_send.pos);
2407 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2409 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2414 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2415 if (!client || client->isBlockSent(blockpos)) {
2419 SendBlockNoLock(peer_id, block, client->serialization_version,
2420 client->net_proto_version);
2426 bool Server::addMediaFile(const std::string &filename,
2427 const std::string &filepath, std::string *filedata_to,
2428 std::string *digest_to)
2430 // If name contains illegal characters, ignore the file
2431 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2432 infostream << "Server: ignoring illegal file name: \""
2433 << filename << "\"" << std::endl;
2436 // If name is not in a supported format, ignore it
2437 const char *supported_ext[] = {
2438 ".png", ".jpg", ".bmp", ".tga",
2439 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2441 ".x", ".b3d", ".md2", ".obj",
2442 // Custom translation file format
2446 if (removeStringEnd(filename, supported_ext).empty()) {
2447 infostream << "Server: ignoring unsupported file extension: \""
2448 << filename << "\"" << std::endl;
2451 // Ok, attempt to load the file and add to cache
2454 std::string filedata;
2455 if (!fs::ReadFile(filepath, filedata)) {
2456 errorstream << "Server::addMediaFile(): Failed to open \""
2457 << filename << "\" for reading" << std::endl;
2461 if (filedata.empty()) {
2462 errorstream << "Server::addMediaFile(): Empty file \""
2463 << filepath << "\"" << std::endl;
2468 sha1.addBytes(filedata.c_str(), filedata.length());
2470 unsigned char *digest = sha1.getDigest();
2471 std::string sha1_base64 = base64_encode(digest, 20);
2472 std::string sha1_hex = hex_encode((char*) digest, 20);
2474 *digest_to = std::string((char*) digest, 20);
2478 m_media[filename] = MediaInfo(filepath, sha1_base64);
2479 verbosestream << "Server: " << sha1_hex << " is " << filename
2483 *filedata_to = std::move(filedata);
2487 void Server::fillMediaCache()
2489 infostream << "Server: Calculating media file checksums" << std::endl;
2491 // Collect all media file paths
2492 std::vector<std::string> paths;
2493 // The paths are ordered in descending priority
2494 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2495 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2496 m_modmgr->getModsMediaPaths(paths);
2498 // Collect media file information from paths into cache
2499 for (const std::string &mediapath : paths) {
2500 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2501 for (const fs::DirListNode &dln : dirlist) {
2502 if (dln.dir) // Ignore dirs (already in paths)
2505 const std::string &filename = dln.name;
2506 if (m_media.find(filename) != m_media.end()) // Do not override
2509 std::string filepath = mediapath;
2510 filepath.append(DIR_DELIM).append(filename);
2511 addMediaFile(filename, filepath);
2515 infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2518 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2521 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2524 std::string lang_suffix;
2525 lang_suffix.append(".").append(lang_code).append(".tr");
2526 for (const auto &i : m_media) {
2527 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2534 for (const auto &i : m_media) {
2535 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2537 pkt << i.first << i.second.sha1_digest;
2540 pkt << g_settings->get("remote_media");
2543 verbosestream << "Server: Announcing files to id(" << peer_id
2544 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2547 struct SendableMedia
2553 SendableMedia(const std::string &name_="", const std::string &path_="",
2554 const std::string &data_=""):
2561 void Server::sendRequestedMedia(session_t peer_id,
2562 const std::vector<std::string> &tosend)
2564 verbosestream<<"Server::sendRequestedMedia(): "
2565 <<"Sending files to client"<<std::endl;
2569 // Put 5kB in one bunch (this is not accurate)
2570 u32 bytes_per_bunch = 5000;
2572 std::vector< std::vector<SendableMedia> > file_bunches;
2573 file_bunches.emplace_back();
2575 u32 file_size_bunch_total = 0;
2577 for (const std::string &name : tosend) {
2578 if (m_media.find(name) == m_media.end()) {
2579 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2580 <<"unknown file \""<<(name)<<"\""<<std::endl;
2584 //TODO get path + name
2585 std::string tpath = m_media[name].path;
2588 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2590 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2591 <<tpath<<"\" for reading"<<std::endl;
2594 std::ostringstream tmp_os(std::ios_base::binary);
2598 fis.read(buf, 1024);
2599 std::streamsize len = fis.gcount();
2600 tmp_os.write(buf, len);
2601 file_size_bunch_total += len;
2610 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2611 <<name<<"\""<<std::endl;
2614 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2615 <<tname<<"\""<<std::endl;*/
2617 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2619 // Start next bunch if got enough data
2620 if(file_size_bunch_total >= bytes_per_bunch) {
2621 file_bunches.emplace_back();
2622 file_size_bunch_total = 0;
2627 /* Create and send packets */
2629 u16 num_bunches = file_bunches.size();
2630 for (u16 i = 0; i < num_bunches; i++) {
2633 u16 total number of texture bunches
2634 u16 index of this bunch
2635 u32 number of files in this bunch
2644 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2645 pkt << num_bunches << i << (u32) file_bunches[i].size();
2647 for (const SendableMedia &j : file_bunches[i]) {
2649 pkt.putLongString(j.data);
2652 verbosestream << "Server::sendRequestedMedia(): bunch "
2653 << i << "/" << num_bunches
2654 << " files=" << file_bunches[i].size()
2655 << " size=" << pkt.getSize() << std::endl;
2660 void Server::SendMinimapModes(session_t peer_id,
2661 std::vector<MinimapMode> &modes, size_t wanted_mode)
2663 RemotePlayer *player = m_env->getPlayer(peer_id);
2665 if (player->getPeerId() == PEER_ID_INEXISTENT)
2668 NetworkPacket pkt(TOCLIENT_MINIMAP_MODES, 0, peer_id);
2669 pkt << (u16)modes.size() << (u16)wanted_mode;
2671 for (auto &mode : modes)
2672 pkt << (u16)mode.type << mode.label << mode.size << mode.texture << mode.scale;
2677 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2679 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2683 pkt << false; // Remove inventory
2685 pkt << true; // Update inventory
2687 // Serialization & NetworkPacket isn't a love story
2688 std::ostringstream os(std::ios_base::binary);
2689 inventory->serialize(os);
2690 inventory->setModified(false);
2692 const std::string &os_str = os.str();
2693 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2694 pkt.putRawString(os_str);
2697 if (peer_id == PEER_ID_INEXISTENT)
2698 m_clients.sendToAll(&pkt);
2703 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2705 // Lookup player name, to filter detached inventories just after
2706 std::string peer_name;
2707 if (peer_id != PEER_ID_INEXISTENT) {
2708 peer_name = getClient(peer_id, CS_Created)->getName();
2711 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2712 sendDetachedInventory(inv, name, peer_id);
2715 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2722 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2724 PlayerSAO *playersao = getPlayerSAO(peer_id);
2727 infostream << "Server::DiePlayer(): Player "
2728 << playersao->getPlayer()->getName()
2729 << " dies" << std::endl;
2731 playersao->setHP(0, reason);
2732 playersao->clearParentAttachment();
2734 // Trigger scripted stuff
2735 m_script->on_dieplayer(playersao, reason);
2737 SendPlayerHP(peer_id);
2738 SendDeathscreen(peer_id, false, v3f(0,0,0));
2741 void Server::RespawnPlayer(session_t peer_id)
2743 PlayerSAO *playersao = getPlayerSAO(peer_id);
2746 infostream << "Server::RespawnPlayer(): Player "
2747 << playersao->getPlayer()->getName()
2748 << " respawns" << std::endl;
2750 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2751 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2752 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2754 bool repositioned = m_script->on_respawnplayer(playersao);
2755 if (!repositioned) {
2756 // setPos will send the new position to client
2757 playersao->setPos(findSpawnPos());
2760 SendPlayerHP(peer_id);
2764 void Server::DenySudoAccess(session_t peer_id)
2766 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2771 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2772 const std::string &str_reason, bool reconnect)
2774 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2776 m_clients.event(peer_id, CSE_SetDenied);
2777 DisconnectPeer(peer_id);
2781 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2782 const std::string &custom_reason)
2784 SendAccessDenied(peer_id, reason, custom_reason);
2785 m_clients.event(peer_id, CSE_SetDenied);
2786 DisconnectPeer(peer_id);
2789 // 13/03/15: remove this function when protocol version 25 will become
2790 // the minimum version for MT users, maybe in 1 year
2791 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2793 SendAccessDenied_Legacy(peer_id, reason);
2794 m_clients.event(peer_id, CSE_SetDenied);
2795 DisconnectPeer(peer_id);
2798 void Server::DisconnectPeer(session_t peer_id)
2800 m_modchannel_mgr->leaveAllChannels(peer_id);
2801 m_con->DisconnectPeer(peer_id);
2804 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2807 RemoteClient* client = getClient(peer_id, CS_Invalid);
2809 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2811 // Right now, the auth mechs don't change between login and sudo mode.
2812 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2813 client->allowed_sudo_mechs = sudo_auth_mechs;
2815 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2816 << g_settings->getFloat("dedicated_server_step")
2820 m_clients.event(peer_id, CSE_AuthAccept);
2822 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2824 // We only support SRP right now
2825 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2827 resp_pkt << sudo_auth_mechs;
2829 m_clients.event(peer_id, CSE_SudoSuccess);
2833 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2835 std::wstring message;
2838 Clear references to playing sounds
2840 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2841 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2842 ServerPlayingSound &psound = i->second;
2843 psound.clients.erase(peer_id);
2844 if (psound.clients.empty())
2845 m_playing_sounds.erase(i++);
2850 // clear formspec info so the next client can't abuse the current state
2851 m_formspec_state_data.erase(peer_id);
2853 RemotePlayer *player = m_env->getPlayer(peer_id);
2855 /* Run scripts and remove from environment */
2857 PlayerSAO *playersao = player->getPlayerSAO();
2860 playersao->clearChildAttachments();
2861 playersao->clearParentAttachment();
2863 // inform connected clients
2864 const std::string &player_name = player->getName();
2865 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2866 // (u16) 1 + std::string represents a vector serialization representation
2867 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2868 m_clients.sendToAll(¬ice);
2870 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2872 playersao->disconnected();
2879 if (player && reason != CDR_DENY) {
2880 std::ostringstream os(std::ios_base::binary);
2881 std::vector<session_t> clients = m_clients.getClientIDs();
2883 for (const session_t client_id : clients) {
2885 RemotePlayer *player = m_env->getPlayer(client_id);
2889 // Get name of player
2890 os << player->getName() << " ";
2893 std::string name = player->getName();
2894 actionstream << name << " "
2895 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2896 << " List of players: " << os.str() << std::endl;
2898 m_admin_chat->outgoing_queue.push_back(
2899 new ChatEventNick(CET_NICK_REMOVE, name));
2903 MutexAutoLock env_lock(m_env_mutex);
2904 m_clients.DeleteClient(peer_id);
2908 // Send leave chat message to all remaining clients
2909 if (!message.empty()) {
2910 SendChatMessage(PEER_ID_INEXISTENT,
2911 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2915 void Server::UpdateCrafting(RemotePlayer *player)
2917 InventoryList *clist = player->inventory.getList("craft");
2918 if (!clist || clist->getSize() == 0)
2921 if (!clist->checkModified())
2924 // Get a preview for crafting
2926 InventoryLocation loc;
2927 loc.setPlayer(player->getName());
2928 std::vector<ItemStack> output_replacements;
2929 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2930 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2933 InventoryList *plist = player->inventory.getList("craftpreview");
2934 if (plist && plist->getSize() >= 1) {
2935 // Put the new preview in
2936 plist->changeItem(0, preview);
2940 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2942 if (evt->type == CET_NICK_ADD) {
2943 // The terminal informed us of its nick choice
2944 m_admin_nick = ((ChatEventNick *)evt)->nick;
2945 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2946 errorstream << "You haven't set up an account." << std::endl
2947 << "Please log in using the client as '"
2948 << m_admin_nick << "' with a secure password." << std::endl
2949 << "Until then, you can't execute admin tasks via the console," << std::endl
2950 << "and everybody can claim the user account instead of you," << std::endl
2951 << "giving them full control over this server." << std::endl;
2954 assert(evt->type == CET_CHAT);
2955 handleAdminChat((ChatEventChat *)evt);
2959 std::wstring Server::handleChat(const std::string &name,
2960 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2962 // If something goes wrong, this player is to blame
2963 RollbackScopeActor rollback_scope(m_rollback,
2964 std::string("player:") + name);
2966 if (g_settings->getBool("strip_color_codes"))
2967 wmessage = unescape_enriched(wmessage);
2970 switch (player->canSendChatMessage()) {
2971 case RPLAYER_CHATRESULT_FLOODING: {
2972 std::wstringstream ws;
2973 ws << L"You cannot send more messages. You are limited to "
2974 << g_settings->getFloat("chat_message_limit_per_10sec")
2975 << L" messages per 10 seconds.";
2978 case RPLAYER_CHATRESULT_KICK:
2979 DenyAccess_Legacy(player->getPeerId(),
2980 L"You have been kicked due to message flooding.");
2982 case RPLAYER_CHATRESULT_OK:
2985 FATAL_ERROR("Unhandled chat filtering result found.");
2989 if (m_max_chatmessage_length > 0
2990 && wmessage.length() > m_max_chatmessage_length) {
2991 return L"Your message exceed the maximum chat message limit set on the server. "
2992 L"It was refused. Send a shorter message";
2995 auto message = trim(wide_to_utf8(wmessage));
2996 if (message.find_first_of("\n\r") != std::wstring::npos) {
2997 return L"Newlines are not permitted in chat messages";
3000 // Run script hook, exit if script ate the chat message
3001 if (m_script->on_chat_message(name, message))
3006 // Whether to send line to the player that sent the message, or to all players
3007 bool broadcast_line = true;
3009 if (check_shout_priv && !checkPriv(name, "shout")) {
3010 line += L"-!- You don't have permission to shout.";
3011 broadcast_line = false;
3014 Workaround for fixing chat on Android. Lua doesn't handle
3015 the Cyrillic alphabet and some characters on older Android devices
3018 line += L"<" + utf8_to_wide(name) + L"> " + wmessage;
3020 line += utf8_to_wide(m_script->formatChatMessage(name,
3021 wide_to_utf8(wmessage)));
3026 Tell calling method to send the message to sender
3028 if (!broadcast_line)
3032 Send the message to others
3034 actionstream << "CHAT: " << wide_to_utf8(unescape_enriched(line)) << std::endl;
3036 ChatMessage chatmsg(line);
3038 std::vector<session_t> clients = m_clients.getClientIDs();
3039 for (u16 cid : clients)
3040 SendChatMessage(cid, chatmsg);
3045 void Server::handleAdminChat(const ChatEventChat *evt)
3047 std::string name = evt->nick;
3048 std::wstring wmessage = evt->evt_msg;
3050 std::wstring answer = handleChat(name, wmessage);
3052 // If asked to send answer to sender
3053 if (!answer.empty()) {
3054 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3058 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3060 RemoteClient *client = getClientNoEx(peer_id,state_min);
3062 throw ClientNotFoundException("Client not found");
3066 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3068 return m_clients.getClientNoEx(peer_id, state_min);
3071 std::string Server::getPlayerName(session_t peer_id)
3073 RemotePlayer *player = m_env->getPlayer(peer_id);
3075 return "[id="+itos(peer_id)+"]";
3076 return player->getName();
3079 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3081 RemotePlayer *player = m_env->getPlayer(peer_id);
3084 return player->getPlayerSAO();
3087 std::string Server::getStatusString()
3089 std::ostringstream os(std::ios_base::binary);
3092 os << "version=" << g_version_string;
3094 os << ", uptime=" << m_uptime_counter->get();
3096 os << ", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3098 // Information about clients
3100 os << ", clients={";
3102 std::vector<session_t> clients = m_clients.getClientIDs();
3103 for (session_t client_id : clients) {
3104 RemotePlayer *player = m_env->getPlayer(client_id);
3106 // Get name of player
3107 const char *name = player ? player->getName() : "<unknown>";
3109 // Add name to information string
3119 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3120 os << std::endl << "# Server: " << " WARNING: Map saving is disabled.";
3122 if (!g_settings->get("motd").empty())
3123 os << std::endl << "# Server: " << g_settings->get("motd");
3128 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3130 std::set<std::string> privs;
3131 m_script->getAuth(name, NULL, &privs);
3135 bool Server::checkPriv(const std::string &name, const std::string &priv)
3137 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3138 return (privs.count(priv) != 0);
3141 void Server::reportPrivsModified(const std::string &name)
3144 std::vector<session_t> clients = m_clients.getClientIDs();
3145 for (const session_t client_id : clients) {
3146 RemotePlayer *player = m_env->getPlayer(client_id);
3147 reportPrivsModified(player->getName());
3150 RemotePlayer *player = m_env->getPlayer(name.c_str());
3153 SendPlayerPrivileges(player->getPeerId());
3154 PlayerSAO *sao = player->getPlayerSAO();
3157 sao->updatePrivileges(
3158 getPlayerEffectivePrivs(name),
3163 void Server::reportInventoryFormspecModified(const std::string &name)
3165 RemotePlayer *player = m_env->getPlayer(name.c_str());
3168 SendPlayerInventoryFormspec(player->getPeerId());
3171 void Server::reportFormspecPrependModified(const std::string &name)
3173 RemotePlayer *player = m_env->getPlayer(name.c_str());
3176 SendPlayerFormspecPrepend(player->getPeerId());
3179 void Server::setIpBanned(const std::string &ip, const std::string &name)
3181 m_banmanager->add(ip, name);
3184 void Server::unsetIpBanned(const std::string &ip_or_name)
3186 m_banmanager->remove(ip_or_name);
3189 std::string Server::getBanDescription(const std::string &ip_or_name)
3191 return m_banmanager->getBanDescription(ip_or_name);
3194 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3196 // m_env will be NULL if the server is initializing
3200 if (m_admin_nick == name && !m_admin_nick.empty()) {
3201 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3204 RemotePlayer *player = m_env->getPlayer(name);
3209 if (player->getPeerId() == PEER_ID_INEXISTENT)
3212 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3215 bool Server::showFormspec(const char *playername, const std::string &formspec,
3216 const std::string &formname)
3218 // m_env will be NULL if the server is initializing
3222 RemotePlayer *player = m_env->getPlayer(playername);
3226 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3230 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3235 u32 id = player->addHud(form);
3237 SendHUDAdd(player->getPeerId(), id, form);
3242 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3246 HudElement* todel = player->removeHud(id);
3253 SendHUDRemove(player->getPeerId(), id);
3257 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3262 SendHUDChange(player->getPeerId(), id, stat, data);
3266 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3271 SendHUDSetFlags(player->getPeerId(), flags, mask);
3272 player->hud_flags &= ~mask;
3273 player->hud_flags |= flags;
3275 PlayerSAO* playersao = player->getPlayerSAO();
3280 m_script->player_event(playersao, "hud_changed");
3284 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3289 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3292 player->setHotbarItemcount(hotbar_itemcount);
3293 std::ostringstream os(std::ios::binary);
3294 writeS32(os, hotbar_itemcount);
3295 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3299 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3304 player->setHotbarImage(name);
3305 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3308 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3313 player->setHotbarSelectedImage(name);
3314 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3317 Address Server::getPeerAddress(session_t peer_id)
3319 // Note that this is only set after Init was received in Server::handleCommand_Init
3320 return getClient(peer_id, CS_Invalid)->getAddress();
3323 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3324 v2s32 animation_frames[4], f32 frame_speed)
3326 sanity_check(player);
3327 player->setLocalAnimations(animation_frames, frame_speed);
3328 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3331 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3333 sanity_check(player);
3334 player->eye_offset_first = first;
3335 player->eye_offset_third = third;
3336 SendEyeOffset(player->getPeerId(), first, third);
3339 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3341 sanity_check(player);
3342 player->setSky(params);
3343 SendSetSky(player->getPeerId(), params);
3346 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3348 sanity_check(player);
3349 player->setSun(params);
3350 SendSetSun(player->getPeerId(), params);
3353 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3355 sanity_check(player);
3356 player->setMoon(params);
3357 SendSetMoon(player->getPeerId(), params);
3360 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3362 sanity_check(player);
3363 player->setStars(params);
3364 SendSetStars(player->getPeerId(), params);
3367 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3369 sanity_check(player);
3370 player->setCloudParams(params);
3371 SendCloudParams(player->getPeerId(), params);
3374 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3377 sanity_check(player);
3378 player->overrideDayNightRatio(do_override, ratio);
3379 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3382 void Server::notifyPlayers(const std::wstring &msg)
3384 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3387 void Server::spawnParticle(const std::string &playername,
3388 const ParticleParameters &p)
3390 // m_env will be NULL if the server is initializing
3394 session_t peer_id = PEER_ID_INEXISTENT;
3396 if (!playername.empty()) {
3397 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3400 peer_id = player->getPeerId();
3401 proto_ver = player->protocol_version;
3404 SendSpawnParticle(peer_id, proto_ver, p);
3407 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3408 ServerActiveObject *attached, const std::string &playername)
3410 // m_env will be NULL if the server is initializing
3414 session_t peer_id = PEER_ID_INEXISTENT;
3416 if (!playername.empty()) {
3417 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3420 peer_id = player->getPeerId();
3421 proto_ver = player->protocol_version;
3424 u16 attached_id = attached ? attached->getId() : 0;
3427 if (attached_id == 0)
3428 id = m_env->addParticleSpawner(p.time);
3430 id = m_env->addParticleSpawner(p.time, attached_id);
3432 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3436 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3438 // m_env will be NULL if the server is initializing
3440 throw ServerError("Can't delete particle spawners during initialisation!");
3442 session_t peer_id = PEER_ID_INEXISTENT;
3443 if (!playername.empty()) {
3444 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3447 peer_id = player->getPeerId();
3450 m_env->deleteParticleSpawner(id);
3451 SendDeleteParticleSpawner(peer_id, id);
3454 bool Server::dynamicAddMedia(const std::string &filepath,
3455 std::vector<RemotePlayer*> &sent_to)
3457 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3458 if (m_media.find(filename) != m_media.end()) {
3459 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3460 << "\" already exists in media cache" << std::endl;
3464 // Load the file and add it to our media cache
3465 std::string filedata, raw_hash;
3466 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3470 // Push file to existing clients
3471 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3472 pkt << raw_hash << filename << (bool) true;
3473 pkt.putLongString(filedata);
3476 for (auto &pair : m_clients.getClientList()) {
3477 if (pair.second->getState() < CS_DefinitionsSent)
3479 if (pair.second->net_proto_version < 39)
3482 if (auto player = m_env->getPlayer(pair.second->peer_id))
3483 sent_to.emplace_back(player);
3485 FIXME: this is a very awful hack
3486 The network layer only guarantees ordered delivery inside a channel.
3487 Since the very next packet could be one that uses the media, we have
3488 to push the media over ALL channels to ensure it is processed before
3490 In practice this means we have to send it twice:
3492 - channel 0 (everything else: e.g. play_sound, object messages)
3494 m_clients.send(pair.second->peer_id, 1, &pkt, true);
3495 m_clients.send(pair.second->peer_id, 0, &pkt, true);
3502 // actions: time-reversed list
3503 // Return value: success/failure
3504 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3505 std::list<std::string> *log)
3507 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3508 ServerMap *map = (ServerMap*)(&m_env->getMap());
3510 // Fail if no actions to handle
3511 if (actions.empty()) {
3513 log->push_back("Nothing to do.");
3520 for (const RollbackAction &action : actions) {
3522 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3525 std::ostringstream os;
3526 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3527 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3529 log->push_back(os.str());
3531 std::ostringstream os;
3532 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3533 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3535 log->push_back(os.str());
3539 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3540 <<" failed"<<std::endl;
3542 // Call it done if less than half failed
3543 return num_failed <= num_tried/2;
3546 // IGameDef interface
3548 IItemDefManager *Server::getItemDefManager()
3553 const NodeDefManager *Server::getNodeDefManager()
3558 ICraftDefManager *Server::getCraftDefManager()
3563 u16 Server::allocateUnknownNodeId(const std::string &name)
3565 return m_nodedef->allocateDummy(name);
3568 IWritableItemDefManager *Server::getWritableItemDefManager()
3573 NodeDefManager *Server::getWritableNodeDefManager()
3578 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3583 const std::vector<ModSpec> & Server::getMods() const
3585 return m_modmgr->getMods();
3588 const ModSpec *Server::getModSpec(const std::string &modname) const
3590 return m_modmgr->getModSpec(modname);
3593 void Server::getModNames(std::vector<std::string> &modlist)
3595 m_modmgr->getModNames(modlist);
3598 std::string Server::getBuiltinLuaPath()
3600 return porting::path_share + DIR_DELIM + "builtin";
3603 std::string Server::getModStoragePath() const
3605 return m_path_world + DIR_DELIM + "mod_storage";
3608 v3f Server::findSpawnPos()
3610 ServerMap &map = m_env->getServerMap();
3612 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3613 return nodeposf * BS;
3615 bool is_good = false;
3616 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3617 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3619 // Try to find a good place a few times
3620 for (s32 i = 0; i < 4000 && !is_good; i++) {
3621 s32 range = MYMIN(1 + i, range_max);
3622 // We're going to try to throw the player to this position
3623 v2s16 nodepos2d = v2s16(
3624 -range + (myrand() % (range * 2)),
3625 -range + (myrand() % (range * 2)));
3626 // Get spawn level at point
3627 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3628 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3629 // signify an unsuitable spawn position, or if outside limits.
3630 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3631 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3634 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3635 // Consecutive empty nodes
3638 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3639 // avoid obstructions in already-generated mapblocks.
3640 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3641 // no obstructions, but mapgen decorations are generated after spawn so
3642 // the player may end up inside one.
3643 for (s32 i = 0; i < 8; i++) {
3644 v3s16 blockpos = getNodeBlockPos(nodepos);
3645 map.emergeBlock(blockpos, true);
3646 content_t c = map.getNode(nodepos).getContent();
3648 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3649 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3650 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3652 if (air_count >= 2) {
3653 // Spawn in lower empty node
3655 nodeposf = intToFloat(nodepos, BS);
3656 // Don't spawn the player outside map boundaries
3657 if (objectpos_over_limit(nodeposf))
3658 // Exit this loop, positions above are probably over limit
3661 // Good position found, cause an exit from main loop
3675 // No suitable spawn point found, return fallback 0,0,0
3676 return v3f(0.0f, 0.0f, 0.0f);
3679 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3681 if (delay == 0.0f) {
3682 // No delay, shutdown immediately
3683 m_shutdown_state.is_requested = true;
3684 // only print to the infostream, a chat message saying
3685 // "Server Shutting Down" is sent when the server destructs.
3686 infostream << "*** Immediate Server shutdown requested." << std::endl;
3687 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3688 // Negative delay, cancel shutdown if requested
3689 m_shutdown_state.reset();
3690 std::wstringstream ws;
3692 ws << L"*** Server shutdown canceled.";
3694 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3695 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3696 // m_shutdown_* are already handled, skip.
3698 } else if (delay > 0.0f) {
3699 // Positive delay, tell the clients when the server will shut down
3700 std::wstringstream ws;
3702 ws << L"*** Server shutting down in "
3703 << duration_to_string(myround(delay)).c_str()
3706 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3707 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3710 m_shutdown_state.trigger(delay, msg, reconnect);
3713 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3716 Try to get an existing player
3718 RemotePlayer *player = m_env->getPlayer(name);
3720 // If player is already connected, cancel
3721 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3722 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3727 If player with the wanted peer_id already exists, cancel.
3729 if (m_env->getPlayer(peer_id)) {
3730 infostream<<"emergePlayer(): Player with wrong name but same"
3731 " peer_id already exists"<<std::endl;
3736 player = new RemotePlayer(name, idef());
3739 bool newplayer = false;
3742 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3744 // Complete init with server parts
3745 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3746 player->protocol_version = proto_version;
3750 m_script->on_newplayer(playersao);
3756 bool Server::registerModStorage(ModMetadata *storage)
3758 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3759 errorstream << "Unable to register same mod storage twice. Storage name: "
3760 << storage->getModName() << std::endl;
3764 m_mod_storages[storage->getModName()] = storage;
3768 void Server::unregisterModStorage(const std::string &name)
3770 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3771 if (it != m_mod_storages.end()) {
3772 // Save unconditionaly on unregistration
3773 it->second->save(getModStoragePath());
3774 m_mod_storages.erase(name);
3778 void dedicated_server_loop(Server &server, bool &kill)
3780 verbosestream<<"dedicated_server_loop()"<<std::endl;
3782 IntervalLimiter m_profiler_interval;
3784 static thread_local const float steplen =
3785 g_settings->getFloat("dedicated_server_step");
3786 static thread_local const float profiler_print_interval =
3787 g_settings->getFloat("profiler_print_interval");
3790 * The dedicated server loop only does time-keeping (in Server::step) and
3791 * provides a way to main.cpp to kill the server externally (bool &kill).
3795 // This is kind of a hack but can be done like this
3796 // because server.step() is very light
3797 sleep_ms((int)(steplen*1000.0));
3798 server.step(steplen);
3800 if (server.isShutdownRequested() || kill)
3806 if (profiler_print_interval != 0) {
3807 if(m_profiler_interval.step(steplen, profiler_print_interval))
3809 infostream<<"Profiler:"<<std::endl;
3810 g_profiler->print(infostream);
3811 g_profiler->clear();
3816 infostream << "Dedicated server quitting" << std::endl;
3818 if (g_settings->getBool("server_announce"))
3819 ServerList::sendAnnounce(ServerList::AA_DELETE,
3820 server.m_bind_addr.getPort());
3829 bool Server::joinModChannel(const std::string &channel)
3831 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3832 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3835 bool Server::leaveModChannel(const std::string &channel)
3837 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3840 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3842 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3845 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3849 ModChannel* Server::getModChannel(const std::string &channel)
3851 return m_modchannel_mgr->getModChannel(channel);
3854 void Server::broadcastModChannelMessage(const std::string &channel,
3855 const std::string &message, session_t from_peer)
3857 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3861 if (message.size() > STRING_MAX_LEN) {
3862 warningstream << "ModChannel message too long, dropping before sending "
3863 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3864 << channel << ")" << std::endl;
3869 if (from_peer != PEER_ID_SERVER) {
3870 sender = getPlayerName(from_peer);
3873 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3874 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3875 resp_pkt << channel << sender << message;
3876 for (session_t peer_id : peers) {
3878 if (peer_id == from_peer)
3881 Send(peer_id, &resp_pkt);
3884 if (from_peer != PEER_ID_SERVER) {
3885 m_script->on_modchannel_message(channel, sender, message);
3889 Translations *Server::getTranslationLanguage(const std::string &lang_code)
3891 if (lang_code.empty())
3894 auto it = server_translations.find(lang_code);
3895 if (it != server_translations.end())
3896 return &it->second; // Already loaded
3898 // [] will create an entry
3899 auto *translations = &server_translations[lang_code];
3901 std::string suffix = "." + lang_code + ".tr";
3902 for (const auto &i : m_media) {
3903 if (str_ends_with(i.first, suffix)) {
3905 if (fs::ReadFile(i.second.path, data)) {
3906 translations->loadTranslation(data);
3911 return translations;