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) : BaseException(s) {}
76 class ServerThread : public Thread
79 ServerThread(Server *server) : Thread("Server"), m_server(server) {}
87 void *ServerThread::run()
89 BEGIN_DEBUG_EXCEPTION_HANDLER
92 * The real business of the server happens on the ServerThread.
94 * AsyncRunStep() runs an actual server step as soon as enough time has
95 * passed (dedicated_server_loop keeps track of that).
96 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
97 * doesn't busy wait) and will process any remaining packets.
100 m_server->AsyncRunStep(true);
102 while (!stopRequested()) {
104 m_server->AsyncRunStep();
108 } catch (con::PeerNotFoundException &e) {
109 infostream << "Server: PeerNotFoundException" << std::endl;
110 } catch (ClientNotFoundException &e) {
111 } catch (con::ConnectionBindFailed &e) {
112 m_server->setAsyncFatalError(e.what());
113 } catch (LuaError &e) {
114 m_server->setAsyncFatalError("ServerThread::run Lua: " +
115 std::string(e.what()));
119 END_DEBUG_EXCEPTION_HANDLER
124 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
138 ServerActiveObject *sao = env->getActiveObject(object);
143 return sao->getBasePosition();
149 void Server::ShutdownState::reset()
153 should_reconnect = false;
154 is_requested = false;
157 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
161 should_reconnect = reconnect;
164 void Server::ShutdownState::tick(float dtime, Server *server)
170 static const float shutdown_msg_times[] = {1, 2, 3, 4, 5, 10, 20, 40, 60, 120,
171 180, 300, 600, 1200, 1800, 3600};
173 // Automated messages
174 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
175 for (float t : shutdown_msg_times) {
176 // If shutdown timer matches an automessage, shot it
177 if (m_timer > t && m_timer - dtime < t) {
178 std::wstring periodicMsg = getShutdownTimerMessage();
180 infostream << wide_to_utf8(periodicMsg).c_str()
182 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
189 if (m_timer < 0.0f) {
195 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
197 std::wstringstream ws;
198 ws << L"*** Server shutting down in "
199 << duration_to_string(myround(m_timer)).c_str() << ".";
207 Server::Server(const std::string &path_world, const SubgameSpec &gamespec,
208 bool simple_singleplayer_mode, Address bind_addr, bool dedicated,
209 ChatInterface *iface) :
210 m_bind_addr(bind_addr),
211 m_path_world(path_world), m_gamespec(gamespec),
212 m_simple_singleplayer_mode(simple_singleplayer_mode),
213 m_dedicated(dedicated), m_async_fatal_error(""),
214 m_con(std::make_shared<con::Connection>(PROTOCOL_ID, 512,
215 CONNECTION_TIMEOUT, m_bind_addr.isIPv6(), this)),
216 m_itemdef(createItemDefManager()), m_nodedef(createNodeDefManager()),
217 m_craftdef(createCraftDefManager()), m_thread(new ServerThread(this)),
218 m_clients(m_con), m_admin_chat(iface),
219 m_modchannel_mgr(new ModChannelMgr())
221 if (m_path_world.empty())
222 throw ServerError("Supplied empty world path");
224 if (!gamespec.isValid())
225 throw ServerError("Supplied invalid gamespec");
229 std::unique_ptr<MetricsBackend>(createPrometheusMetricsBackend());
231 m_metrics_backend = std::unique_ptr<MetricsBackend>(new MetricsBackend());
234 m_uptime_counter = m_metrics_backend->addCounter(
235 "minetest_core_server_uptime", "Server uptime (in seconds)");
236 m_player_gauge = m_metrics_backend->addGauge(
237 "minetest_core_player_number", "Number of connected players");
239 m_timeofday_gauge = m_metrics_backend->addGauge(
240 "minetest_core_timeofday", "Time of day value");
242 m_lag_gauge = m_metrics_backend->addGauge(
243 "minetest_core_latency", "Latency value (in seconds)");
245 m_aom_buffer_counter =
246 m_metrics_backend->addCounter("minetest_core_aom_generated_count",
247 "Number of active object messages generated");
249 m_packet_recv_counter =
250 m_metrics_backend->addCounter("minetest_core_server_packet_recv",
251 "Processable packets received");
253 m_packet_recv_processed_counter = m_metrics_backend->addCounter(
254 "minetest_core_server_packet_recv_processed",
255 "Valid received packets processed");
257 m_lag_gauge->set(g_settings->getFloat("dedicated_server_step"));
263 // Send shutdown message
264 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
265 L"*** Server shutting down"));
268 MutexAutoLock envlock(m_env_mutex);
270 infostream << "Server: Saving players" << std::endl;
271 m_env->saveLoadedPlayers();
273 infostream << "Server: Kicking players" << std::endl;
274 std::string kick_msg;
275 bool reconnect = false;
276 if (isShutdownRequested()) {
277 reconnect = m_shutdown_state.should_reconnect;
278 kick_msg = m_shutdown_state.message;
280 if (kick_msg.empty()) {
281 kick_msg = g_settings->get("kick_msg_shutdown");
283 m_env->saveLoadedPlayers(true);
284 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN, kick_msg, reconnect);
287 actionstream << "Server: Shutting down" << std::endl;
289 // Do this before stopping the server in case mapgen callbacks need to access
290 // server-controlled resources (like ModStorages). Also do them before
291 // shutdown callbacks since they may modify state that is finalized in a
294 m_emerge->stopThreads();
297 MutexAutoLock envlock(m_env_mutex);
299 // Execute script shutdown hooks
300 infostream << "Executing shutdown hooks" << std::endl;
301 m_script->on_shutdown();
303 infostream << "Server: Saving environment metadata" << std::endl;
313 // Delete things in the reverse order of creation
322 // Deinitialize scripting
323 infostream << "Server: Deinitializing scripting" << std::endl;
326 while (!m_unsent_map_edit_queue.empty()) {
327 delete m_unsent_map_edit_queue.front();
328 m_unsent_map_edit_queue.pop();
334 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
335 if (m_simple_singleplayer_mode)
336 infostream << " in simple singleplayer mode" << std::endl;
338 infostream << std::endl;
339 infostream << "- world: " << m_path_world << std::endl;
340 infostream << "- game: " << m_gamespec.path << std::endl;
342 // Create world if it doesn't exist
343 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
344 throw ServerError("Failed to initialize world");
346 // Create emerge manager
347 m_emerge = new EmergeManager(this);
349 // Create ban manager
350 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
351 m_banmanager = new BanManager(ban_path);
353 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
354 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
355 // complain about mods with unsatisfied dependencies
356 if (!m_modmgr->isConsistent()) {
357 m_modmgr->printUnsatisfiedModsError();
361 MutexAutoLock envlock(m_env_mutex);
363 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
364 ServerMap *servermap = new ServerMap(
365 m_path_world, this, m_emerge, m_metrics_backend.get());
367 // Initialize scripting
368 infostream << "Server: Initializing Lua" << std::endl;
370 m_script = new ServerScripting(this);
372 // Must be created before mod loading because we have some inventory creation
373 m_inventory_mgr = std::unique_ptr<ServerInventoryManager>(
374 new ServerInventoryManager());
376 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
378 m_modmgr->loadMods(m_script);
380 // Read Textures and calculate sha1 sums
383 // Apply item aliases in the node definition manager
384 m_nodedef->updateAliases(m_itemdef);
386 // Apply texture overrides from texturepack/override.txt
387 std::vector<std::string> paths;
388 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
389 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
390 for (const std::string &path : paths) {
391 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
392 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
393 m_itemdef->applyTextureOverrides(
394 override_source.getItemTextureOverrides());
397 m_nodedef->setNodeRegistrationStatus(true);
399 // Perform pending node name resolutions
400 m_nodedef->runNodeResolveCallbacks();
402 // unmap node names in cross-references
403 m_nodedef->resolveCrossrefs();
405 // init the recipe hashes to speed up crafting
406 m_craftdef->initHashes(this);
408 // Initialize Environment
409 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
411 m_inventory_mgr->setEnv(m_env);
412 m_clients.setEnv(m_env);
414 if (!servermap->settings_mgr.makeMapgenParams())
415 FATAL_ERROR("Couldn't create any mapgen type");
417 // Initialize mapgens
418 m_emerge->initMapgens(servermap->getMapgenParams());
420 if (g_settings->getBool("enable_rollback_recording")) {
421 // Create rollback manager
422 m_rollback = new RollbackManager(m_path_world, this);
425 // Give environment reference to scripting api
426 m_script->initializeEnvironment(m_env);
428 // Register us to receive map edit events
429 servermap->addEventReceiver(this);
433 // Those settings can be overwritten in world.mt, they are
434 // intended to be cached after environment loading.
435 m_liquid_transform_every = g_settings->getFloat("liquid_update");
436 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
437 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
438 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
445 infostream << "Starting server on " << m_bind_addr.serializeString() << "..."
448 // Stop thread if already running
451 // Initialize connection
452 m_con->SetTimeoutMs(30);
453 m_con->Serve(m_bind_addr);
458 // ASCII art for the win!
459 std::cerr << " .__ __ __ " << std::endl
460 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
461 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"
463 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "
465 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
466 << " \\/ \\/ \\/ \\/ \\/ "
468 actionstream << "World at [" << m_path_world << "]" << std::endl;
469 actionstream << "Server for gameid=\"" << m_gamespec.id << "\" listening on "
470 << m_bind_addr.serializeString() << ":" << m_bind_addr.getPort()
476 infostream << "Server: Stopping and waiting threads" << std::endl;
478 // Stop threads (set run=false first so both start stopping)
480 // m_emergethread.setRun(false);
482 // m_emergethread.stop();
484 infostream << "Server: Threads stopped" << std::endl;
487 void Server::step(float dtime)
493 MutexAutoLock lock(m_step_dtime_mutex);
494 m_step_dtime += dtime;
496 // Throw if fatal error occurred in thread
497 std::string async_err = m_async_fatal_error.get();
498 if (!async_err.empty()) {
499 if (!m_simple_singleplayer_mode) {
500 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
501 g_settings->get("kick_msg_crash"),
502 g_settings->getBool("ask_reconnect_on_crash"));
504 throw ServerError("AsyncErr: " + async_err);
508 void Server::AsyncRunStep(bool initial_step)
513 MutexAutoLock lock1(m_step_dtime_mutex);
514 dtime = m_step_dtime;
518 // Send blocks to clients
522 if ((dtime < 0.001) && !initial_step)
525 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
528 MutexAutoLock lock1(m_step_dtime_mutex);
529 m_step_dtime -= dtime;
535 m_uptime_counter->increment(dtime);
540 Update time of day and overall game time
542 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
545 Send to clients at constant intervals
548 m_time_of_day_send_timer -= dtime;
549 if (m_time_of_day_send_timer < 0.0) {
550 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
551 u16 time = m_env->getTimeOfDay();
552 float time_speed = g_settings->getFloat("time_speed");
553 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
555 m_timeofday_gauge->set(time);
559 MutexAutoLock lock(m_env_mutex);
560 // Figure out and report maximum lag to environment
561 float max_lag = m_env->getMaxLagEstimate();
562 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
563 if (dtime > max_lag) {
564 if (dtime > 0.1 && dtime > max_lag * 2.0)
565 infostream << "Server: Maximum lag peaked to " << dtime
566 << " s" << std::endl;
569 m_env->reportMaxLagEstimate(max_lag);
574 static const float map_timer_and_unload_dtime = 2.92;
575 if (m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) {
576 MutexAutoLock lock(m_env_mutex);
577 // Run Map's timers and unload unused data
578 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
579 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
580 g_settings->getFloat("server_unload_unused_data_timeout"),
585 Listen to the admin chat, if available
588 if (!m_admin_chat->command_queue.empty()) {
589 MutexAutoLock lock(m_env_mutex);
590 while (!m_admin_chat->command_queue.empty()) {
591 ChatEvent *evt = m_admin_chat->command_queue
593 handleChatInterfaceEvent(evt);
597 m_admin_chat->outgoing_queue.push_back(new ChatEventTimeInfo(
598 m_env->getGameTime(), m_env->getTimeOfDay()));
605 /* Transform liquids */
606 m_liquid_transform_timer += dtime;
607 if (m_liquid_transform_timer >= m_liquid_transform_every) {
608 m_liquid_transform_timer -= m_liquid_transform_every;
610 MutexAutoLock lock(m_env_mutex);
612 ScopeProfiler sp(g_profiler, "Server: liquid transform");
614 std::map<v3s16, MapBlock *> modified_blocks;
615 m_env->getMap().transformLiquids(modified_blocks, m_env);
618 Set the modified blocks unsent for all the clients
620 if (!modified_blocks.empty()) {
621 SetBlocksNotSent(modified_blocks);
624 m_clients.step(dtime);
626 m_lag_gauge->increment((m_lag_gauge->get() > dtime ? -1 : 1) * dtime / 100);
628 // send masterserver announce
630 float &counter = m_masterserver_timer;
631 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
632 g_settings->getBool("server_announce")) {
633 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE
634 : ServerList::AA_START,
635 m_bind_addr.getPort(), m_clients.getPlayerNames(),
636 m_uptime_counter->get(), m_env->getGameTime(),
637 m_lag_gauge->get(), m_gamespec.id,
638 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
639 m_modmgr->getMods(), m_dedicated);
647 Check added and deleted active objects
650 // infostream<<"Server: Checking added and deleted active
651 // objects"<<std::endl;
652 MutexAutoLock envlock(m_env_mutex);
655 const RemoteClientMap &clients = m_clients.getClientList();
656 ScopeProfiler sp(g_profiler, "Server: update objects within range");
658 m_player_gauge->set(clients.size());
659 for (const auto &client_it : clients) {
660 RemoteClient *client = client_it.second;
662 if (client->getState() < CS_DefinitionsSent)
665 // This can happen if the client times out somehow
666 if (!m_env->getPlayer(client->peer_id))
669 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
673 SendActiveObjectRemoveAdd(client, playersao);
677 // Save mod storages if modified
678 m_mod_storage_save_timer -= dtime;
679 if (m_mod_storage_save_timer <= 0.0f) {
680 m_mod_storage_save_timer =
681 g_settings->getFloat("server_map_save_interval");
683 for (std::unordered_map<std::string,
684 ModMetadata *>::const_iterator it =
685 m_mod_storages.begin();
686 it != m_mod_storages.end(); ++it) {
687 if (it->second->isModified()) {
688 it->second->save(getModStoragePath());
693 infostream << "Saved " << n << " modified mod storages."
702 MutexAutoLock envlock(m_env_mutex);
703 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
706 // Value = data sent by object
707 std::unordered_map<u16, std::vector<ActiveObjectMessage> *>
710 // Get active object messages from environment
711 ActiveObjectMessage aom(0);
714 if (!m_env->getActiveObjectMessage(&aom))
717 std::vector<ActiveObjectMessage> *message_list = nullptr;
718 auto n = buffered_messages.find(aom.id);
719 if (n == buffered_messages.end()) {
720 message_list = new std::vector<ActiveObjectMessage>;
721 buffered_messages[aom.id] = message_list;
723 message_list = n->second;
725 message_list->push_back(std::move(aom));
729 m_aom_buffer_counter->increment(aom_count);
732 const RemoteClientMap &clients = m_clients.getClientList();
733 // Route data to every client
734 std::string reliable_data, unreliable_data;
735 for (const auto &client_it : clients) {
736 reliable_data.clear();
737 unreliable_data.clear();
738 RemoteClient *client = client_it.second;
739 PlayerSAO *player = getPlayerSAO(client->peer_id);
740 // Go through all objects in message buffer
741 for (const auto &buffered_message : buffered_messages) {
742 // If object does not exist or is not known by client,
744 u16 id = buffered_message.first;
745 ServerActiveObject *sao = m_env->getActiveObject(id);
746 if (!sao || client->m_known_objects.find(id) ==
747 client->m_known_objects
751 // Get message list of object
752 std::vector<ActiveObjectMessage> *list =
753 buffered_message.second;
754 // Go through every message
755 for (const ActiveObjectMessage &aom : *list) {
756 // Send position updates to players who do not see
758 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
759 if (sao->getId() == player->getId())
762 // Do not send position updates for
763 // attached players as long the parent is
764 // known to the client
765 ServerActiveObject *parent =
767 if (parent && client->m_known_objects.find(
769 client->m_known_objects
774 // Add full new data to appropriate buffer
775 std::string &buffer =
776 aom.reliable ? reliable_data
779 writeU16((u8 *)idbuf, aom.id);
782 buffer.append(idbuf, sizeof(idbuf));
783 buffer.append(serializeString(aom.datastring));
787 reliable_data and unreliable_data are now ready.
790 if (!reliable_data.empty()) {
791 SendActiveObjectMessages(client->peer_id, reliable_data);
794 if (!unreliable_data.empty()) {
795 SendActiveObjectMessages(
796 client->peer_id, unreliable_data, false);
801 // Clear buffered_messages
802 for (auto &buffered_message : buffered_messages) {
803 delete buffered_message.second;
808 Send queued-for-sending map edit events.
811 // We will be accessing the environment
812 MutexAutoLock lock(m_env_mutex);
814 // Don't send too many at a time
817 // Single change sending is disabled if queue size is not small
818 bool disable_single_change_sending = false;
819 if (m_unsent_map_edit_queue.size() >= 4)
820 disable_single_change_sending = true;
822 int event_count = m_unsent_map_edit_queue.size();
824 // We'll log the amount of each
827 std::list<v3s16> node_meta_updates;
829 while (!m_unsent_map_edit_queue.empty()) {
830 MapEditEvent *event = m_unsent_map_edit_queue.front();
831 m_unsent_map_edit_queue.pop();
833 // Players far away from the change are stored here.
834 // Instead of sending the changes, MapBlocks are set not sent
836 std::unordered_set<u16> far_players;
838 switch (event->type) {
841 prof.add("MEET_ADDNODE", 1);
842 sendAddNode(event->p, event->n, &far_players,
843 disable_single_change_sending ? 5 : 30,
844 event->type == MEET_ADDNODE);
846 case MEET_REMOVENODE:
847 prof.add("MEET_REMOVENODE", 1);
848 sendRemoveNode(event->p, &far_players,
849 disable_single_change_sending ? 5 : 30);
851 case MEET_BLOCK_NODE_METADATA_CHANGED: {
852 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
853 if (!event->is_private_change) {
854 // Don't send the change yet. Collect them to
856 node_meta_updates.remove(event->p);
857 node_meta_updates.push_back(event->p);
860 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
861 getNodeBlockPos(event->p))) {
862 block->raiseModified(MOD_STATE_WRITE_NEEDED,
863 MOD_REASON_REPORT_META_CHANGE);
868 prof.add("MEET_OTHER", 1);
869 for (const v3s16 &modified_block :
870 event->modified_blocks) {
871 m_clients.markBlockposAsNotSent(modified_block);
875 prof.add("unknown", 1);
876 warningstream << "Server: Unknown MapEditEvent "
877 << ((u32)event->type) << std::endl;
882 Set blocks not sent to far players
884 if (!far_players.empty()) {
885 // Convert list format to that wanted by SetBlocksNotSent
886 std::map<v3s16, MapBlock *> modified_blocks2;
887 for (const v3s16 &modified_block :
888 event->modified_blocks) {
889 modified_blocks2[modified_block] =
890 m_env->getMap().getBlockNoCreateNoEx(
894 // Set blocks not sent
895 for (const u16 far_player : far_players) {
896 if (RemoteClient *client = getClient(far_player))
897 client->SetBlocksNotSent(
905 if (event_count >= 5) {
906 infostream << "Server: MapEditEvents:" << std::endl;
907 prof.print(infostream);
908 } else if (event_count != 0) {
909 verbosestream << "Server: MapEditEvents:" << std::endl;
910 prof.print(verbosestream);
913 // Send all metadata updates
914 if (node_meta_updates.size())
915 sendMetadataChanged(node_meta_updates);
919 Trigger emergethread (it somehow gets to a non-triggered but
920 bysy state sometimes)
923 float &counter = m_emergethread_trigger_timer;
925 if (counter >= 2.0) {
928 m_emerge->startThreads();
932 // Save map, players and auth stuff
934 float &counter = m_savemap_timer;
936 static thread_local const float save_interval =
937 g_settings->getFloat("server_map_save_interval");
938 if (counter >= save_interval) {
940 MutexAutoLock lock(m_env_mutex);
942 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
945 if (m_banmanager->isModified()) {
946 m_banmanager->save();
949 // Save changed parts of map
950 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
953 m_env->saveLoadedPlayers();
955 // Save environment metadata
960 m_shutdown_state.tick(dtime, this);
963 void Server::Receive()
973 In the first iteration *wait* for a packet, afterwards
974 process all packets that are immediately available (no
978 m_con->Receive(&pkt);
981 if (!m_con->TryReceive(&pkt))
985 peer_id = pkt.getPeerId();
986 m_packet_recv_counter->increment();
988 m_packet_recv_processed_counter->increment();
989 } catch (const con::InvalidIncomingDataException &e) {
990 infostream << "Server::Receive(): InvalidIncomingDataException: "
992 << e.what() << std::endl;
993 } catch (const SerializationError &e) {
994 infostream << "Server::Receive(): SerializationError: what()="
995 << e.what() << std::endl;
996 } catch (const ClientStateError &e) {
997 errorstream << "ProcessData: peer=" << peer_id
998 << " what()=" << e.what() << std::endl;
999 DenyAccess_Legacy(peer_id,
1000 L"Your client sent something server didn't "
1002 L"Try reconnecting or updating your client");
1003 } catch (const con::PeerNotFoundException &e) {
1005 } catch (const con::NoIncomingDataException &e) {
1011 PlayerSAO *Server::StageTwoClientInit(session_t peer_id)
1013 std::string playername;
1014 PlayerSAO *playersao = NULL;
1017 RemoteClient *client =
1018 m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1020 playername = client->getName();
1021 playersao = emergePlayer(playername.c_str(), peer_id,
1022 client->net_proto_version);
1024 } catch (std::exception &e) {
1030 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1032 // If failed, cancel
1033 if (!playersao || !player) {
1034 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1035 actionstream << "Server: Failed to emerge player \"" << playername
1036 << "\" (player allocated to an another client)"
1038 DenyAccess_Legacy(peer_id,
1039 L"Another client is connected with this "
1040 L"name. If your client closed unexpectedly, try "
1044 errorstream << "Server: " << playername
1045 << ": Failed to emerge player" << std::endl;
1046 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1052 Send complete position information
1054 SendMovePlayer(peer_id);
1057 SendPlayerPrivileges(peer_id);
1059 // Send inventory formspec
1060 SendPlayerInventoryFormspec(peer_id);
1063 SendInventory(playersao, false);
1065 // Send HP or death screen
1066 if (playersao->isDead())
1067 SendDeathscreen(peer_id, false, v3f(0, 0, 0));
1069 SendPlayerHPOrDie(playersao,
1070 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1073 SendPlayerBreath(playersao);
1079 Address addr = getPeerAddress(player->getPeerId());
1080 std::string ip_str = addr.serializeString();
1081 const std::vector<std::string> &names = m_clients.getPlayerNames();
1083 actionstream << player->getName() << " [" << ip_str
1084 << "] joins game. List of players: ";
1086 for (const std::string &name : names) {
1087 actionstream << name << " ";
1090 actionstream << player->getName() << std::endl;
1095 inline void Server::handleCommand(NetworkPacket *pkt)
1097 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1098 (this->*opHandle.handler)(pkt);
1101 void Server::ProcessData(NetworkPacket *pkt)
1103 // Environment is locked first.
1104 MutexAutoLock envlock(m_env_mutex);
1106 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1107 u32 peer_id = pkt->getPeerId();
1110 Address address = getPeerAddress(peer_id);
1111 std::string addr_s = address.serializeString();
1113 if (m_banmanager->isIpBanned(addr_s)) {
1114 std::string ban_name = m_banmanager->getBanName(addr_s);
1115 infostream << "Server: A banned client tried to connect from "
1116 << addr_s << "; banned name was " << ban_name
1118 // This actually doesn't seem to transfer to the client
1120 peer_id, L"Your ip is banned. Banned name was " +
1121 utf8_to_wide(ban_name));
1124 } catch (con::PeerNotFoundException &e) {
1126 * no peer for this packet found
1127 * most common reason is peer timeout, e.g. peer didn't
1128 * respond for some time, your server was overloaded or
1131 infostream << "Server::ProcessData(): Canceling: peer " << peer_id
1132 << " not found" << std::endl;
1137 ToServerCommand command = (ToServerCommand)pkt->getCommand();
1139 // Command must be handled into ToServerCommandHandler
1140 if (command >= TOSERVER_NUM_MSG_TYPES) {
1141 infostream << "Server: Ignoring unknown command " << command
1146 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1151 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1153 if (peer_ser_ver == SER_FMT_VER_INVALID) {
1154 errorstream << "Server::ProcessData(): Cancelling: Peer"
1155 " serialization format invalid or not initialized."
1156 " Skipping incoming command="
1157 << command << std::endl;
1161 /* Handle commands related to client startup */
1162 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1167 if (m_clients.getClientState(peer_id) < CS_Active) {
1168 if (command == TOSERVER_PLAYERPOS)
1171 errorstream << "Got packet command: " << command
1172 << " for peer id " << peer_id
1173 << " but client isn't active yet. Dropping packet "
1179 } catch (SendFailedException &e) {
1180 errorstream << "Server::ProcessData(): SendFailedException: "
1181 << "what=" << e.what() << std::endl;
1182 } catch (PacketError &e) {
1183 actionstream << "Server::ProcessData(): PacketError: "
1184 << "what=" << e.what() << std::endl;
1188 void Server::setTimeOfDay(u32 time)
1190 m_env->setTimeOfDay(time);
1191 m_time_of_day_send_timer = 0;
1194 void Server::onMapEditEvent(const MapEditEvent &event)
1196 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1199 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1202 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *> &block)
1204 std::vector<session_t> clients = m_clients.getClientIDs();
1206 // Set the modified blocks unsent for all the clients
1207 for (const session_t client_id : clients) {
1208 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1209 client->SetBlocksNotSent(block);
1214 void Server::peerAdded(con::Peer *peer)
1216 verbosestream << "Server::peerAdded(): peer->id=" << peer->id << std::endl;
1218 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1221 void Server::deletingPeer(con::Peer *peer, bool timeout)
1223 verbosestream << "Server::deletingPeer(): peer->id=" << peer->id
1224 << ", timeout=" << timeout << std::endl;
1226 m_clients.event(peer->id, CSE_Disconnect);
1227 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1230 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float *retval)
1232 *retval = m_con->getPeerStat(peer_id, type);
1233 return *retval != -1;
1236 bool Server::getClientInfo(session_t peer_id, ClientState *state, u32 *uptime,
1237 u8 *ser_vers, u16 *prot_vers, u8 *major, u8 *minor, u8 *patch,
1238 std::string *vers_string, std::string *lang_code)
1240 *state = m_clients.getClientState(peer_id);
1242 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1249 *uptime = client->uptime();
1250 *ser_vers = client->serialization_version;
1251 *prot_vers = client->net_proto_version;
1253 *major = client->getMajor();
1254 *minor = client->getMinor();
1255 *patch = client->getPatch();
1256 *vers_string = client->getFull();
1257 *lang_code = client->getLangCode();
1264 void Server::handlePeerChanges()
1266 while (!m_peer_change_queue.empty()) {
1267 con::PeerChange c = m_peer_change_queue.front();
1268 m_peer_change_queue.pop();
1270 verbosestream << "Server: Handling peer change: "
1271 << "id=" << c.peer_id << ", timeout=" << c.timeout
1275 case con::PEER_ADDED:
1276 m_clients.CreateClient(c.peer_id);
1279 case con::PEER_REMOVED:
1280 DeleteClient(c.peer_id, c.timeout ? CDR_TIMEOUT : CDR_LEAVE);
1284 FATAL_ERROR("Invalid peer change event received!");
1290 void Server::printToConsoleOnly(const std::string &text)
1293 m_admin_chat->outgoing_queue.push_back(
1294 new ChatEventChat("", utf8_to_wide(text)));
1296 std::cout << text << std::endl;
1300 void Server::Send(NetworkPacket *pkt)
1302 Send(pkt->getPeerId(), pkt);
1305 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1307 m_clients.send(peer_id, clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
1308 clientCommandFactoryTable[pkt->getCommand()].reliable);
1311 void Server::SendMovement(session_t peer_id)
1313 std::ostringstream os(std::ios_base::binary);
1315 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1317 pkt << g_settings->getFloat("movement_acceleration_default");
1318 pkt << g_settings->getFloat("movement_acceleration_air");
1319 pkt << g_settings->getFloat("movement_acceleration_fast");
1320 pkt << g_settings->getFloat("movement_speed_walk");
1321 pkt << g_settings->getFloat("movement_speed_crouch");
1322 pkt << g_settings->getFloat("movement_speed_fast");
1323 pkt << g_settings->getFloat("movement_speed_climb");
1324 pkt << g_settings->getFloat("movement_speed_jump");
1325 pkt << g_settings->getFloat("movement_liquid_fluidity");
1326 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1327 pkt << g_settings->getFloat("movement_liquid_sink");
1328 pkt << g_settings->getFloat("movement_gravity");
1333 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1335 if (playersao->isImmortal())
1338 session_t peer_id = playersao->getPeerID();
1339 bool is_alive = playersao->getHP() > 0;
1342 SendPlayerHP(peer_id);
1344 DiePlayer(peer_id, reason);
1347 void Server::SendHP(session_t peer_id, u16 hp)
1349 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1354 void Server::SendBreath(session_t peer_id, u16 breath)
1356 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1361 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1362 const std::string &custom_reason, bool reconnect)
1364 assert(reason < SERVER_ACCESSDENIED_MAX);
1366 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1368 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1369 pkt << custom_reason;
1370 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1371 reason == SERVER_ACCESSDENIED_CRASH)
1372 pkt << custom_reason << (u8)reconnect;
1376 void Server::SendAccessDenied_Legacy(session_t peer_id, const std::wstring &reason)
1378 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1383 void Server::SendDeathscreen(
1384 session_t peer_id, bool set_camera_point_target, v3f camera_point_target)
1386 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1387 pkt << set_camera_point_target << camera_point_target;
1391 void Server::SendItemDef(
1392 session_t peer_id, IItemDefManager *itemdef, u16 protocol_version)
1394 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1398 u32 length of the next item
1399 zlib-compressed serialized ItemDefManager
1401 std::ostringstream tmp_os(std::ios::binary);
1402 itemdef->serialize(tmp_os, protocol_version);
1403 std::ostringstream tmp_os2(std::ios::binary);
1404 compressZlib(tmp_os.str(), tmp_os2);
1405 pkt.putLongString(tmp_os2.str());
1408 verbosestream << "Server: Sending item definitions to id(" << peer_id
1409 << "): size=" << pkt.getSize() << std::endl;
1414 void Server::SendNodeDef(
1415 session_t peer_id, const NodeDefManager *nodedef, u16 protocol_version)
1417 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1421 u32 length of the next item
1422 zlib-compressed serialized NodeDefManager
1424 std::ostringstream tmp_os(std::ios::binary);
1425 nodedef->serialize(tmp_os, protocol_version);
1426 std::ostringstream tmp_os2(std::ios::binary);
1427 compressZlib(tmp_os.str(), tmp_os2);
1429 pkt.putLongString(tmp_os2.str());
1432 verbosestream << "Server: Sending node definitions to id(" << peer_id
1433 << "): size=" << pkt.getSize() << std::endl;
1439 Non-static send methods
1442 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1444 RemotePlayer *player = sao->getPlayer();
1446 // Do not send new format to old clients
1447 incremental &= player->protocol_version >= 38;
1449 UpdateCrafting(player);
1455 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1457 std::ostringstream os(std::ios::binary);
1458 sao->getInventory()->serialize(os, incremental);
1459 sao->getInventory()->setModified(false);
1460 player->setModified(true);
1462 const std::string &s = os.str();
1463 pkt.putRawString(s.c_str(), s.size());
1467 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1469 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1471 u8 type = message.type;
1472 pkt << version << type << std::wstring(L"") << message.message
1473 << (u64)message.timestamp;
1475 if (peer_id != PEER_ID_INEXISTENT) {
1476 RemotePlayer *player = m_env->getPlayer(peer_id);
1482 m_clients.sendToAll(&pkt);
1486 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1487 const std::string &formname)
1489 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1490 if (formspec.empty()) {
1491 // the client should close the formspec
1492 // but make sure there wasn't another one open in meantime
1493 const auto it = m_formspec_state_data.find(peer_id);
1494 if (it != m_formspec_state_data.end() && it->second == formname) {
1495 m_formspec_state_data.erase(peer_id);
1497 pkt.putLongString("");
1499 m_formspec_state_data[peer_id] = formname;
1500 pkt.putLongString(formspec);
1507 // Spawns a particle on peer with peer_id
1508 void Server::SendSpawnParticle(
1509 session_t peer_id, u16 protocol_version, const ParticleParameters &p)
1511 static thread_local const float radius =
1512 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE *
1515 if (peer_id == PEER_ID_INEXISTENT) {
1516 std::vector<session_t> clients = m_clients.getClientIDs();
1517 const v3f pos = p.pos * BS;
1518 const float radius_sq = radius * radius;
1520 for (const session_t client_id : clients) {
1521 RemotePlayer *player = m_env->getPlayer(client_id);
1525 PlayerSAO *sao = player->getPlayerSAO();
1529 // Do not send to distant clients
1530 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1533 SendSpawnParticle(client_id, player->protocol_version, p);
1537 assert(protocol_version != 0);
1539 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1542 // NetworkPacket and iostreams are incompatible...
1543 std::ostringstream oss(std::ios_base::binary);
1544 p.serialize(oss, protocol_version);
1545 pkt.putRawString(oss.str());
1551 // Adds a ParticleSpawner on peer with peer_id
1552 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1553 const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1555 static thread_local const float radius =
1556 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE *
1559 if (peer_id == PEER_ID_INEXISTENT) {
1560 std::vector<session_t> clients = m_clients.getClientIDs();
1561 const v3f pos = (p.minpos + p.maxpos) / 2.0f * BS;
1562 const float radius_sq = radius * radius;
1563 /* Don't send short-lived spawners to distant players.
1564 * This could be replaced with proper tracking at some point. */
1565 const bool distance_check = !attached_id && p.time <= 1.0f;
1567 for (const session_t client_id : clients) {
1568 RemotePlayer *player = m_env->getPlayer(client_id);
1572 if (distance_check) {
1573 PlayerSAO *sao = player->getPlayerSAO();
1576 if (sao->getBasePosition().getDistanceFromSQ(pos) >
1581 SendAddParticleSpawner(client_id, player->protocol_version, p,
1586 assert(protocol_version != 0);
1588 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1590 pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel << p.maxvel
1591 << p.minacc << p.maxacc << p.minexptime << p.maxexptime << p.minsize
1592 << p.maxsize << p.collisiondetection;
1594 pkt.putLongString(p.texture);
1596 pkt << id << p.vertical << p.collision_removal << attached_id;
1598 std::ostringstream os(std::ios_base::binary);
1599 p.animation.serialize(os, protocol_version);
1600 pkt.putRawString(os.str());
1602 pkt << p.glow << p.object_collision;
1603 pkt << p.node.param0 << p.node.param2 << p.node_tile;
1608 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1610 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1614 if (peer_id != PEER_ID_INEXISTENT)
1617 m_clients.sendToAll(&pkt);
1620 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1622 NetworkPacket pkt(TOCLIENT_HUDADD, 0, peer_id);
1624 pkt << id << (u8)form->type << form->pos << form->name << form->scale
1625 << form->text << form->number << form->item << form->dir << form->align
1626 << form->offset << form->world_pos << form->size << form->z_index
1632 void Server::SendHUDRemove(session_t peer_id, u32 id)
1634 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1639 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1641 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1642 pkt << id << (u8)stat;
1646 case HUD_STAT_SCALE:
1647 case HUD_STAT_ALIGN:
1648 case HUD_STAT_OFFSET:
1649 pkt << *(v2f *)value;
1653 case HUD_STAT_TEXT2:
1654 pkt << *(std::string *)value;
1656 case HUD_STAT_WORLD_POS:
1657 pkt << *(v3f *)value;
1660 pkt << *(v2s32 *)value;
1662 case HUD_STAT_NUMBER:
1666 pkt << *(u32 *)value;
1673 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1675 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1677 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1679 pkt << flags << mask;
1684 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1686 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1687 pkt << param << value;
1691 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1693 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1695 // Handle prior clients here
1696 if (m_clients.getProtocolVersion(peer_id) < 39) {
1697 pkt << params.bgcolor << params.type << (u16)params.textures.size();
1699 for (const std::string &texture : params.textures)
1702 pkt << params.clouds;
1703 } else { // Handle current clients and future clients
1704 pkt << params.bgcolor << params.type << params.clouds
1705 << params.fog_sun_tint << params.fog_moon_tint
1706 << params.fog_tint_type;
1708 if (params.type == "skybox") {
1709 pkt << (u16)params.textures.size();
1710 for (const std::string &texture : params.textures)
1712 } else if (params.type == "regular") {
1713 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1714 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1715 << params.sky_color.night_sky
1716 << params.sky_color.night_horizon << params.sky_color.indoors;
1723 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1725 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1726 pkt << params.visible << params.texture << params.tonemap << params.sunrise
1727 << params.sunrise_visible << params.scale;
1731 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1733 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1735 pkt << params.visible << params.texture << params.tonemap << params.scale;
1739 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1741 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1743 pkt << params.visible << params.count << params.starcolor << params.scale;
1748 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1750 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1751 pkt << params.density << params.color_bright << params.color_ambient
1752 << params.height << params.thickness << params.speed;
1756 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override, float ratio)
1758 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO, 1 + 2, peer_id);
1760 pkt << do_override << (u16)(ratio * 65535);
1765 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1767 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1768 pkt << time << time_speed;
1770 if (peer_id == PEER_ID_INEXISTENT) {
1771 m_clients.sendToAll(&pkt);
1777 void Server::SendPlayerHP(session_t peer_id)
1779 PlayerSAO *playersao = getPlayerSAO(peer_id);
1782 SendHP(peer_id, playersao->getHP());
1783 m_script->player_event(playersao, "health_changed");
1785 // Send to other clients
1786 playersao->sendPunchCommand();
1789 void Server::SendPlayerBreath(PlayerSAO *sao)
1793 m_script->player_event(sao, "breath_changed");
1794 SendBreath(sao->getPeerID(), sao->getBreath());
1797 void Server::SendMovePlayer(session_t peer_id)
1799 RemotePlayer *player = m_env->getPlayer(peer_id);
1801 PlayerSAO *sao = player->getPlayerSAO();
1804 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1805 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1808 v3f pos = sao->getBasePosition();
1809 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1810 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1811 << " pitch=" << sao->getLookPitch()
1812 << " yaw=" << sao->getRotation().Y << std::endl;
1818 void Server::SendPlayerFov(session_t peer_id)
1820 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1822 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1823 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1828 void Server::SendLocalPlayerAnimations(
1829 session_t peer_id, v2s32 animation_frames[4], f32 animation_speed)
1831 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0, peer_id);
1833 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1834 << animation_frames[3] << animation_speed;
1839 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1841 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1842 pkt << first << third;
1846 void Server::SendPlayerPrivileges(session_t peer_id)
1848 RemotePlayer *player = m_env->getPlayer(peer_id);
1850 if (player->getPeerId() == PEER_ID_INEXISTENT)
1853 std::set<std::string> privs;
1854 m_script->getAuth(player->getName(), NULL, &privs);
1856 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1857 pkt << (u16)privs.size();
1859 for (const std::string &priv : privs) {
1866 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1868 RemotePlayer *player = m_env->getPlayer(peer_id);
1870 if (player->getPeerId() == PEER_ID_INEXISTENT)
1873 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1874 pkt.putLongString(player->inventory_formspec);
1879 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1881 RemotePlayer *player = m_env->getPlayer(peer_id);
1883 if (player->getPeerId() == PEER_ID_INEXISTENT)
1886 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1887 pkt << player->formspec_prepend;
1891 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1893 // Radius inside which objects are active
1894 static thread_local const s16 radius =
1895 g_settings->getS16("active_object_send_range_blocks") *
1898 // Radius inside which players are active
1899 static thread_local const bool is_transfer_limited =
1900 g_settings->exists("unlimited_player_transfer_distance") &&
1901 !g_settings->getBool("unlimited_player_transfer_distance");
1903 static thread_local const s16 player_transfer_dist =
1904 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1906 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited
1908 : player_transfer_dist;
1910 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1914 std::queue<u16> removed_objects, added_objects;
1915 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1916 client->m_known_objects, removed_objects);
1917 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1918 client->m_known_objects, added_objects);
1920 int removed_count = removed_objects.size();
1921 int added_count = added_objects.size();
1923 if (removed_objects.empty() && added_objects.empty())
1929 // Handle removed objects
1930 writeU16((u8 *)buf, removed_objects.size());
1931 data.append(buf, 2);
1932 while (!removed_objects.empty()) {
1934 u16 id = removed_objects.front();
1935 ServerActiveObject *obj = m_env->getActiveObject(id);
1937 // Add to data buffer for sending
1938 writeU16((u8 *)buf, id);
1939 data.append(buf, 2);
1941 // Remove from known objects
1942 client->m_known_objects.erase(id);
1944 if (obj && obj->m_known_by_count > 0)
1945 obj->m_known_by_count--;
1947 removed_objects.pop();
1950 // Handle added objects
1951 writeU16((u8 *)buf, added_objects.size());
1952 data.append(buf, 2);
1953 while (!added_objects.empty()) {
1955 u16 id = added_objects.front();
1956 ServerActiveObject *obj = m_env->getActiveObject(id);
1957 added_objects.pop();
1960 warningstream << FUNCTION_NAME << ": NULL object id=" << (int)id
1966 u8 type = obj->getSendType();
1968 // Add to data buffer for sending
1969 writeU16((u8 *)buf, id);
1970 data.append(buf, 2);
1971 writeU8((u8 *)buf, type);
1972 data.append(buf, 1);
1974 data.append(serializeLongString(obj->getClientInitializationData(
1975 client->net_proto_version)));
1977 // Add to known objects
1978 client->m_known_objects.insert(id);
1980 obj->m_known_by_count++;
1984 TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
1985 pkt.putRawString(data.c_str(), data.size());
1988 verbosestream << "Server::SendActiveObjectRemoveAdd: " << removed_count
1989 << " removed, " << added_count << " added, "
1990 << "packet size is " << pkt.getSize() << std::endl;
1993 void Server::SendActiveObjectMessages(
1994 session_t peer_id, const std::string &datas, bool reliable)
1996 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES, datas.size(), peer_id);
1998 pkt.putRawString(datas.c_str(), datas.size());
2000 m_clients.send(pkt.getPeerId(),
2001 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel
2006 void Server::SendCSMRestrictionFlags(session_t peer_id)
2008 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2009 sizeof(m_csm_restriction_flags) +
2010 sizeof(m_csm_restriction_noderange),
2012 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2016 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2018 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2023 inline s32 Server::nextSoundId()
2025 s32 ret = m_next_sound_id;
2026 if (m_next_sound_id == INT32_MAX)
2027 m_next_sound_id = 0; // signed overflow is undefined
2033 s32 Server::playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms,
2036 // Find out initial position of sound
2037 bool pos_exists = false;
2038 v3f pos = params.getPos(m_env, &pos_exists);
2039 // If position is not found while it should be, cancel sound
2040 if (pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2043 // Filter destination clients
2044 std::vector<session_t> dst_clients;
2045 if (!params.to_player.empty()) {
2046 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2048 infostream << "Server::playSound: Player \"" << params.to_player
2049 << "\" not found" << std::endl;
2052 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2053 infostream << "Server::playSound: Player \"" << params.to_player
2054 << "\" not connected" << std::endl;
2057 dst_clients.push_back(player->getPeerId());
2059 std::vector<session_t> clients = m_clients.getClientIDs();
2061 for (const session_t client_id : clients) {
2062 RemotePlayer *player = m_env->getPlayer(client_id);
2065 if (!params.exclude_player.empty() &&
2066 params.exclude_player == player->getName())
2069 PlayerSAO *sao = player->getPlayerSAO();
2074 if (sao->getBasePosition().getDistanceFrom(pos) >
2075 params.max_hear_distance)
2078 dst_clients.push_back(client_id);
2082 if (dst_clients.empty())
2087 ServerPlayingSound *psound = nullptr;
2089 id = -1; // old clients will still use this, so pick a reserved ID
2092 // The sound will exist as a reference in m_playing_sounds
2093 m_playing_sounds[id] = ServerPlayingSound();
2094 psound = &m_playing_sounds[id];
2095 psound->params = params;
2096 psound->spec = spec;
2099 float gain = params.gain * spec.gain;
2100 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2101 pkt << id << spec.name << gain << (u8)params.type << pos << params.object
2102 << params.loop << params.fade << params.pitch << ephemeral;
2104 bool as_reliable = !ephemeral;
2106 for (const u16 dst_client : dst_clients) {
2108 psound->clients.insert(dst_client);
2109 m_clients.send(dst_client, 0, &pkt, as_reliable);
2113 void Server::stopSound(s32 handle)
2115 // Get sound reference
2116 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2117 m_playing_sounds.find(handle);
2118 if (i == m_playing_sounds.end())
2120 ServerPlayingSound &psound = i->second;
2122 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2125 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2126 si != psound.clients.end(); ++si) {
2128 m_clients.send(*si, 0, &pkt, true);
2130 // Remove sound reference
2131 m_playing_sounds.erase(i);
2134 void Server::fadeSound(s32 handle, float step, float gain)
2136 // Get sound reference
2137 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2138 m_playing_sounds.find(handle);
2139 if (i == m_playing_sounds.end())
2142 ServerPlayingSound &psound = i->second;
2143 psound.params.gain = gain;
2145 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2146 pkt << handle << step << gain;
2148 // Backwards compability
2149 bool play_sound = gain > 0;
2150 ServerPlayingSound compat_psound = psound;
2151 compat_psound.clients.clear();
2153 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2154 compat_pkt << handle;
2156 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2157 it != psound.clients.end();) {
2158 if (m_clients.getProtocolVersion(*it) >= 32) {
2160 m_clients.send(*it, 0, &pkt, true);
2163 compat_psound.clients.insert(*it);
2165 m_clients.send(*it, 0, &compat_pkt, true);
2166 psound.clients.erase(it++);
2170 // Remove sound reference
2171 if (!play_sound || psound.clients.empty())
2172 m_playing_sounds.erase(i);
2174 if (play_sound && !compat_psound.clients.empty()) {
2175 // Play new sound volume on older clients
2176 playSound(compat_psound.spec, compat_psound.params);
2180 void Server::sendRemoveNode(
2181 v3s16 p, std::unordered_set<u16> *far_players, float far_d_nodes)
2183 float maxd = far_d_nodes * BS;
2184 v3f p_f = intToFloat(p, BS);
2185 v3s16 block_pos = getNodeBlockPos(p);
2187 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2190 std::vector<session_t> clients = m_clients.getClientIDs();
2193 for (session_t client_id : clients) {
2194 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2198 RemotePlayer *player = m_env->getPlayer(client_id);
2199 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2201 // If player is far away, only set modified blocks not sent
2202 if (!client->isBlockSent(block_pos) ||
2203 (sao && sao->getBasePosition().getDistanceFrom(p_f) >
2206 far_players->emplace(client_id);
2208 client->SetBlockNotSent(block_pos);
2213 m_clients.send(client_id, 0, &pkt, true);
2219 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2220 float far_d_nodes, bool remove_metadata)
2222 float maxd = far_d_nodes * BS;
2223 v3f p_f = intToFloat(p, BS);
2224 v3s16 block_pos = getNodeBlockPos(p);
2226 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2227 pkt << p << n.param0 << n.param1 << n.param2 << (u8)(remove_metadata ? 0 : 1);
2229 std::vector<session_t> clients = m_clients.getClientIDs();
2232 for (session_t client_id : clients) {
2233 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2237 RemotePlayer *player = m_env->getPlayer(client_id);
2238 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2240 // If player is far away, only set modified blocks not sent
2241 if (!client->isBlockSent(block_pos) ||
2242 (sao && sao->getBasePosition().getDistanceFrom(p_f) >
2245 far_players->emplace(client_id);
2247 client->SetBlockNotSent(block_pos);
2252 m_clients.send(client_id, 0, &pkt, true);
2258 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2260 float maxd = far_d_nodes * BS;
2261 NodeMetadataList meta_updates_list(false);
2262 std::vector<session_t> clients = m_clients.getClientIDs();
2266 for (session_t i : clients) {
2267 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2271 ServerActiveObject *player = m_env->getActiveObject(i);
2272 v3f player_pos = player ? player->getBasePosition() : v3f();
2274 for (const v3s16 &pos : meta_updates) {
2275 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2280 v3s16 block_pos = getNodeBlockPos(pos);
2281 if (!client->isBlockSent(block_pos) ||
2282 (player && player_pos.getDistanceFrom(intToFloat(
2283 pos, BS)) > maxd)) {
2284 client->SetBlockNotSent(block_pos);
2288 // Add the change to send list
2289 meta_updates_list.set(pos, meta);
2291 if (meta_updates_list.size() == 0)
2294 // Send the meta changes
2295 std::ostringstream os(std::ios::binary);
2296 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2297 std::ostringstream oss(std::ios::binary);
2298 compressZlib(os.str(), oss);
2300 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2301 pkt.putLongString(oss.str());
2302 m_clients.send(i, 0, &pkt, true);
2304 meta_updates_list.clear();
2310 void Server::SendBlockNoLock(
2311 session_t peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
2314 Create a packet with the block in the right format
2317 std::ostringstream os(std::ios_base::binary);
2318 block->serialize(os, ver, false);
2319 block->serializeNetworkSpecific(os);
2320 std::string s = os.str();
2322 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2324 pkt << block->getPos();
2325 pkt.putRawString(s.c_str(), s.size());
2329 void Server::SendBlocks(float dtime)
2331 MutexAutoLock envlock(m_env_mutex);
2332 // TODO check if one big lock could be faster then multiple small ones
2334 std::vector<PrioritySortedBlockTransfer> queue;
2336 u32 total_sending = 0;
2339 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2341 std::vector<session_t> clients = m_clients.getClientIDs();
2344 for (const session_t client_id : clients) {
2345 RemoteClient *client = m_clients.lockedGetClientNoEx(
2346 client_id, CS_Active);
2351 total_sending += client->getSendingCount();
2352 client->GetNextBlocks(m_env, m_emerge, dtime, queue);
2358 // Lowest priority number comes first.
2359 // Lowest is most important.
2360 std::sort(queue.begin(), queue.end());
2364 // Maximal total count calculation
2365 // The per-client block sends is halved with the maximal online users
2366 u32 max_blocks_to_send =
2367 (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2368 g_settings->getU32("max_simultaneous_block_sends_"
2373 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2374 Map &map = m_env->getMap();
2376 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2377 if (total_sending >= max_blocks_to_send)
2380 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2384 RemoteClient *client = m_clients.lockedGetClientNoEx(
2385 block_to_send.peer_id, CS_Active);
2389 SendBlockNoLock(block_to_send.peer_id, block,
2390 client->serialization_version, client->net_proto_version);
2392 client->SentBlock(block_to_send.pos);
2398 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2400 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2405 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2406 if (!client || client->isBlockSent(blockpos)) {
2410 SendBlockNoLock(peer_id, block, client->serialization_version,
2411 client->net_proto_version);
2417 bool Server::addMediaFile(const std::string &filename, const std::string &filepath,
2418 std::string *filedata_to, std::string *digest_to)
2420 // If name contains illegal characters, ignore the file
2421 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2422 infostream << "Server: ignoring illegal file name: \"" << filename << "\""
2426 // If name is not in a supported format, ignore it
2427 const char *supported_ext[] = {".png", ".jpg", ".bmp", ".tga", ".pcx", ".ppm",
2428 ".psd", ".wal", ".rgb", ".ogg", ".x", ".b3d", ".md2", ".obj",
2429 // Custom translation file format
2431 if (removeStringEnd(filename, supported_ext).empty()) {
2432 infostream << "Server: ignoring unsupported file extension: \""
2433 << filename << "\"" << std::endl;
2436 // Ok, attempt to load the file and add to cache
2439 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2441 errorstream << "Server::addMediaFile(): Could not open \"" << filename
2442 << "\" for reading" << std::endl;
2445 std::string filedata;
2449 fis.read(buf, sizeof(buf));
2450 std::streamsize len = fis.gcount();
2451 filedata.append(buf, len);
2460 errorstream << "Server::addMediaFile(): Failed to read \"" << filename
2461 << "\"" << std::endl;
2463 } else if (filedata.empty()) {
2464 errorstream << "Server::addMediaFile(): Empty file \"" << filepath << "\""
2470 sha1.addBytes(filedata.c_str(), filedata.length());
2472 unsigned char *digest = sha1.getDigest();
2473 std::string sha1_base64 = base64_encode(digest, 20);
2474 std::string sha1_hex = hex_encode((char *)digest, 20);
2476 *digest_to = std::string((char *)digest, 20);
2480 m_media[filename] = MediaInfo(filepath, sha1_base64);
2481 verbosestream << "Server: " << sha1_hex << " is " << filename << std::endl;
2484 *filedata_to = std::move(filedata);
2488 void Server::fillMediaCache()
2490 infostream << "Server: Calculating media file checksums" << std::endl;
2492 // Collect all media file paths
2493 std::vector<std::string> paths;
2494 m_modmgr->getModsMediaPaths(paths);
2495 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2496 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" +
2497 DIR_DELIM + "server");
2499 // Collect media file information from paths into cache
2500 for (const std::string &mediapath : paths) {
2501 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2502 for (const fs::DirListNode &dln : dirlist) {
2503 if (dln.dir) // Ignore dirs
2505 std::string filepath = mediapath;
2506 filepath.append(DIR_DELIM).append(dln.name);
2507 addMediaFile(dln.name, filepath);
2511 infostream << "Server: " << m_media.size() << " media files collected"
2515 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2518 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2521 std::string lang_suffix;
2522 lang_suffix.append(".").append(lang_code).append(".tr");
2523 for (const auto &i : m_media) {
2524 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2531 for (const auto &i : m_media) {
2532 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2534 pkt << i.first << i.second.sha1_digest;
2537 pkt << g_settings->get("remote_media");
2540 verbosestream << "Server: Announcing files to id(" << peer_id
2541 << "): count=" << media_sent << " size=" << pkt.getSize()
2545 struct SendableMedia
2551 SendableMedia(const std::string &name_ = "", const std::string &path_ = "",
2552 const std::string &data_ = "") :
2554 path(path_), data(data_)
2559 void Server::sendRequestedMedia(session_t peer_id, const std::vector<std::string> &tosend)
2561 verbosestream << "Server::sendRequestedMedia(): "
2562 << "Sending files to client" << std::endl;
2566 // Put 5kB in one bunch (this is not accurate)
2567 u32 bytes_per_bunch = 5000;
2569 std::vector<std::vector<SendableMedia>> file_bunches;
2570 file_bunches.emplace_back();
2572 u32 file_size_bunch_total = 0;
2574 for (const std::string &name : tosend) {
2575 if (m_media.find(name) == m_media.end()) {
2576 errorstream << "Server::sendRequestedMedia(): Client asked for "
2577 << "unknown file \"" << (name) << "\"" << std::endl;
2581 // TODO get path + name
2582 std::string tpath = m_media[name].path;
2585 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2587 errorstream << "Server::sendRequestedMedia(): Could not open \""
2588 << tpath << "\" for reading" << std::endl;
2591 std::ostringstream tmp_os(std::ios_base::binary);
2595 fis.read(buf, 1024);
2596 std::streamsize len = fis.gcount();
2597 tmp_os.write(buf, len);
2598 file_size_bunch_total += len;
2607 errorstream << "Server::sendRequestedMedia(): Failed to read \""
2608 << name << "\"" << std::endl;
2611 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2612 <<tname<<"\""<<std::endl;*/
2614 file_bunches[file_bunches.size() - 1].emplace_back(
2615 name, tpath, tmp_os.str());
2617 // Start next bunch if got enough data
2618 if (file_size_bunch_total >= bytes_per_bunch) {
2619 file_bunches.emplace_back();
2620 file_size_bunch_total = 0;
2624 /* Create and send packets */
2626 u16 num_bunches = file_bunches.size();
2627 for (u16 i = 0; i < num_bunches; i++) {
2630 u16 total number of texture bunches
2631 u16 index of this bunch
2632 u32 number of files in this bunch
2641 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2642 pkt << num_bunches << i << (u32)file_bunches[i].size();
2644 for (const SendableMedia &j : file_bunches[i]) {
2646 pkt.putLongString(j.data);
2649 verbosestream << "Server::sendRequestedMedia(): bunch " << i << "/"
2650 << num_bunches << " files=" << file_bunches[i].size()
2651 << " size=" << pkt.getSize() << std::endl;
2656 void Server::sendDetachedInventory(
2657 Inventory *inventory, const std::string &name, session_t peer_id)
2659 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2663 pkt << false; // Remove inventory
2665 pkt << true; // Update inventory
2667 // Serialization & NetworkPacket isn't a love story
2668 std::ostringstream os(std::ios_base::binary);
2669 inventory->serialize(os);
2670 inventory->setModified(false);
2672 const std::string &os_str = os.str();
2673 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility
2674 // with 5.0.0 clients
2675 pkt.putRawString(os_str);
2678 if (peer_id == PEER_ID_INEXISTENT)
2679 m_clients.sendToAll(&pkt);
2684 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2686 // Lookup player name, to filter detached inventories just after
2687 std::string peer_name;
2688 if (peer_id != PEER_ID_INEXISTENT) {
2689 peer_name = getClient(peer_id, CS_Created)->getName();
2692 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2693 sendDetachedInventory(inv, name, peer_id);
2696 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2703 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2705 PlayerSAO *playersao = getPlayerSAO(peer_id);
2708 infostream << "Server::DiePlayer(): Player " << playersao->getPlayer()->getName()
2709 << " dies" << std::endl;
2711 playersao->setHP(0, reason);
2712 playersao->clearParentAttachment();
2714 // Trigger scripted stuff
2715 m_script->on_dieplayer(playersao, reason);
2717 SendPlayerHP(peer_id);
2718 SendDeathscreen(peer_id, false, v3f(0, 0, 0));
2721 void Server::RespawnPlayer(session_t peer_id)
2723 PlayerSAO *playersao = getPlayerSAO(peer_id);
2726 infostream << "Server::RespawnPlayer(): Player "
2727 << playersao->getPlayer()->getName() << " respawns" << std::endl;
2729 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2730 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2731 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2733 bool repositioned = m_script->on_respawnplayer(playersao);
2734 if (!repositioned) {
2735 // setPos will send the new position to client
2736 playersao->setPos(findSpawnPos());
2739 SendPlayerHP(peer_id);
2742 void Server::DenySudoAccess(session_t peer_id)
2744 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2748 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver,
2749 AccessDeniedCode reason, const std::string &str_reason, bool reconnect)
2751 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2753 m_clients.event(peer_id, CSE_SetDenied);
2754 DisconnectPeer(peer_id);
2757 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2758 const std::string &custom_reason)
2760 SendAccessDenied(peer_id, reason, custom_reason);
2761 m_clients.event(peer_id, CSE_SetDenied);
2762 DisconnectPeer(peer_id);
2765 // 13/03/15: remove this function when protocol version 25 will become
2766 // the minimum version for MT users, maybe in 1 year
2767 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2769 SendAccessDenied_Legacy(peer_id, reason);
2770 m_clients.event(peer_id, CSE_SetDenied);
2771 DisconnectPeer(peer_id);
2774 void Server::DisconnectPeer(session_t peer_id)
2776 m_modchannel_mgr->leaveAllChannels(peer_id);
2777 m_con->DisconnectPeer(peer_id);
2780 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2783 RemoteClient *client = getClient(peer_id, CS_Invalid);
2785 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2787 // Right now, the auth mechs don't change between login and sudo mode.
2788 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2789 client->allowed_sudo_mechs = sudo_auth_mechs;
2791 resp_pkt << v3f(0, 0, 0) << (u64)m_env->getServerMap().getSeed()
2792 << g_settings->getFloat("dedicated_server_step")
2796 m_clients.event(peer_id, CSE_AuthAccept);
2798 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2800 // We only support SRP right now
2801 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2803 resp_pkt << sudo_auth_mechs;
2805 m_clients.event(peer_id, CSE_SudoSuccess);
2809 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2811 std::wstring message;
2814 Clear references to playing sounds
2816 for (std::unordered_map<s32, ServerPlayingSound>::iterator i =
2817 m_playing_sounds.begin();
2818 i != m_playing_sounds.end();) {
2819 ServerPlayingSound &psound = i->second;
2820 psound.clients.erase(peer_id);
2821 if (psound.clients.empty())
2822 m_playing_sounds.erase(i++);
2827 // clear formspec info so the next client can't abuse the current state
2828 m_formspec_state_data.erase(peer_id);
2830 RemotePlayer *player = m_env->getPlayer(peer_id);
2832 /* Run scripts and remove from environment */
2834 PlayerSAO *playersao = player->getPlayerSAO();
2837 playersao->clearChildAttachments();
2838 playersao->clearParentAttachment();
2840 // inform connected clients
2841 const std::string &player_name = player->getName();
2842 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0,
2843 PEER_ID_INEXISTENT);
2844 // (u16) 1 + std::string represents a vector serialization
2846 notice << (u8)PLAYER_LIST_REMOVE << (u16)1 << player_name;
2847 m_clients.sendToAll(¬ice);
2849 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2851 playersao->disconnected();
2858 if (player && reason != CDR_DENY) {
2859 std::ostringstream os(std::ios_base::binary);
2860 std::vector<session_t> clients = m_clients.getClientIDs();
2862 for (const session_t client_id : clients) {
2864 RemotePlayer *player =
2865 m_env->getPlayer(client_id);
2869 // Get name of player
2870 os << player->getName() << " ";
2873 std::string name = player->getName();
2874 actionstream << name << " "
2875 << (reason == CDR_TIMEOUT ? "times out."
2877 << " List of players: " << os.str()
2880 m_admin_chat->outgoing_queue.push_back(
2881 new ChatEventNick(CET_NICK_REMOVE,
2886 MutexAutoLock env_lock(m_env_mutex);
2887 m_clients.DeleteClient(peer_id);
2891 // Send leave chat message to all remaining clients
2892 if (!message.empty()) {
2893 SendChatMessage(PEER_ID_INEXISTENT,
2894 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2898 void Server::UpdateCrafting(RemotePlayer *player)
2900 InventoryList *clist = player->inventory.getList("craft");
2901 if (!clist || clist->getSize() == 0)
2904 if (!clist->checkModified())
2907 // Get a preview for crafting
2909 InventoryLocation loc;
2910 loc.setPlayer(player->getName());
2911 std::vector<ItemStack> output_replacements;
2912 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2913 m_env->getScriptIface()->item_CraftPredict(
2914 preview, player->getPlayerSAO(), clist, loc);
2916 InventoryList *plist = player->inventory.getList("craftpreview");
2917 if (plist && plist->getSize() >= 1) {
2918 // Put the new preview in
2919 plist->changeItem(0, preview);
2923 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2925 if (evt->type == CET_NICK_ADD) {
2926 // The terminal informed us of its nick choice
2927 m_admin_nick = ((ChatEventNick *)evt)->nick;
2928 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2929 errorstream << "You haven't set up an account." << std::endl
2930 << "Please log in using the client as '"
2931 << m_admin_nick << "' with a secure password."
2933 << "Until then, you can't execute admin tasks via "
2936 << "and everybody can claim the user account instead "
2939 << "giving them full control over this server."
2943 assert(evt->type == CET_CHAT);
2944 handleAdminChat((ChatEventChat *)evt);
2948 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2949 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2951 // If something goes wrong, this player is to blame
2952 RollbackScopeActor rollback_scope(m_rollback, std::string("player:") + name);
2954 if (g_settings->getBool("strip_color_codes"))
2955 wmessage = unescape_enriched(wmessage);
2958 switch (player->canSendChatMessage()) {
2959 case RPLAYER_CHATRESULT_FLOODING: {
2960 std::wstringstream ws;
2961 ws << L"You cannot send more messages. You are limited to "
2962 << g_settings->getFloat("chat_message_limit_per_10sec")
2963 << L" messages per 10 seconds.";
2966 case RPLAYER_CHATRESULT_KICK:
2967 DenyAccess_Legacy(player->getPeerId(),
2968 L"You have been kicked due to message flooding.");
2970 case RPLAYER_CHATRESULT_OK:
2973 FATAL_ERROR("Unhandled chat filtering result found.");
2977 if (m_max_chatmessage_length > 0 &&
2978 wmessage.length() > m_max_chatmessage_length) {
2979 return L"Your message exceed the maximum chat message limit set on the "
2981 L"It was refused. Send a shorter message";
2984 auto message = trim(wide_to_utf8(wmessage));
2985 if (message.find_first_of("\n\r") != std::wstring::npos) {
2986 return L"New lines are not permitted in chat messages";
2989 // Run script hook, exit if script ate the chat message
2990 if (m_script->on_chat_message(name, message))
2995 // Whether to send line to the player that sent the message, or to all players
2996 bool broadcast_line = true;
2998 if (check_shout_priv && !checkPriv(name, "shout")) {
2999 line += L"-!- You don't have permission to shout.";
3000 broadcast_line = false;
3003 Workaround for fixing chat on Android. Lua doesn't handle
3004 the Cyrillic alphabet and some characters on older Android devices
3007 line += L"<" + wname + L"> " + wmessage;
3009 line += narrow_to_wide(m_script->formatChatMessage(
3010 name, wide_to_narrow(wmessage)));
3015 Tell calling method to send the message to sender
3017 if (!broadcast_line)
3021 Send the message to others
3023 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
3025 std::vector<session_t> clients = m_clients.getClientIDs();
3028 Send the message back to the inital sender
3029 if they are using protocol version >= 29
3032 session_t peer_id_to_avoid_sending =
3033 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
3035 if (player && player->protocol_version >= 29)
3036 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
3038 for (u16 cid : clients) {
3039 if (cid != peer_id_to_avoid_sending)
3040 SendChatMessage(cid, ChatMessage(line));
3045 void Server::handleAdminChat(const ChatEventChat *evt)
3047 std::string name = evt->nick;
3048 std::wstring wname = utf8_to_wide(name);
3049 std::wstring wmessage = evt->evt_msg;
3051 std::wstring answer = handleChat(name, wname, wmessage);
3053 // If asked to send answer to sender
3054 if (!answer.empty()) {
3055 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3059 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3061 RemoteClient *client = getClientNoEx(peer_id, state_min);
3063 throw ClientNotFoundException("Client not found");
3067 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3069 return m_clients.getClientNoEx(peer_id, state_min);
3072 std::string Server::getPlayerName(session_t peer_id)
3074 RemotePlayer *player = m_env->getPlayer(peer_id);
3076 return "[id=" + itos(peer_id) + "]";
3077 return player->getName();
3080 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3082 RemotePlayer *player = m_env->getPlayer(peer_id);
3085 return player->getPlayerSAO();
3088 std::wstring Server::getStatusString()
3090 std::wostringstream os(std::ios_base::binary);
3091 os << L"# Server: ";
3093 os << L"version=" << narrow_to_wide(g_version_string);
3095 os << L", uptime=" << m_uptime_counter->get();
3097 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3099 // Information about clients
3101 os << L", clients={";
3103 std::vector<session_t> clients = m_clients.getClientIDs();
3104 for (session_t client_id : clients) {
3105 RemotePlayer *player = m_env->getPlayer(client_id);
3107 // Get name of player
3108 std::wstring name = L"unknown";
3110 name = narrow_to_wide(player->getName());
3112 // Add name to information string
3123 if (m_env && !((ServerMap *)(&m_env->getMap()))->isSavingEnabled())
3124 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3126 if (!g_settings->get("motd").empty())
3128 << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3133 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3135 std::set<std::string> privs;
3136 m_script->getAuth(name, NULL, &privs);
3140 bool Server::checkPriv(const std::string &name, const std::string &priv)
3142 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3143 return (privs.count(priv) != 0);
3146 void Server::reportPrivsModified(const std::string &name)
3149 std::vector<session_t> clients = m_clients.getClientIDs();
3150 for (const session_t client_id : clients) {
3151 RemotePlayer *player = m_env->getPlayer(client_id);
3152 reportPrivsModified(player->getName());
3155 RemotePlayer *player = m_env->getPlayer(name.c_str());
3158 SendPlayerPrivileges(player->getPeerId());
3159 PlayerSAO *sao = player->getPlayerSAO();
3162 sao->updatePrivileges(getPlayerEffectivePrivs(name), isSingleplayer());
3166 void Server::reportInventoryFormspecModified(const std::string &name)
3168 RemotePlayer *player = m_env->getPlayer(name.c_str());
3171 SendPlayerInventoryFormspec(player->getPeerId());
3174 void Server::reportFormspecPrependModified(const std::string &name)
3176 RemotePlayer *player = m_env->getPlayer(name.c_str());
3179 SendPlayerFormspecPrepend(player->getPeerId());
3182 void Server::setIpBanned(const std::string &ip, const std::string &name)
3184 m_banmanager->add(ip, name);
3187 void Server::unsetIpBanned(const std::string &ip_or_name)
3189 m_banmanager->remove(ip_or_name);
3192 std::string Server::getBanDescription(const std::string &ip_or_name)
3194 return m_banmanager->getBanDescription(ip_or_name);
3197 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3199 // m_env will be NULL if the server is initializing
3203 if (m_admin_nick == name && !m_admin_nick.empty()) {
3204 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3207 RemotePlayer *player = m_env->getPlayer(name);
3212 if (player->getPeerId() == PEER_ID_INEXISTENT)
3215 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3218 bool Server::showFormspec(const char *playername, const std::string &formspec,
3219 const std::string &formname)
3221 // m_env will be NULL if the server is initializing
3225 RemotePlayer *player = m_env->getPlayer(playername);
3229 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3233 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3238 u32 id = player->addHud(form);
3240 SendHUDAdd(player->getPeerId(), id, form);
3245 bool Server::hudRemove(RemotePlayer *player, u32 id)
3250 HudElement *todel = player->removeHud(id);
3257 SendHUDRemove(player->getPeerId(), id);
3261 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3266 SendHUDChange(player->getPeerId(), id, stat, data);
3270 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3275 SendHUDSetFlags(player->getPeerId(), flags, mask);
3276 player->hud_flags &= ~mask;
3277 player->hud_flags |= flags;
3279 PlayerSAO *playersao = player->getPlayerSAO();
3284 m_script->player_event(playersao, "hud_changed");
3288 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3293 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3296 player->setHotbarItemcount(hotbar_itemcount);
3297 std::ostringstream os(std::ios::binary);
3298 writeS32(os, hotbar_itemcount);
3299 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3303 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3308 player->setHotbarImage(name);
3309 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3312 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3317 player->setHotbarSelectedImage(name);
3318 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3321 Address Server::getPeerAddress(session_t peer_id)
3323 return m_con->GetPeerAddress(peer_id);
3326 void Server::setLocalPlayerAnimations(
3327 RemotePlayer *player, v2s32 animation_frames[4], f32 frame_speed)
3329 sanity_check(player);
3330 player->setLocalAnimations(animation_frames, frame_speed);
3331 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3334 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3336 sanity_check(player);
3337 player->eye_offset_first = first;
3338 player->eye_offset_third = third;
3339 SendEyeOffset(player->getPeerId(), first, third);
3342 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3344 sanity_check(player);
3345 player->setSky(params);
3346 SendSetSky(player->getPeerId(), params);
3349 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3351 sanity_check(player);
3352 player->setSun(params);
3353 SendSetSun(player->getPeerId(), params);
3356 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3358 sanity_check(player);
3359 player->setMoon(params);
3360 SendSetMoon(player->getPeerId(), params);
3363 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3365 sanity_check(player);
3366 player->setStars(params);
3367 SendSetStars(player->getPeerId(), params);
3370 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3372 sanity_check(player);
3373 player->setCloudParams(params);
3374 SendCloudParams(player->getPeerId(), params);
3377 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override, float ratio)
3379 sanity_check(player);
3380 player->overrideDayNightRatio(do_override, ratio);
3381 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3384 void Server::notifyPlayers(const std::wstring &msg)
3386 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3389 void Server::spawnParticle(const std::string &playername, const ParticleParameters &p)
3391 // m_env will be NULL if the server is initializing
3395 session_t peer_id = PEER_ID_INEXISTENT;
3397 if (!playername.empty()) {
3398 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3401 peer_id = player->getPeerId();
3402 proto_ver = player->protocol_version;
3405 SendSpawnParticle(peer_id, proto_ver, p);
3408 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3409 ServerActiveObject *attached, const std::string &playername)
3411 // m_env will be NULL if the server is initializing
3415 session_t peer_id = PEER_ID_INEXISTENT;
3417 if (!playername.empty()) {
3418 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3421 peer_id = player->getPeerId();
3422 proto_ver = player->protocol_version;
3425 u16 attached_id = attached ? attached->getId() : 0;
3428 if (attached_id == 0)
3429 id = m_env->addParticleSpawner(p.time);
3431 id = m_env->addParticleSpawner(p.time, attached_id);
3433 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3437 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3439 // m_env will be NULL if the server is initializing
3442 "Can't delete particle spawners during initialisation!");
3444 session_t peer_id = PEER_ID_INEXISTENT;
3445 if (!playername.empty()) {
3446 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3449 peer_id = player->getPeerId();
3452 m_env->deleteParticleSpawner(id);
3453 SendDeleteParticleSpawner(peer_id, id);
3456 bool Server::dynamicAddMedia(const std::string &filepath)
3458 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3459 if (m_media.find(filename) != m_media.end()) {
3460 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3461 << "\" already exists in media cache" << std::endl;
3465 // Load the file and add it to our media cache
3466 std::string filedata, raw_hash;
3467 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3471 // Push file to existing clients
3472 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3473 pkt << raw_hash << filename << (bool)true;
3474 pkt.putLongString(filedata);
3476 auto client_ids = m_clients.getClientIDs(CS_DefinitionsSent);
3477 for (session_t client_id : client_ids) {
3479 The network layer only guarantees ordered delivery inside a
3480 channel. Since the very next packet could be one that uses the media,
3481 we have to push the media over ALL channels to ensure it is processed
3482 before it is used. In practice this means we have to send it twice:
3484 - channel 0 (everything else: e.g. play_sound, object messages)
3486 m_clients.send(client_id, 1, &pkt, true);
3487 m_clients.send(client_id, 0, &pkt, true);
3493 // actions: time-reversed list
3494 // Return value: success/failure
3495 bool Server::rollbackRevertActions(
3496 const std::list<RollbackAction> &actions, std::list<std::string> *log)
3498 infostream << "Server::rollbackRevertActions(len=" << actions.size() << ")"
3500 ServerMap *map = (ServerMap *)(&m_env->getMap());
3502 // Fail if no actions to handle
3503 if (actions.empty()) {
3505 log->push_back("Nothing to do.");
3512 for (const RollbackAction &action : actions) {
3514 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3517 std::ostringstream os;
3518 os << "Revert of step (" << num_tried << ") " << action.toString()
3520 infostream << "Map::rollbackRevertActions(): " << os.str()
3523 log->push_back(os.str());
3525 std::ostringstream os;
3526 os << "Successfully reverted step (" << num_tried << ") "
3527 << action.toString();
3528 infostream << "Map::rollbackRevertActions(): " << os.str()
3531 log->push_back(os.str());
3535 infostream << "Map::rollbackRevertActions(): " << num_failed << "/" << num_tried
3536 << " failed" << std::endl;
3538 // Call it done if less than half failed
3539 return num_failed <= num_tried / 2;
3542 // IGameDef interface
3544 IItemDefManager *Server::getItemDefManager()
3549 const NodeDefManager *Server::getNodeDefManager()
3554 ICraftDefManager *Server::getCraftDefManager()
3559 u16 Server::allocateUnknownNodeId(const std::string &name)
3561 return m_nodedef->allocateDummy(name);
3564 IWritableItemDefManager *Server::getWritableItemDefManager()
3569 NodeDefManager *Server::getWritableNodeDefManager()
3574 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3579 const std::vector<ModSpec> &Server::getMods() const
3581 return m_modmgr->getMods();
3584 const ModSpec *Server::getModSpec(const std::string &modname) const
3586 return m_modmgr->getModSpec(modname);
3589 void Server::getModNames(std::vector<std::string> &modlist)
3591 m_modmgr->getModNames(modlist);
3594 std::string Server::getBuiltinLuaPath()
3596 return porting::path_share + DIR_DELIM + "builtin";
3599 std::string Server::getModStoragePath() const
3601 return m_path_world + DIR_DELIM + "mod_storage";
3604 v3f Server::findSpawnPos()
3606 ServerMap &map = m_env->getServerMap();
3608 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3609 return nodeposf * BS;
3611 bool is_good = false;
3612 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3613 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3615 // Try to find a good place a few times
3616 for (s32 i = 0; i < 4000 && !is_good; i++) {
3617 s32 range = MYMIN(1 + i, range_max);
3618 // We're going to try to throw the player to this position
3619 v2s16 nodepos2d = v2s16(-range + (myrand() % (range * 2)),
3620 -range + (myrand() % (range * 2)));
3621 // Get spawn level at point
3622 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3623 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3624 // signify an unsuitable spawn position, or if outside limits.
3625 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3626 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3629 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3630 // Consecutive empty nodes
3633 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3634 // avoid obstructions in already-generated mapblocks.
3635 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3636 // no obstructions, but mapgen decorations are generated after spawn so
3637 // the player may end up inside one.
3638 for (s32 i = 0; i < 8; i++) {
3639 v3s16 blockpos = getNodeBlockPos(nodepos);
3640 map.emergeBlock(blockpos, true);
3641 content_t c = map.getNode(nodepos).getContent();
3643 // In generated mapblocks allow spawn in all 'airlike' drawtype
3644 // nodes. In ungenerated mapblocks allow spawn in 'ignore' nodes.
3645 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE ||
3646 c == CONTENT_IGNORE) {
3648 if (air_count >= 2) {
3649 // Spawn in lower empty node
3651 nodeposf = intToFloat(nodepos, BS);
3652 // Don't spawn the player outside map boundaries
3653 if (objectpos_over_limit(nodeposf))
3654 // Exit this loop, positions above are
3655 // probably over limit
3658 // Good position found, cause an exit from main
3673 // No suitable spawn point found, return fallback 0,0,0
3674 return v3f(0.0f, 0.0f, 0.0f);
3677 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3679 if (delay == 0.0f) {
3680 // No delay, shutdown immediately
3681 m_shutdown_state.is_requested = true;
3682 // only print to the infostream, a chat message saying
3683 // "Server Shutting Down" is sent when the server destructs.
3684 infostream << "*** Immediate Server shutdown requested." << std::endl;
3685 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3686 // Negative delay, cancel shutdown if requested
3687 m_shutdown_state.reset();
3688 std::wstringstream ws;
3690 ws << L"*** Server shutdown canceled.";
3692 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3693 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3694 // m_shutdown_* are already handled, skip.
3696 } else if (delay > 0.0f) {
3697 // Positive delay, tell the clients when the server will shut down
3698 std::wstringstream ws;
3700 ws << L"*** Server shutting down in "
3701 << duration_to_string(myround(delay)).c_str() << ".";
3703 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3704 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3707 m_shutdown_state.trigger(delay, msg, reconnect);
3710 PlayerSAO *Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3713 Try to get an existing player
3715 RemotePlayer *player = m_env->getPlayer(name);
3717 // If player is already connected, cancel
3718 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3719 infostream << "emergePlayer(): Player already connected" << std::endl;
3724 If player with the wanted peer_id already exists, cancel.
3726 if (m_env->getPlayer(peer_id)) {
3727 infostream << "emergePlayer(): Player with wrong name but same"
3728 " peer_id already exists"
3734 player = new RemotePlayer(name, idef());
3737 bool newplayer = false;
3740 PlayerSAO *playersao =
3741 m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3743 // Complete init with server parts
3744 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3745 player->protocol_version = proto_version;
3749 m_script->on_newplayer(playersao);
3755 bool Server::registerModStorage(ModMetadata *storage)
3757 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3758 errorstream << "Unable to register same mod storage twice. Storage name: "
3759 << storage->getModName() << std::endl;
3763 m_mod_storages[storage->getModName()] = storage;
3767 void Server::unregisterModStorage(const std::string &name)
3769 std::unordered_map<std::string, ModMetadata *>::const_iterator it =
3770 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)) {
3808 infostream << "Profiler:" << std::endl;
3809 g_profiler->print(infostream);
3810 g_profiler->clear();
3815 infostream << "Dedicated server quitting" << std::endl;
3817 if (g_settings->getBool("server_announce"))
3818 ServerList::sendAnnounce(
3819 ServerList::AA_DELETE, server.m_bind_addr.getPort());
3827 bool Server::joinModChannel(const std::string &channel)
3829 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3830 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3833 bool Server::leaveModChannel(const std::string &channel)
3835 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3838 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3840 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3843 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3847 ModChannel *Server::getModChannel(const std::string &channel)
3849 return m_modchannel_mgr->getModChannel(channel);
3852 void Server::broadcastModChannelMessage(const std::string &channel,
3853 const std::string &message, session_t from_peer)
3855 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3859 if (message.size() > STRING_MAX_LEN) {
3860 warningstream << "ModChannel message too long, dropping before sending "
3861 << " (" << message.size() << " > " << STRING_MAX_LEN
3862 << ", channel: " << channel << ")" << std::endl;
3867 if (from_peer != PEER_ID_SERVER) {
3868 sender = getPlayerName(from_peer);
3871 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3872 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3873 resp_pkt << channel << sender << message;
3874 for (session_t peer_id : peers) {
3876 if (peer_id == from_peer)
3879 Send(peer_id, &resp_pkt);
3882 if (from_peer != PEER_ID_SERVER) {
3883 m_script->on_modchannel_message(channel, sender, message);
3887 void Server::loadTranslationLanguage(const std::string &lang_code)
3889 if (g_server_translations->count(lang_code))
3890 return; // Already loaded
3892 std::string suffix = "." + lang_code + ".tr";
3893 for (const auto &i : m_media) {
3894 if (str_ends_with(i.first, suffix)) {
3895 std::ifstream t(i.second.path);
3896 std::string data((std::istreambuf_iterator<char>(t)),
3897 std::istreambuf_iterator<char>());
3899 (*g_server_translations)[lang_code].loadTranslation(data);