3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "server/serveractiveobject.h"
41 #include "scripting_server.h"
46 #include "mapgen/mapgen.h"
47 #include "mapgen/mg_biome.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content/mods.h"
51 #include "modchannels.h"
52 #include "serverlist.h"
53 #include "util/string.h"
55 #include "util/serialize.h"
56 #include "util/thread.h"
57 #include "defaultsettings.h"
58 #include "server/mods.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
62 #include "database/database.h"
63 #include "chatmessage.h"
64 #include "chat_interface.h"
65 #include "remoteplayer.h"
66 #include "server/player_sao.h"
67 #include "server/serverinventorymgr.h"
68 #include "translation.h"
70 class ClientNotFoundException : public BaseException
73 ClientNotFoundException(const char *s):
78 class ServerThread : public Thread
82 ServerThread(Server *server):
93 void *ServerThread::run()
95 BEGIN_DEBUG_EXCEPTION_HANDLER
98 * The real business of the server happens on the ServerThread.
100 * AsyncRunStep() runs an actual server step as soon as enough time has
101 * passed (dedicated_server_loop keeps track of that).
102 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
103 * doesn't busy wait) and will process any remaining packets.
106 m_server->AsyncRunStep(true);
108 while (!stopRequested()) {
110 m_server->AsyncRunStep();
114 } catch (con::PeerNotFoundException &e) {
115 infostream<<"Server: PeerNotFoundException"<<std::endl;
116 } catch (ClientNotFoundException &e) {
117 } catch (con::ConnectionBindFailed &e) {
118 m_server->setAsyncFatalError(e.what());
119 } catch (LuaError &e) {
120 m_server->setAsyncFatalError(
121 "ServerThread::run Lua: " + std::string(e.what()));
125 END_DEBUG_EXCEPTION_HANDLER
130 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
132 if(pos_exists) *pos_exists = false;
137 if(pos_exists) *pos_exists = true;
142 ServerActiveObject *sao = env->getActiveObject(object);
145 if(pos_exists) *pos_exists = true;
146 return sao->getBasePosition(); }
151 void Server::ShutdownState::reset()
155 should_reconnect = false;
156 is_requested = false;
159 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
163 should_reconnect = reconnect;
166 void Server::ShutdownState::tick(float dtime, Server *server)
172 static const float shutdown_msg_times[] =
174 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
177 // Automated messages
178 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
179 for (float t : shutdown_msg_times) {
180 // If shutdown timer matches an automessage, shot it
181 if (m_timer > t && m_timer - dtime < t) {
182 std::wstring periodicMsg = getShutdownTimerMessage();
184 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
185 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
192 if (m_timer < 0.0f) {
198 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
200 std::wstringstream ws;
201 ws << L"*** Server shutting down in "
202 << duration_to_string(myround(m_timer)).c_str() << ".";
211 const std::string &path_world,
212 const SubgameSpec &gamespec,
213 bool simple_singleplayer_mode,
218 m_bind_addr(bind_addr),
219 m_path_world(path_world),
220 m_gamespec(gamespec),
221 m_simple_singleplayer_mode(simple_singleplayer_mode),
222 m_dedicated(dedicated),
223 m_async_fatal_error(""),
224 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
227 m_bind_addr.isIPv6(),
229 m_itemdef(createItemDefManager()),
230 m_nodedef(createNodeDefManager()),
231 m_craftdef(createCraftDefManager()),
232 m_thread(new ServerThread(this)),
235 m_modchannel_mgr(new ModChannelMgr())
237 if (m_path_world.empty())
238 throw ServerError("Supplied empty world path");
240 if (!gamespec.isValid())
241 throw ServerError("Supplied invalid gamespec");
244 m_metrics_backend = std::unique_ptr<MetricsBackend>(createPrometheusMetricsBackend());
246 m_metrics_backend = std::unique_ptr<MetricsBackend>(new MetricsBackend());
249 m_uptime_counter = m_metrics_backend->addCounter("minetest_core_server_uptime", "Server uptime (in seconds)");
250 m_player_gauge = m_metrics_backend->addGauge("minetest_core_player_number", "Number of connected players");
252 m_timeofday_gauge = m_metrics_backend->addGauge(
253 "minetest_core_timeofday",
254 "Time of day value");
256 m_lag_gauge = m_metrics_backend->addGauge(
257 "minetest_core_latency",
258 "Latency value (in seconds)");
260 m_aom_buffer_counter = m_metrics_backend->addCounter(
261 "minetest_core_aom_generated_count",
262 "Number of active object messages generated");
264 m_packet_recv_counter = m_metrics_backend->addCounter(
265 "minetest_core_server_packet_recv",
266 "Processable packets received");
268 m_packet_recv_processed_counter = m_metrics_backend->addCounter(
269 "minetest_core_server_packet_recv_processed",
270 "Valid received packets processed");
272 m_lag_gauge->set(g_settings->getFloat("dedicated_server_step"));
278 // Send shutdown message
279 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
280 L"*** Server shutting down"));
283 MutexAutoLock envlock(m_env_mutex);
285 infostream << "Server: Saving players" << std::endl;
286 m_env->saveLoadedPlayers();
288 infostream << "Server: Kicking players" << std::endl;
289 std::string kick_msg;
290 bool reconnect = false;
291 if (isShutdownRequested()) {
292 reconnect = m_shutdown_state.should_reconnect;
293 kick_msg = m_shutdown_state.message;
295 if (kick_msg.empty()) {
296 kick_msg = g_settings->get("kick_msg_shutdown");
298 m_env->saveLoadedPlayers(true);
299 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
300 kick_msg, reconnect);
303 actionstream << "Server: Shutting down" << std::endl;
305 // Do this before stopping the server in case mapgen callbacks need to access
306 // server-controlled resources (like ModStorages). Also do them before
307 // shutdown callbacks since they may modify state that is finalized in a
310 m_emerge->stopThreads();
313 MutexAutoLock envlock(m_env_mutex);
315 // Execute script shutdown hooks
316 infostream << "Executing shutdown hooks" << std::endl;
317 m_script->on_shutdown();
319 infostream << "Server: Saving environment metadata" << std::endl;
329 // Delete things in the reverse order of creation
338 // Deinitialize scripting
339 infostream << "Server: Deinitializing scripting" << std::endl;
342 while (!m_unsent_map_edit_queue.empty()) {
343 delete m_unsent_map_edit_queue.front();
344 m_unsent_map_edit_queue.pop();
350 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
351 if (m_simple_singleplayer_mode)
352 infostream << " in simple singleplayer mode" << std::endl;
354 infostream << std::endl;
355 infostream << "- world: " << m_path_world << std::endl;
356 infostream << "- game: " << m_gamespec.path << std::endl;
358 // Create world if it doesn't exist
359 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
360 throw ServerError("Failed to initialize world");
362 // Create emerge manager
363 m_emerge = new EmergeManager(this);
365 // Create ban manager
366 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
367 m_banmanager = new BanManager(ban_path);
369 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
370 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
371 // complain about mods with unsatisfied dependencies
372 if (!m_modmgr->isConsistent()) {
373 m_modmgr->printUnsatisfiedModsError();
377 MutexAutoLock envlock(m_env_mutex);
379 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
380 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge, m_metrics_backend.get());
382 // Initialize scripting
383 infostream << "Server: Initializing Lua" << std::endl;
385 m_script = new ServerScripting(this);
387 // Must be created before mod loading because we have some inventory creation
388 m_inventory_mgr = std::unique_ptr<ServerInventoryManager>(new ServerInventoryManager());
390 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
392 m_modmgr->loadMods(m_script);
394 // Read Textures and calculate sha1 sums
397 // Apply item aliases in the node definition manager
398 m_nodedef->updateAliases(m_itemdef);
400 // Apply texture overrides from texturepack/override.txt
401 std::vector<std::string> paths;
402 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
403 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
404 for (const std::string &path : paths) {
405 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
406 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
407 m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
410 m_nodedef->setNodeRegistrationStatus(true);
412 // Perform pending node name resolutions
413 m_nodedef->runNodeResolveCallbacks();
415 // unmap node names in cross-references
416 m_nodedef->resolveCrossrefs();
418 // init the recipe hashes to speed up crafting
419 m_craftdef->initHashes(this);
421 // Initialize Environment
422 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
424 m_inventory_mgr->setEnv(m_env);
425 m_clients.setEnv(m_env);
427 if (!servermap->settings_mgr.makeMapgenParams())
428 FATAL_ERROR("Couldn't create any mapgen type");
430 // Initialize mapgens
431 m_emerge->initMapgens(servermap->getMapgenParams());
433 if (g_settings->getBool("enable_rollback_recording")) {
434 // Create rollback manager
435 m_rollback = new RollbackManager(m_path_world, this);
438 // Give environment reference to scripting api
439 m_script->initializeEnvironment(m_env);
441 // Register us to receive map edit events
442 servermap->addEventReceiver(this);
446 // Those settings can be overwritten in world.mt, they are
447 // intended to be cached after environment loading.
448 m_liquid_transform_every = g_settings->getFloat("liquid_update");
449 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
450 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
451 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
458 infostream << "Starting server on " << m_bind_addr.serializeString()
459 << "..." << std::endl;
461 // Stop thread if already running
464 // Initialize connection
465 m_con->SetTimeoutMs(30);
466 m_con->Serve(m_bind_addr);
471 // ASCII art for the win!
473 << " .__ __ __ " << std::endl
474 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
475 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
476 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
477 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
478 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
479 actionstream << "World at [" << m_path_world << "]" << std::endl;
480 actionstream << "Server for gameid=\"" << m_gamespec.id
481 << "\" listening on " << m_bind_addr.serializeString() << ":"
482 << m_bind_addr.getPort() << "." << std::endl;
487 infostream<<"Server: Stopping and waiting threads"<<std::endl;
489 // Stop threads (set run=false first so both start stopping)
491 //m_emergethread.setRun(false);
493 //m_emergethread.stop();
495 infostream<<"Server: Threads stopped"<<std::endl;
498 void Server::step(float dtime)
504 MutexAutoLock lock(m_step_dtime_mutex);
505 m_step_dtime += dtime;
507 // Throw if fatal error occurred in thread
508 std::string async_err = m_async_fatal_error.get();
509 if (!async_err.empty()) {
510 if (!m_simple_singleplayer_mode) {
511 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
512 g_settings->get("kick_msg_crash"),
513 g_settings->getBool("ask_reconnect_on_crash"));
515 throw ServerError("AsyncErr: " + async_err);
519 void Server::AsyncRunStep(bool initial_step)
524 MutexAutoLock lock1(m_step_dtime_mutex);
525 dtime = m_step_dtime;
529 // Send blocks to clients
533 if((dtime < 0.001) && !initial_step)
536 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
539 MutexAutoLock lock1(m_step_dtime_mutex);
540 m_step_dtime -= dtime;
546 m_uptime_counter->increment(dtime);
551 Update time of day and overall game time
553 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
556 Send to clients at constant intervals
559 m_time_of_day_send_timer -= dtime;
560 if (m_time_of_day_send_timer < 0.0) {
561 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
562 u16 time = m_env->getTimeOfDay();
563 float time_speed = g_settings->getFloat("time_speed");
564 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
566 m_timeofday_gauge->set(time);
570 MutexAutoLock lock(m_env_mutex);
571 // Figure out and report maximum lag to environment
572 float max_lag = m_env->getMaxLagEstimate();
573 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
575 if(dtime > 0.1 && dtime > max_lag * 2.0)
576 infostream<<"Server: Maximum lag peaked to "<<dtime
580 m_env->reportMaxLagEstimate(max_lag);
585 static const float map_timer_and_unload_dtime = 2.92;
586 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
588 MutexAutoLock lock(m_env_mutex);
589 // Run Map's timers and unload unused data
590 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
591 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
592 g_settings->getFloat("server_unload_unused_data_timeout"),
597 Listen to the admin chat, if available
600 if (!m_admin_chat->command_queue.empty()) {
601 MutexAutoLock lock(m_env_mutex);
602 while (!m_admin_chat->command_queue.empty()) {
603 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
604 handleChatInterfaceEvent(evt);
608 m_admin_chat->outgoing_queue.push_back(
609 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
616 /* Transform liquids */
617 m_liquid_transform_timer += dtime;
618 if(m_liquid_transform_timer >= m_liquid_transform_every)
620 m_liquid_transform_timer -= m_liquid_transform_every;
622 MutexAutoLock lock(m_env_mutex);
624 ScopeProfiler sp(g_profiler, "Server: liquid transform");
626 std::map<v3s16, MapBlock*> modified_blocks;
627 m_env->getMap().transformLiquids(modified_blocks, m_env);
630 Set the modified blocks unsent for all the clients
632 if (!modified_blocks.empty()) {
633 SetBlocksNotSent(modified_blocks);
636 m_clients.step(dtime);
638 m_lag_gauge->increment((m_lag_gauge->get() > dtime ? -1 : 1) * dtime/100);
640 // send masterserver announce
642 float &counter = m_masterserver_timer;
643 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
644 g_settings->getBool("server_announce")) {
645 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
646 ServerList::AA_START,
647 m_bind_addr.getPort(),
648 m_clients.getPlayerNames(),
649 m_uptime_counter->get(),
650 m_env->getGameTime(),
653 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
663 Check added and deleted active objects
666 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
667 MutexAutoLock envlock(m_env_mutex);
670 const RemoteClientMap &clients = m_clients.getClientList();
671 ScopeProfiler sp(g_profiler, "Server: update objects within range");
673 m_player_gauge->set(clients.size());
674 for (const auto &client_it : clients) {
675 RemoteClient *client = client_it.second;
677 if (client->getState() < CS_DefinitionsSent)
680 // This can happen if the client times out somehow
681 if (!m_env->getPlayer(client->peer_id))
684 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
688 SendActiveObjectRemoveAdd(client, playersao);
692 // Save mod storages if modified
693 m_mod_storage_save_timer -= dtime;
694 if (m_mod_storage_save_timer <= 0.0f) {
695 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
697 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
698 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
699 if (it->second->isModified()) {
700 it->second->save(getModStoragePath());
705 infostream << "Saved " << n << " modified mod storages." << std::endl;
713 MutexAutoLock envlock(m_env_mutex);
714 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
717 // Value = data sent by object
718 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
720 // Get active object messages from environment
721 ActiveObjectMessage aom(0);
724 if (!m_env->getActiveObjectMessage(&aom))
727 std::vector<ActiveObjectMessage>* message_list = nullptr;
728 auto n = buffered_messages.find(aom.id);
729 if (n == buffered_messages.end()) {
730 message_list = new std::vector<ActiveObjectMessage>;
731 buffered_messages[aom.id] = message_list;
733 message_list = n->second;
735 message_list->push_back(std::move(aom));
739 m_aom_buffer_counter->increment(aom_count);
742 const RemoteClientMap &clients = m_clients.getClientList();
743 // Route data to every client
744 std::string reliable_data, unreliable_data;
745 for (const auto &client_it : clients) {
746 reliable_data.clear();
747 unreliable_data.clear();
748 RemoteClient *client = client_it.second;
749 PlayerSAO *player = getPlayerSAO(client->peer_id);
750 // Go through all objects in message buffer
751 for (const auto &buffered_message : buffered_messages) {
752 // If object does not exist or is not known by client, skip it
753 u16 id = buffered_message.first;
754 ServerActiveObject *sao = m_env->getActiveObject(id);
755 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
758 // Get message list of object
759 std::vector<ActiveObjectMessage>* list = buffered_message.second;
760 // Go through every message
761 for (const ActiveObjectMessage &aom : *list) {
762 // Send position updates to players who do not see the attachment
763 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
764 if (sao->getId() == player->getId())
767 // Do not send position updates for attached players
768 // as long the parent is known to the client
769 ServerActiveObject *parent = sao->getParent();
770 if (parent && client->m_known_objects.find(parent->getId()) !=
771 client->m_known_objects.end())
775 // Add full new data to appropriate buffer
776 std::string &buffer = aom.reliable ? reliable_data : unreliable_data;
778 writeU16((u8*) idbuf, aom.id);
781 buffer.append(idbuf, sizeof(idbuf));
782 buffer.append(serializeString(aom.datastring));
786 reliable_data and unreliable_data are now ready.
789 if (!reliable_data.empty()) {
790 SendActiveObjectMessages(client->peer_id, reliable_data);
793 if (!unreliable_data.empty()) {
794 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
799 // Clear buffered_messages
800 for (auto &buffered_message : buffered_messages) {
801 delete buffered_message.second;
806 Send queued-for-sending map edit events.
809 // We will be accessing the environment
810 MutexAutoLock lock(m_env_mutex);
812 // Don't send too many at a time
815 // Single change sending is disabled if queue size is not small
816 bool disable_single_change_sending = false;
817 if(m_unsent_map_edit_queue.size() >= 4)
818 disable_single_change_sending = true;
820 int event_count = m_unsent_map_edit_queue.size();
822 // We'll log the amount of each
825 std::list<v3s16> node_meta_updates;
827 while (!m_unsent_map_edit_queue.empty()) {
828 MapEditEvent* event = m_unsent_map_edit_queue.front();
829 m_unsent_map_edit_queue.pop();
831 // Players far away from the change are stored here.
832 // Instead of sending the changes, MapBlocks are set not sent
834 std::unordered_set<u16> far_players;
836 switch (event->type) {
839 prof.add("MEET_ADDNODE", 1);
840 sendAddNode(event->p, event->n, &far_players,
841 disable_single_change_sending ? 5 : 30,
842 event->type == MEET_ADDNODE);
844 case MEET_REMOVENODE:
845 prof.add("MEET_REMOVENODE", 1);
846 sendRemoveNode(event->p, &far_players,
847 disable_single_change_sending ? 5 : 30);
849 case MEET_BLOCK_NODE_METADATA_CHANGED: {
850 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
851 if (!event->is_private_change) {
852 // Don't send the change yet. Collect them to eliminate dupes.
853 node_meta_updates.remove(event->p);
854 node_meta_updates.push_back(event->p);
857 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
858 getNodeBlockPos(event->p))) {
859 block->raiseModified(MOD_STATE_WRITE_NEEDED,
860 MOD_REASON_REPORT_META_CHANGE);
865 prof.add("MEET_OTHER", 1);
866 for (const v3s16 &modified_block : event->modified_blocks) {
867 m_clients.markBlockposAsNotSent(modified_block);
871 prof.add("unknown", 1);
872 warningstream << "Server: Unknown MapEditEvent "
873 << ((u32)event->type) << std::endl;
878 Set blocks not sent to far players
880 if (!far_players.empty()) {
881 // Convert list format to that wanted by SetBlocksNotSent
882 std::map<v3s16, MapBlock*> modified_blocks2;
883 for (const v3s16 &modified_block : event->modified_blocks) {
884 modified_blocks2[modified_block] =
885 m_env->getMap().getBlockNoCreateNoEx(modified_block);
888 // Set blocks not sent
889 for (const u16 far_player : far_players) {
890 if (RemoteClient *client = getClient(far_player))
891 client->SetBlocksNotSent(modified_blocks2);
898 if (event_count >= 5) {
899 infostream << "Server: MapEditEvents:" << std::endl;
900 prof.print(infostream);
901 } else if (event_count != 0) {
902 verbosestream << "Server: MapEditEvents:" << std::endl;
903 prof.print(verbosestream);
906 // Send all metadata updates
907 if (node_meta_updates.size())
908 sendMetadataChanged(node_meta_updates);
912 Trigger emergethread (it somehow gets to a non-triggered but
913 bysy state sometimes)
916 float &counter = m_emergethread_trigger_timer;
918 if (counter >= 2.0) {
921 m_emerge->startThreads();
925 // Save map, players and auth stuff
927 float &counter = m_savemap_timer;
929 static thread_local const float save_interval =
930 g_settings->getFloat("server_map_save_interval");
931 if (counter >= save_interval) {
933 MutexAutoLock lock(m_env_mutex);
935 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
938 if (m_banmanager->isModified()) {
939 m_banmanager->save();
942 // Save changed parts of map
943 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
946 m_env->saveLoadedPlayers();
948 // Save environment metadata
953 m_shutdown_state.tick(dtime, this);
956 void Server::Receive()
966 In the first iteration *wait* for a packet, afterwards process
967 all packets that are immediately available (no waiting).
970 m_con->Receive(&pkt);
973 if (!m_con->TryReceive(&pkt))
977 peer_id = pkt.getPeerId();
978 m_packet_recv_counter->increment();
980 m_packet_recv_processed_counter->increment();
981 } catch (const con::InvalidIncomingDataException &e) {
982 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
983 << e.what() << std::endl;
984 } catch (const SerializationError &e) {
985 infostream << "Server::Receive(): SerializationError: what()="
986 << e.what() << std::endl;
987 } catch (const ClientStateError &e) {
988 errorstream << "ProcessData: peer=" << peer_id << " what()="
989 << e.what() << std::endl;
990 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
991 L"Try reconnecting or updating your client");
992 } catch (const con::PeerNotFoundException &e) {
994 } catch (const con::NoIncomingDataException &e) {
1000 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1002 std::string playername;
1003 PlayerSAO *playersao = NULL;
1006 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1008 playername = client->getName();
1009 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1011 } catch (std::exception &e) {
1017 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1019 // If failed, cancel
1020 if (!playersao || !player) {
1021 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1022 actionstream << "Server: Failed to emerge player \"" << playername
1023 << "\" (player allocated to an another client)" << std::endl;
1024 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1025 L"name. If your client closed unexpectedly, try again in "
1028 errorstream << "Server: " << playername << ": Failed to emerge player"
1030 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1036 Send complete position information
1038 SendMovePlayer(peer_id);
1041 SendPlayerPrivileges(peer_id);
1043 // Send inventory formspec
1044 SendPlayerInventoryFormspec(peer_id);
1047 SendInventory(playersao, false);
1049 // Send HP or death screen
1050 if (playersao->isDead())
1051 SendDeathscreen(peer_id, false, v3f(0,0,0));
1053 SendPlayerHPOrDie(playersao,
1054 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1057 SendPlayerBreath(playersao);
1063 Address addr = getPeerAddress(player->getPeerId());
1064 std::string ip_str = addr.serializeString();
1065 const std::vector<std::string> &names = m_clients.getPlayerNames();
1067 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1069 for (const std::string &name : names) {
1070 actionstream << name << " ";
1073 actionstream << player->getName() <<std::endl;
1078 inline void Server::handleCommand(NetworkPacket *pkt)
1080 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1081 (this->*opHandle.handler)(pkt);
1084 void Server::ProcessData(NetworkPacket *pkt)
1086 // Environment is locked first.
1087 MutexAutoLock envlock(m_env_mutex);
1089 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1090 u32 peer_id = pkt->getPeerId();
1093 Address address = getPeerAddress(peer_id);
1094 std::string addr_s = address.serializeString();
1096 if(m_banmanager->isIpBanned(addr_s)) {
1097 std::string ban_name = m_banmanager->getBanName(addr_s);
1098 infostream << "Server: A banned client tried to connect from "
1099 << addr_s << "; banned name was "
1100 << ban_name << std::endl;
1101 // This actually doesn't seem to transfer to the client
1102 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1103 + utf8_to_wide(ban_name));
1107 catch(con::PeerNotFoundException &e) {
1109 * no peer for this packet found
1110 * most common reason is peer timeout, e.g. peer didn't
1111 * respond for some time, your server was overloaded or
1114 infostream << "Server::ProcessData(): Canceling: peer "
1115 << peer_id << " not found" << std::endl;
1120 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1122 // Command must be handled into ToServerCommandHandler
1123 if (command >= TOSERVER_NUM_MSG_TYPES) {
1124 infostream << "Server: Ignoring unknown command "
1125 << command << std::endl;
1129 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1134 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1136 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1137 errorstream << "Server::ProcessData(): Cancelling: Peer"
1138 " serialization format invalid or not initialized."
1139 " Skipping incoming command=" << command << std::endl;
1143 /* Handle commands related to client startup */
1144 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1149 if (m_clients.getClientState(peer_id) < CS_Active) {
1150 if (command == TOSERVER_PLAYERPOS) return;
1152 errorstream << "Got packet command: " << command << " for peer id "
1153 << peer_id << " but client isn't active yet. Dropping packet "
1159 } catch (SendFailedException &e) {
1160 errorstream << "Server::ProcessData(): SendFailedException: "
1161 << "what=" << e.what()
1163 } catch (PacketError &e) {
1164 actionstream << "Server::ProcessData(): PacketError: "
1165 << "what=" << e.what()
1170 void Server::setTimeOfDay(u32 time)
1172 m_env->setTimeOfDay(time);
1173 m_time_of_day_send_timer = 0;
1176 void Server::onMapEditEvent(const MapEditEvent &event)
1178 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1181 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1184 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1186 std::vector<session_t> clients = m_clients.getClientIDs();
1188 // Set the modified blocks unsent for all the clients
1189 for (const session_t client_id : clients) {
1190 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1191 client->SetBlocksNotSent(block);
1196 void Server::peerAdded(con::Peer *peer)
1198 verbosestream<<"Server::peerAdded(): peer->id="
1199 <<peer->id<<std::endl;
1201 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1204 void Server::deletingPeer(con::Peer *peer, bool timeout)
1206 verbosestream<<"Server::deletingPeer(): peer->id="
1207 <<peer->id<<", timeout="<<timeout<<std::endl;
1209 m_clients.event(peer->id, CSE_Disconnect);
1210 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1213 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1215 *retval = m_con->getPeerStat(peer_id,type);
1216 return *retval != -1;
1219 bool Server::getClientInfo(
1228 std::string* vers_string,
1229 std::string* lang_code
1232 *state = m_clients.getClientState(peer_id);
1234 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1241 *uptime = client->uptime();
1242 *ser_vers = client->serialization_version;
1243 *prot_vers = client->net_proto_version;
1245 *major = client->getMajor();
1246 *minor = client->getMinor();
1247 *patch = client->getPatch();
1248 *vers_string = client->getFull();
1249 *lang_code = client->getLangCode();
1256 void Server::handlePeerChanges()
1258 while(!m_peer_change_queue.empty())
1260 con::PeerChange c = m_peer_change_queue.front();
1261 m_peer_change_queue.pop();
1263 verbosestream<<"Server: Handling peer change: "
1264 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1269 case con::PEER_ADDED:
1270 m_clients.CreateClient(c.peer_id);
1273 case con::PEER_REMOVED:
1274 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1278 FATAL_ERROR("Invalid peer change event received!");
1284 void Server::printToConsoleOnly(const std::string &text)
1287 m_admin_chat->outgoing_queue.push_back(
1288 new ChatEventChat("", utf8_to_wide(text)));
1290 std::cout << text << std::endl;
1294 void Server::Send(NetworkPacket *pkt)
1296 Send(pkt->getPeerId(), pkt);
1299 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1301 m_clients.send(peer_id,
1302 clientCommandFactoryTable[pkt->getCommand()].channel,
1304 clientCommandFactoryTable[pkt->getCommand()].reliable);
1307 void Server::SendMovement(session_t peer_id)
1309 std::ostringstream os(std::ios_base::binary);
1311 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1313 pkt << g_settings->getFloat("movement_acceleration_default");
1314 pkt << g_settings->getFloat("movement_acceleration_air");
1315 pkt << g_settings->getFloat("movement_acceleration_fast");
1316 pkt << g_settings->getFloat("movement_speed_walk");
1317 pkt << g_settings->getFloat("movement_speed_crouch");
1318 pkt << g_settings->getFloat("movement_speed_fast");
1319 pkt << g_settings->getFloat("movement_speed_climb");
1320 pkt << g_settings->getFloat("movement_speed_jump");
1321 pkt << g_settings->getFloat("movement_liquid_fluidity");
1322 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1323 pkt << g_settings->getFloat("movement_liquid_sink");
1324 pkt << g_settings->getFloat("movement_gravity");
1329 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1331 if (playersao->isImmortal())
1334 session_t peer_id = playersao->getPeerID();
1335 bool is_alive = playersao->getHP() > 0;
1338 SendPlayerHP(peer_id);
1340 DiePlayer(peer_id, reason);
1343 void Server::SendHP(session_t peer_id, u16 hp)
1345 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1350 void Server::SendBreath(session_t peer_id, u16 breath)
1352 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1353 pkt << (u16) breath;
1357 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1358 const std::string &custom_reason, bool reconnect)
1360 assert(reason < SERVER_ACCESSDENIED_MAX);
1362 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1364 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1365 pkt << custom_reason;
1366 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1367 reason == SERVER_ACCESSDENIED_CRASH)
1368 pkt << custom_reason << (u8)reconnect;
1372 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1374 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1379 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1380 v3f camera_point_target)
1382 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1383 pkt << set_camera_point_target << camera_point_target;
1387 void Server::SendItemDef(session_t peer_id,
1388 IItemDefManager *itemdef, u16 protocol_version)
1390 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1394 u32 length of the next item
1395 zlib-compressed serialized ItemDefManager
1397 std::ostringstream tmp_os(std::ios::binary);
1398 itemdef->serialize(tmp_os, protocol_version);
1399 std::ostringstream tmp_os2(std::ios::binary);
1400 compressZlib(tmp_os.str(), tmp_os2);
1401 pkt.putLongString(tmp_os2.str());
1404 verbosestream << "Server: Sending item definitions to id(" << peer_id
1405 << "): size=" << pkt.getSize() << std::endl;
1410 void Server::SendNodeDef(session_t peer_id,
1411 const NodeDefManager *nodedef, u16 protocol_version)
1413 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1417 u32 length of the next item
1418 zlib-compressed serialized NodeDefManager
1420 std::ostringstream tmp_os(std::ios::binary);
1421 nodedef->serialize(tmp_os, protocol_version);
1422 std::ostringstream tmp_os2(std::ios::binary);
1423 compressZlib(tmp_os.str(), tmp_os2);
1425 pkt.putLongString(tmp_os2.str());
1428 verbosestream << "Server: Sending node definitions to id(" << peer_id
1429 << "): size=" << pkt.getSize() << std::endl;
1435 Non-static send methods
1438 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1440 RemotePlayer *player = sao->getPlayer();
1442 // Do not send new format to old clients
1443 incremental &= player->protocol_version >= 38;
1445 UpdateCrafting(player);
1451 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1453 std::ostringstream os(std::ios::binary);
1454 sao->getInventory()->serialize(os, incremental);
1455 sao->getInventory()->setModified(false);
1456 player->setModified(true);
1458 const std::string &s = os.str();
1459 pkt.putRawString(s.c_str(), s.size());
1463 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1465 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1467 u8 type = message.type;
1468 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1470 if (peer_id != PEER_ID_INEXISTENT) {
1471 RemotePlayer *player = m_env->getPlayer(peer_id);
1477 m_clients.sendToAll(&pkt);
1481 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1482 const std::string &formname)
1484 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1485 if (formspec.empty()){
1486 //the client should close the formspec
1487 //but make sure there wasn't another one open in meantime
1488 const auto it = m_formspec_state_data.find(peer_id);
1489 if (it != m_formspec_state_data.end() && it->second == formname) {
1490 m_formspec_state_data.erase(peer_id);
1492 pkt.putLongString("");
1494 m_formspec_state_data[peer_id] = formname;
1495 pkt.putLongString(formspec);
1502 // Spawns a particle on peer with peer_id
1503 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1504 const ParticleParameters &p)
1506 static thread_local const float radius =
1507 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1509 if (peer_id == PEER_ID_INEXISTENT) {
1510 std::vector<session_t> clients = m_clients.getClientIDs();
1511 const v3f pos = p.pos * BS;
1512 const float radius_sq = radius * radius;
1514 for (const session_t client_id : clients) {
1515 RemotePlayer *player = m_env->getPlayer(client_id);
1519 PlayerSAO *sao = player->getPlayerSAO();
1523 // Do not send to distant clients
1524 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1527 SendSpawnParticle(client_id, player->protocol_version, p);
1531 assert(protocol_version != 0);
1533 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1536 // NetworkPacket and iostreams are incompatible...
1537 std::ostringstream oss(std::ios_base::binary);
1538 p.serialize(oss, protocol_version);
1539 pkt.putRawString(oss.str());
1545 // Adds a ParticleSpawner on peer with peer_id
1546 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1547 const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1549 static thread_local const float radius =
1550 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1552 if (peer_id == PEER_ID_INEXISTENT) {
1553 std::vector<session_t> clients = m_clients.getClientIDs();
1554 const v3f pos = (p.minpos + p.maxpos) / 2.0f * BS;
1555 const float radius_sq = radius * radius;
1556 /* Don't send short-lived spawners to distant players.
1557 * This could be replaced with proper tracking at some point. */
1558 const bool distance_check = !attached_id && p.time <= 1.0f;
1560 for (const session_t client_id : clients) {
1561 RemotePlayer *player = m_env->getPlayer(client_id);
1565 if (distance_check) {
1566 PlayerSAO *sao = player->getPlayerSAO();
1569 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1573 SendAddParticleSpawner(client_id, player->protocol_version,
1574 p, attached_id, id);
1578 assert(protocol_version != 0);
1580 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1582 pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
1583 << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
1584 << p.minsize << p.maxsize << p.collisiondetection;
1586 pkt.putLongString(p.texture);
1588 pkt << id << p.vertical << p.collision_removal << attached_id;
1590 std::ostringstream os(std::ios_base::binary);
1591 p.animation.serialize(os, protocol_version);
1592 pkt.putRawString(os.str());
1594 pkt << p.glow << p.object_collision;
1595 pkt << p.node.param0 << p.node.param2 << p.node_tile;
1600 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1602 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1606 if (peer_id != PEER_ID_INEXISTENT)
1609 m_clients.sendToAll(&pkt);
1613 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1615 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1617 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1618 << form->text << form->number << form->item << form->dir
1619 << form->align << form->offset << form->world_pos << form->size
1620 << form->z_index << form->text2;
1625 void Server::SendHUDRemove(session_t peer_id, u32 id)
1627 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1632 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1634 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1635 pkt << id << (u8) stat;
1639 case HUD_STAT_SCALE:
1640 case HUD_STAT_ALIGN:
1641 case HUD_STAT_OFFSET:
1642 pkt << *(v2f *) value;
1646 case HUD_STAT_TEXT2:
1647 pkt << *(std::string *) value;
1649 case HUD_STAT_WORLD_POS:
1650 pkt << *(v3f *) value;
1653 pkt << *(v2s32 *) value;
1655 case HUD_STAT_NUMBER:
1659 pkt << *(u32 *) value;
1666 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1668 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1670 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1672 pkt << flags << mask;
1677 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1679 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1680 pkt << param << value;
1684 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1686 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1688 // Handle prior clients here
1689 if (m_clients.getProtocolVersion(peer_id) < 39) {
1690 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1692 for (const std::string& texture : params.textures)
1695 pkt << params.clouds;
1696 } else { // Handle current clients and future clients
1697 pkt << params.bgcolor << params.type
1698 << params.clouds << params.fog_sun_tint
1699 << params.fog_moon_tint << params.fog_tint_type;
1701 if (params.type == "skybox") {
1702 pkt << (u16) params.textures.size();
1703 for (const std::string &texture : params.textures)
1705 } else if (params.type == "regular") {
1706 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1707 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1708 << params.sky_color.night_sky << params.sky_color.night_horizon
1709 << params.sky_color.indoors;
1716 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1718 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1719 pkt << params.visible << params.texture
1720 << params.tonemap << params.sunrise
1721 << params.sunrise_visible << params.scale;
1725 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1727 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1729 pkt << params.visible << params.texture
1730 << params.tonemap << params.scale;
1734 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1736 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1738 pkt << params.visible << params.count
1739 << params.starcolor << params.scale;
1744 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1746 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1747 pkt << params.density << params.color_bright << params.color_ambient
1748 << params.height << params.thickness << params.speed;
1752 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1755 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1758 pkt << do_override << (u16) (ratio * 65535);
1763 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1765 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1766 pkt << time << time_speed;
1768 if (peer_id == PEER_ID_INEXISTENT) {
1769 m_clients.sendToAll(&pkt);
1776 void Server::SendPlayerHP(session_t peer_id)
1778 PlayerSAO *playersao = getPlayerSAO(peer_id);
1781 SendHP(peer_id, playersao->getHP());
1782 m_script->player_event(playersao,"health_changed");
1784 // Send to other clients
1785 playersao->sendPunchCommand();
1788 void Server::SendPlayerBreath(PlayerSAO *sao)
1792 m_script->player_event(sao, "breath_changed");
1793 SendBreath(sao->getPeerID(), sao->getBreath());
1796 void Server::SendMovePlayer(session_t peer_id)
1798 RemotePlayer *player = m_env->getPlayer(peer_id);
1800 PlayerSAO *sao = player->getPlayerSAO();
1803 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1804 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1807 v3f pos = sao->getBasePosition();
1808 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1809 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1810 << " pitch=" << sao->getLookPitch()
1811 << " yaw=" << sao->getRotation().Y
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(session_t peer_id, v2s32 animation_frames[4],
1829 f32 animation_speed)
1831 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1834 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1835 << animation_frames[3] << animation_speed;
1840 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1842 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1843 pkt << first << third;
1847 void Server::SendPlayerPrivileges(session_t peer_id)
1849 RemotePlayer *player = m_env->getPlayer(peer_id);
1851 if(player->getPeerId() == PEER_ID_INEXISTENT)
1854 std::set<std::string> privs;
1855 m_script->getAuth(player->getName(), NULL, &privs);
1857 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1858 pkt << (u16) privs.size();
1860 for (const std::string &priv : privs) {
1867 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1869 RemotePlayer *player = m_env->getPlayer(peer_id);
1871 if (player->getPeerId() == PEER_ID_INEXISTENT)
1874 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1875 pkt.putLongString(player->inventory_formspec);
1880 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1882 RemotePlayer *player = m_env->getPlayer(peer_id);
1884 if (player->getPeerId() == PEER_ID_INEXISTENT)
1887 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1888 pkt << player->formspec_prepend;
1892 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1894 // Radius inside which objects are active
1895 static thread_local const s16 radius =
1896 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
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 ?
1907 radius : player_transfer_dist;
1909 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1913 std::queue<u16> removed_objects, added_objects;
1914 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1915 client->m_known_objects, removed_objects);
1916 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1917 client->m_known_objects, added_objects);
1919 int removed_count = removed_objects.size();
1920 int added_count = added_objects.size();
1922 if (removed_objects.empty() && added_objects.empty())
1928 // Handle removed objects
1929 writeU16((u8*)buf, removed_objects.size());
1930 data.append(buf, 2);
1931 while (!removed_objects.empty()) {
1933 u16 id = removed_objects.front();
1934 ServerActiveObject* obj = m_env->getActiveObject(id);
1936 // Add to data buffer for sending
1937 writeU16((u8*)buf, id);
1938 data.append(buf, 2);
1940 // Remove from known objects
1941 client->m_known_objects.erase(id);
1943 if (obj && obj->m_known_by_count > 0)
1944 obj->m_known_by_count--;
1946 removed_objects.pop();
1949 // Handle added objects
1950 writeU16((u8*)buf, added_objects.size());
1951 data.append(buf, 2);
1952 while (!added_objects.empty()) {
1954 u16 id = added_objects.front();
1955 ServerActiveObject *obj = m_env->getActiveObject(id);
1956 added_objects.pop();
1959 warningstream << FUNCTION_NAME << ": NULL object id="
1960 << (int)id << std::endl;
1965 u8 type = obj->getSendType();
1967 // Add to data buffer for sending
1968 writeU16((u8*)buf, id);
1969 data.append(buf, 2);
1970 writeU8((u8*)buf, type);
1971 data.append(buf, 1);
1973 data.append(serializeLongString(
1974 obj->getClientInitializationData(client->net_proto_version)));
1976 // Add to known objects
1977 client->m_known_objects.insert(id);
1979 obj->m_known_by_count++;
1982 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
1983 pkt.putRawString(data.c_str(), data.size());
1986 verbosestream << "Server::SendActiveObjectRemoveAdd: "
1987 << removed_count << " removed, " << added_count << " added, "
1988 << "packet size is " << pkt.getSize() << std::endl;
1991 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1994 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1995 datas.size(), peer_id);
1997 pkt.putRawString(datas.c_str(), datas.size());
1999 m_clients.send(pkt.getPeerId(),
2000 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2004 void Server::SendCSMRestrictionFlags(session_t peer_id)
2006 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2007 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2008 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2012 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2014 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2019 inline s32 Server::nextSoundId()
2021 s32 ret = m_next_sound_id;
2022 if (m_next_sound_id == INT32_MAX)
2023 m_next_sound_id = 0; // signed overflow is undefined
2029 s32 Server::playSound(const SimpleSoundSpec &spec,
2030 const ServerSoundParams ¶ms, bool ephemeral)
2032 // Find out initial position of sound
2033 bool pos_exists = false;
2034 v3f pos = params.getPos(m_env, &pos_exists);
2035 // If position is not found while it should be, cancel sound
2036 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2039 // Filter destination clients
2040 std::vector<session_t> dst_clients;
2041 if (!params.to_player.empty()) {
2042 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2044 infostream<<"Server::playSound: Player \""<<params.to_player
2045 <<"\" not found"<<std::endl;
2048 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2049 infostream<<"Server::playSound: Player \""<<params.to_player
2050 <<"\" not connected"<<std::endl;
2053 dst_clients.push_back(player->getPeerId());
2055 std::vector<session_t> clients = m_clients.getClientIDs();
2057 for (const session_t client_id : clients) {
2058 RemotePlayer *player = m_env->getPlayer(client_id);
2061 if (!params.exclude_player.empty() &&
2062 params.exclude_player == player->getName())
2065 PlayerSAO *sao = player->getPlayerSAO();
2070 if(sao->getBasePosition().getDistanceFrom(pos) >
2071 params.max_hear_distance)
2074 dst_clients.push_back(client_id);
2078 if(dst_clients.empty())
2083 ServerPlayingSound *psound = nullptr;
2085 id = -1; // old clients will still use this, so pick a reserved ID
2088 // The sound will exist as a reference in m_playing_sounds
2089 m_playing_sounds[id] = ServerPlayingSound();
2090 psound = &m_playing_sounds[id];
2091 psound->params = params;
2092 psound->spec = spec;
2095 float gain = params.gain * spec.gain;
2096 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2097 pkt << id << spec.name << gain
2098 << (u8) params.type << pos << params.object
2099 << params.loop << params.fade << params.pitch
2102 bool as_reliable = !ephemeral;
2104 for (const u16 dst_client : dst_clients) {
2106 psound->clients.insert(dst_client);
2107 m_clients.send(dst_client, 0, &pkt, as_reliable);
2111 void Server::stopSound(s32 handle)
2113 // Get sound reference
2114 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2115 m_playing_sounds.find(handle);
2116 if (i == m_playing_sounds.end())
2118 ServerPlayingSound &psound = i->second;
2120 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2123 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2124 si != psound.clients.end(); ++si) {
2126 m_clients.send(*si, 0, &pkt, true);
2128 // Remove sound reference
2129 m_playing_sounds.erase(i);
2132 void Server::fadeSound(s32 handle, float step, float gain)
2134 // Get sound reference
2135 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2136 m_playing_sounds.find(handle);
2137 if (i == m_playing_sounds.end())
2140 ServerPlayingSound &psound = i->second;
2141 psound.params.gain = gain;
2143 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2144 pkt << handle << step << gain;
2146 // Backwards compability
2147 bool play_sound = gain > 0;
2148 ServerPlayingSound compat_psound = psound;
2149 compat_psound.clients.clear();
2151 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2152 compat_pkt << handle;
2154 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2155 it != psound.clients.end();) {
2156 if (m_clients.getProtocolVersion(*it) >= 32) {
2158 m_clients.send(*it, 0, &pkt, true);
2161 compat_psound.clients.insert(*it);
2163 m_clients.send(*it, 0, &compat_pkt, true);
2164 psound.clients.erase(it++);
2168 // Remove sound reference
2169 if (!play_sound || psound.clients.empty())
2170 m_playing_sounds.erase(i);
2172 if (play_sound && !compat_psound.clients.empty()) {
2173 // Play new sound volume on older clients
2174 playSound(compat_psound.spec, compat_psound.params);
2178 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2181 float maxd = far_d_nodes * BS;
2182 v3f p_f = intToFloat(p, BS);
2183 v3s16 block_pos = getNodeBlockPos(p);
2185 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2188 std::vector<session_t> clients = m_clients.getClientIDs();
2191 for (session_t client_id : clients) {
2192 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2196 RemotePlayer *player = m_env->getPlayer(client_id);
2197 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2199 // If player is far away, only set modified blocks not sent
2200 if (!client->isBlockSent(block_pos) || (sao &&
2201 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2203 far_players->emplace(client_id);
2205 client->SetBlockNotSent(block_pos);
2210 m_clients.send(client_id, 0, &pkt, true);
2216 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2217 float far_d_nodes, bool remove_metadata)
2219 float maxd = far_d_nodes * BS;
2220 v3f p_f = intToFloat(p, BS);
2221 v3s16 block_pos = getNodeBlockPos(p);
2223 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2224 pkt << p << n.param0 << n.param1 << n.param2
2225 << (u8) (remove_metadata ? 0 : 1);
2227 std::vector<session_t> clients = m_clients.getClientIDs();
2230 for (session_t client_id : clients) {
2231 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2235 RemotePlayer *player = m_env->getPlayer(client_id);
2236 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2238 // If player is far away, only set modified blocks not sent
2239 if (!client->isBlockSent(block_pos) || (sao &&
2240 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2242 far_players->emplace(client_id);
2244 client->SetBlockNotSent(block_pos);
2249 m_clients.send(client_id, 0, &pkt, true);
2255 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2257 float maxd = far_d_nodes * BS;
2258 NodeMetadataList meta_updates_list(false);
2259 std::vector<session_t> clients = m_clients.getClientIDs();
2263 for (session_t i : clients) {
2264 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2268 ServerActiveObject *player = m_env->getActiveObject(i);
2269 v3f player_pos = player ? player->getBasePosition() : v3f();
2271 for (const v3s16 &pos : meta_updates) {
2272 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2277 v3s16 block_pos = getNodeBlockPos(pos);
2278 if (!client->isBlockSent(block_pos) || (player &&
2279 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2280 client->SetBlockNotSent(block_pos);
2284 // Add the change to send list
2285 meta_updates_list.set(pos, meta);
2287 if (meta_updates_list.size() == 0)
2290 // Send the meta changes
2291 std::ostringstream os(std::ios::binary);
2292 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2293 std::ostringstream oss(std::ios::binary);
2294 compressZlib(os.str(), oss);
2296 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2297 pkt.putLongString(oss.str());
2298 m_clients.send(i, 0, &pkt, true);
2300 meta_updates_list.clear();
2306 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2307 u16 net_proto_version)
2310 Create a packet with the block in the right format
2313 std::ostringstream os(std::ios_base::binary);
2314 block->serialize(os, ver, false);
2315 block->serializeNetworkSpecific(os);
2316 std::string s = os.str();
2318 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2320 pkt << block->getPos();
2321 pkt.putRawString(s.c_str(), s.size());
2325 void Server::SendBlocks(float dtime)
2327 MutexAutoLock envlock(m_env_mutex);
2328 //TODO check if one big lock could be faster then multiple small ones
2330 std::vector<PrioritySortedBlockTransfer> queue;
2332 u32 total_sending = 0;
2335 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2337 std::vector<session_t> clients = m_clients.getClientIDs();
2340 for (const session_t client_id : clients) {
2341 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2346 total_sending += client->getSendingCount();
2347 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2353 // Lowest priority number comes first.
2354 // Lowest is most important.
2355 std::sort(queue.begin(), queue.end());
2359 // Maximal total count calculation
2360 // The per-client block sends is halved with the maximal online users
2361 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2362 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2364 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2365 Map &map = m_env->getMap();
2367 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2368 if (total_sending >= max_blocks_to_send)
2371 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2375 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2380 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2381 client->net_proto_version);
2383 client->SentBlock(block_to_send.pos);
2389 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2391 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2396 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2397 if (!client || client->isBlockSent(blockpos)) {
2401 SendBlockNoLock(peer_id, block, client->serialization_version,
2402 client->net_proto_version);
2408 bool Server::addMediaFile(const std::string &filename,
2409 const std::string &filepath, std::string *filedata_to,
2410 std::string *digest_to)
2412 // If name contains illegal characters, ignore the file
2413 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2414 infostream << "Server: ignoring illegal file name: \""
2415 << filename << "\"" << std::endl;
2418 // If name is not in a supported format, ignore it
2419 const char *supported_ext[] = {
2420 ".png", ".jpg", ".bmp", ".tga",
2421 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2423 ".x", ".b3d", ".md2", ".obj",
2424 // Custom translation file format
2428 if (removeStringEnd(filename, supported_ext).empty()) {
2429 infostream << "Server: ignoring unsupported file extension: \""
2430 << filename << "\"" << std::endl;
2433 // Ok, attempt to load the file and add to cache
2436 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2438 errorstream << "Server::addMediaFile(): Could not open \""
2439 << filename << "\" for reading" << std::endl;
2442 std::string filedata;
2446 fis.read(buf, sizeof(buf));
2447 std::streamsize len = fis.gcount();
2448 filedata.append(buf, len);
2457 errorstream << "Server::addMediaFile(): Failed to read \""
2458 << filename << "\"" << std::endl;
2460 } else if (filedata.empty()) {
2461 errorstream << "Server::addMediaFile(): Empty file \""
2462 << filepath << "\"" << std::endl;
2467 sha1.addBytes(filedata.c_str(), filedata.length());
2469 unsigned char *digest = sha1.getDigest();
2470 std::string sha1_base64 = base64_encode(digest, 20);
2471 std::string sha1_hex = hex_encode((char*) digest, 20);
2473 *digest_to = std::string((char*) digest, 20);
2477 m_media[filename] = MediaInfo(filepath, sha1_base64);
2478 verbosestream << "Server: " << sha1_hex << " is " << filename
2482 *filedata_to = std::move(filedata);
2486 void Server::fillMediaCache()
2488 infostream << "Server: Calculating media file checksums" << std::endl;
2490 // Collect all media file paths
2491 std::vector<std::string> paths;
2492 m_modmgr->getModsMediaPaths(paths);
2493 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2494 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2496 // Collect media file information from paths into cache
2497 for (const std::string &mediapath : paths) {
2498 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2499 for (const fs::DirListNode &dln : dirlist) {
2500 if (dln.dir) // Ignore dirs
2502 std::string filepath = mediapath;
2503 filepath.append(DIR_DELIM).append(dln.name);
2504 addMediaFile(dln.name, filepath);
2508 infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2511 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2514 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2517 std::string lang_suffix;
2518 lang_suffix.append(".").append(lang_code).append(".tr");
2519 for (const auto &i : m_media) {
2520 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2527 for (const auto &i : m_media) {
2528 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2530 pkt << i.first << i.second.sha1_digest;
2533 pkt << g_settings->get("remote_media");
2536 verbosestream << "Server: Announcing files to id(" << peer_id
2537 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2540 struct SendableMedia
2546 SendableMedia(const std::string &name_="", const std::string &path_="",
2547 const std::string &data_=""):
2554 void Server::sendRequestedMedia(session_t peer_id,
2555 const std::vector<std::string> &tosend)
2557 verbosestream<<"Server::sendRequestedMedia(): "
2558 <<"Sending files to client"<<std::endl;
2562 // Put 5kB in one bunch (this is not accurate)
2563 u32 bytes_per_bunch = 5000;
2565 std::vector< std::vector<SendableMedia> > file_bunches;
2566 file_bunches.emplace_back();
2568 u32 file_size_bunch_total = 0;
2570 for (const std::string &name : tosend) {
2571 if (m_media.find(name) == m_media.end()) {
2572 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2573 <<"unknown file \""<<(name)<<"\""<<std::endl;
2577 //TODO get path + name
2578 std::string tpath = m_media[name].path;
2581 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2583 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2584 <<tpath<<"\" for reading"<<std::endl;
2587 std::ostringstream tmp_os(std::ios_base::binary);
2591 fis.read(buf, 1024);
2592 std::streamsize len = fis.gcount();
2593 tmp_os.write(buf, len);
2594 file_size_bunch_total += len;
2603 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2604 <<name<<"\""<<std::endl;
2607 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2608 <<tname<<"\""<<std::endl;*/
2610 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2612 // Start next bunch if got enough data
2613 if(file_size_bunch_total >= bytes_per_bunch) {
2614 file_bunches.emplace_back();
2615 file_size_bunch_total = 0;
2620 /* Create and send packets */
2622 u16 num_bunches = file_bunches.size();
2623 for (u16 i = 0; i < num_bunches; i++) {
2626 u16 total number of texture bunches
2627 u16 index of this bunch
2628 u32 number of files in this bunch
2637 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2638 pkt << num_bunches << i << (u32) file_bunches[i].size();
2640 for (const SendableMedia &j : file_bunches[i]) {
2642 pkt.putLongString(j.data);
2645 verbosestream << "Server::sendRequestedMedia(): bunch "
2646 << i << "/" << num_bunches
2647 << " files=" << file_bunches[i].size()
2648 << " size=" << pkt.getSize() << std::endl;
2653 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2655 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2659 pkt << false; // Remove inventory
2661 pkt << true; // Update inventory
2663 // Serialization & NetworkPacket isn't a love story
2664 std::ostringstream os(std::ios_base::binary);
2665 inventory->serialize(os);
2666 inventory->setModified(false);
2668 const std::string &os_str = os.str();
2669 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2670 pkt.putRawString(os_str);
2673 if (peer_id == PEER_ID_INEXISTENT)
2674 m_clients.sendToAll(&pkt);
2679 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2681 // Lookup player name, to filter detached inventories just after
2682 std::string peer_name;
2683 if (peer_id != PEER_ID_INEXISTENT) {
2684 peer_name = getClient(peer_id, CS_Created)->getName();
2687 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2688 sendDetachedInventory(inv, name, peer_id);
2691 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2698 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2700 PlayerSAO *playersao = getPlayerSAO(peer_id);
2703 infostream << "Server::DiePlayer(): Player "
2704 << playersao->getPlayer()->getName()
2705 << " dies" << std::endl;
2707 playersao->setHP(0, reason);
2708 playersao->clearParentAttachment();
2710 // Trigger scripted stuff
2711 m_script->on_dieplayer(playersao, reason);
2713 SendPlayerHP(peer_id);
2714 SendDeathscreen(peer_id, false, v3f(0,0,0));
2717 void Server::RespawnPlayer(session_t peer_id)
2719 PlayerSAO *playersao = getPlayerSAO(peer_id);
2722 infostream << "Server::RespawnPlayer(): Player "
2723 << playersao->getPlayer()->getName()
2724 << " respawns" << std::endl;
2726 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2727 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2728 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2730 bool repositioned = m_script->on_respawnplayer(playersao);
2731 if (!repositioned) {
2732 // setPos will send the new position to client
2733 playersao->setPos(findSpawnPos());
2736 SendPlayerHP(peer_id);
2740 void Server::DenySudoAccess(session_t peer_id)
2742 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2747 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2748 const std::string &str_reason, bool reconnect)
2750 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2752 m_clients.event(peer_id, CSE_SetDenied);
2753 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
2817 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2818 ServerPlayingSound &psound = i->second;
2819 psound.clients.erase(peer_id);
2820 if (psound.clients.empty())
2821 m_playing_sounds.erase(i++);
2826 // clear formspec info so the next client can't abuse the current state
2827 m_formspec_state_data.erase(peer_id);
2829 RemotePlayer *player = m_env->getPlayer(peer_id);
2831 /* Run scripts and remove from environment */
2833 PlayerSAO *playersao = player->getPlayerSAO();
2836 playersao->clearChildAttachments();
2837 playersao->clearParentAttachment();
2839 // inform connected clients
2840 const std::string &player_name = player->getName();
2841 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2842 // (u16) 1 + std::string represents a vector serialization representation
2843 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2844 m_clients.sendToAll(¬ice);
2846 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2848 playersao->disconnected();
2855 if (player && reason != CDR_DENY) {
2856 std::ostringstream os(std::ios_base::binary);
2857 std::vector<session_t> clients = m_clients.getClientIDs();
2859 for (const session_t client_id : clients) {
2861 RemotePlayer *player = m_env->getPlayer(client_id);
2865 // Get name of player
2866 os << player->getName() << " ";
2869 std::string name = player->getName();
2870 actionstream << name << " "
2871 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2872 << " List of players: " << os.str() << std::endl;
2874 m_admin_chat->outgoing_queue.push_back(
2875 new ChatEventNick(CET_NICK_REMOVE, name));
2879 MutexAutoLock env_lock(m_env_mutex);
2880 m_clients.DeleteClient(peer_id);
2884 // Send leave chat message to all remaining clients
2885 if (!message.empty()) {
2886 SendChatMessage(PEER_ID_INEXISTENT,
2887 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2891 void Server::UpdateCrafting(RemotePlayer *player)
2893 InventoryList *clist = player->inventory.getList("craft");
2894 if (!clist || clist->getSize() == 0)
2897 if (!clist->checkModified())
2900 // Get a preview for crafting
2902 InventoryLocation loc;
2903 loc.setPlayer(player->getName());
2904 std::vector<ItemStack> output_replacements;
2905 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2906 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2909 InventoryList *plist = player->inventory.getList("craftpreview");
2910 if (plist && plist->getSize() >= 1) {
2911 // Put the new preview in
2912 plist->changeItem(0, preview);
2916 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2918 if (evt->type == CET_NICK_ADD) {
2919 // The terminal informed us of its nick choice
2920 m_admin_nick = ((ChatEventNick *)evt)->nick;
2921 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2922 errorstream << "You haven't set up an account." << std::endl
2923 << "Please log in using the client as '"
2924 << m_admin_nick << "' with a secure password." << std::endl
2925 << "Until then, you can't execute admin tasks via the console," << std::endl
2926 << "and everybody can claim the user account instead of you," << std::endl
2927 << "giving them full control over this server." << std::endl;
2930 assert(evt->type == CET_CHAT);
2931 handleAdminChat((ChatEventChat *)evt);
2935 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2936 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2938 // If something goes wrong, this player is to blame
2939 RollbackScopeActor rollback_scope(m_rollback,
2940 std::string("player:") + name);
2942 if (g_settings->getBool("strip_color_codes"))
2943 wmessage = unescape_enriched(wmessage);
2946 switch (player->canSendChatMessage()) {
2947 case RPLAYER_CHATRESULT_FLOODING: {
2948 std::wstringstream ws;
2949 ws << L"You cannot send more messages. You are limited to "
2950 << g_settings->getFloat("chat_message_limit_per_10sec")
2951 << L" messages per 10 seconds.";
2954 case RPLAYER_CHATRESULT_KICK:
2955 DenyAccess_Legacy(player->getPeerId(),
2956 L"You have been kicked due to message flooding.");
2958 case RPLAYER_CHATRESULT_OK:
2961 FATAL_ERROR("Unhandled chat filtering result found.");
2965 if (m_max_chatmessage_length > 0
2966 && wmessage.length() > m_max_chatmessage_length) {
2967 return L"Your message exceed the maximum chat message limit set on the server. "
2968 L"It was refused. Send a shorter message";
2971 auto message = trim(wide_to_utf8(wmessage));
2972 if (message.find_first_of("\n\r") != std::wstring::npos) {
2973 return L"New lines are not permitted in chat messages";
2976 // Run script hook, exit if script ate the chat message
2977 if (m_script->on_chat_message(name, message))
2982 // Whether to send line to the player that sent the message, or to all players
2983 bool broadcast_line = true;
2985 if (check_shout_priv && !checkPriv(name, "shout")) {
2986 line += L"-!- You don't have permission to shout.";
2987 broadcast_line = false;
2990 Workaround for fixing chat on Android. Lua doesn't handle
2991 the Cyrillic alphabet and some characters on older Android devices
2994 line += L"<" + wname + L"> " + wmessage;
2996 line += narrow_to_wide(m_script->formatChatMessage(name,
2997 wide_to_narrow(wmessage)));
3002 Tell calling method to send the message to sender
3004 if (!broadcast_line)
3008 Send the message to others
3010 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
3012 std::vector<session_t> clients = m_clients.getClientIDs();
3015 Send the message back to the inital sender
3016 if they are using protocol version >= 29
3019 session_t peer_id_to_avoid_sending =
3020 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
3022 if (player && player->protocol_version >= 29)
3023 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
3025 for (u16 cid : clients) {
3026 if (cid != peer_id_to_avoid_sending)
3027 SendChatMessage(cid, ChatMessage(line));
3032 void Server::handleAdminChat(const ChatEventChat *evt)
3034 std::string name = evt->nick;
3035 std::wstring wname = utf8_to_wide(name);
3036 std::wstring wmessage = evt->evt_msg;
3038 std::wstring answer = handleChat(name, wname, wmessage);
3040 // If asked to send answer to sender
3041 if (!answer.empty()) {
3042 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3046 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3048 RemoteClient *client = getClientNoEx(peer_id,state_min);
3050 throw ClientNotFoundException("Client not found");
3054 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3056 return m_clients.getClientNoEx(peer_id, state_min);
3059 std::string Server::getPlayerName(session_t peer_id)
3061 RemotePlayer *player = m_env->getPlayer(peer_id);
3063 return "[id="+itos(peer_id)+"]";
3064 return player->getName();
3067 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3069 RemotePlayer *player = m_env->getPlayer(peer_id);
3072 return player->getPlayerSAO();
3075 std::wstring Server::getStatusString()
3077 std::wostringstream os(std::ios_base::binary);
3078 os << L"# Server: ";
3080 os << L"version=" << narrow_to_wide(g_version_string);
3082 os << L", uptime=" << m_uptime_counter->get();
3084 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3086 // Information about clients
3088 os << L", clients={";
3090 std::vector<session_t> clients = m_clients.getClientIDs();
3091 for (session_t client_id : clients) {
3092 RemotePlayer *player = m_env->getPlayer(client_id);
3094 // Get name of player
3095 std::wstring name = L"unknown";
3097 name = narrow_to_wide(player->getName());
3099 // Add name to information string
3110 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3111 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3113 if (!g_settings->get("motd").empty())
3114 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3119 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3121 std::set<std::string> privs;
3122 m_script->getAuth(name, NULL, &privs);
3126 bool Server::checkPriv(const std::string &name, const std::string &priv)
3128 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3129 return (privs.count(priv) != 0);
3132 void Server::reportPrivsModified(const std::string &name)
3135 std::vector<session_t> clients = m_clients.getClientIDs();
3136 for (const session_t client_id : clients) {
3137 RemotePlayer *player = m_env->getPlayer(client_id);
3138 reportPrivsModified(player->getName());
3141 RemotePlayer *player = m_env->getPlayer(name.c_str());
3144 SendPlayerPrivileges(player->getPeerId());
3145 PlayerSAO *sao = player->getPlayerSAO();
3148 sao->updatePrivileges(
3149 getPlayerEffectivePrivs(name),
3154 void Server::reportInventoryFormspecModified(const std::string &name)
3156 RemotePlayer *player = m_env->getPlayer(name.c_str());
3159 SendPlayerInventoryFormspec(player->getPeerId());
3162 void Server::reportFormspecPrependModified(const std::string &name)
3164 RemotePlayer *player = m_env->getPlayer(name.c_str());
3167 SendPlayerFormspecPrepend(player->getPeerId());
3170 void Server::setIpBanned(const std::string &ip, const std::string &name)
3172 m_banmanager->add(ip, name);
3175 void Server::unsetIpBanned(const std::string &ip_or_name)
3177 m_banmanager->remove(ip_or_name);
3180 std::string Server::getBanDescription(const std::string &ip_or_name)
3182 return m_banmanager->getBanDescription(ip_or_name);
3185 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3187 // m_env will be NULL if the server is initializing
3191 if (m_admin_nick == name && !m_admin_nick.empty()) {
3192 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3195 RemotePlayer *player = m_env->getPlayer(name);
3200 if (player->getPeerId() == PEER_ID_INEXISTENT)
3203 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3206 bool Server::showFormspec(const char *playername, const std::string &formspec,
3207 const std::string &formname)
3209 // m_env will be NULL if the server is initializing
3213 RemotePlayer *player = m_env->getPlayer(playername);
3217 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3221 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3226 u32 id = player->addHud(form);
3228 SendHUDAdd(player->getPeerId(), id, form);
3233 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3237 HudElement* todel = player->removeHud(id);
3244 SendHUDRemove(player->getPeerId(), id);
3248 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3253 SendHUDChange(player->getPeerId(), id, stat, data);
3257 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3262 SendHUDSetFlags(player->getPeerId(), flags, mask);
3263 player->hud_flags &= ~mask;
3264 player->hud_flags |= flags;
3266 PlayerSAO* playersao = player->getPlayerSAO();
3271 m_script->player_event(playersao, "hud_changed");
3275 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3280 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3283 player->setHotbarItemcount(hotbar_itemcount);
3284 std::ostringstream os(std::ios::binary);
3285 writeS32(os, hotbar_itemcount);
3286 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3290 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3295 player->setHotbarImage(name);
3296 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3299 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3304 player->setHotbarSelectedImage(name);
3305 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3308 Address Server::getPeerAddress(session_t peer_id)
3310 return m_con->GetPeerAddress(peer_id);
3313 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3314 v2s32 animation_frames[4], f32 frame_speed)
3316 sanity_check(player);
3317 player->setLocalAnimations(animation_frames, frame_speed);
3318 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3321 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3323 sanity_check(player);
3324 player->eye_offset_first = first;
3325 player->eye_offset_third = third;
3326 SendEyeOffset(player->getPeerId(), first, third);
3329 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3331 sanity_check(player);
3332 player->setSky(params);
3333 SendSetSky(player->getPeerId(), params);
3336 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3338 sanity_check(player);
3339 player->setSun(params);
3340 SendSetSun(player->getPeerId(), params);
3343 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3345 sanity_check(player);
3346 player->setMoon(params);
3347 SendSetMoon(player->getPeerId(), params);
3350 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3352 sanity_check(player);
3353 player->setStars(params);
3354 SendSetStars(player->getPeerId(), params);
3357 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3359 sanity_check(player);
3360 player->setCloudParams(params);
3361 SendCloudParams(player->getPeerId(), params);
3364 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3367 sanity_check(player);
3368 player->overrideDayNightRatio(do_override, ratio);
3369 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3372 void Server::notifyPlayers(const std::wstring &msg)
3374 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3377 void Server::spawnParticle(const std::string &playername,
3378 const ParticleParameters &p)
3380 // m_env will be NULL if the server is initializing
3384 session_t peer_id = PEER_ID_INEXISTENT;
3386 if (!playername.empty()) {
3387 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3390 peer_id = player->getPeerId();
3391 proto_ver = player->protocol_version;
3394 SendSpawnParticle(peer_id, proto_ver, p);
3397 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3398 ServerActiveObject *attached, const std::string &playername)
3400 // m_env will be NULL if the server is initializing
3404 session_t peer_id = PEER_ID_INEXISTENT;
3406 if (!playername.empty()) {
3407 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3410 peer_id = player->getPeerId();
3411 proto_ver = player->protocol_version;
3414 u16 attached_id = attached ? attached->getId() : 0;
3417 if (attached_id == 0)
3418 id = m_env->addParticleSpawner(p.time);
3420 id = m_env->addParticleSpawner(p.time, attached_id);
3422 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3426 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3428 // m_env will be NULL if the server is initializing
3430 throw ServerError("Can't delete particle spawners during initialisation!");
3432 session_t peer_id = PEER_ID_INEXISTENT;
3433 if (!playername.empty()) {
3434 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3437 peer_id = player->getPeerId();
3440 m_env->deleteParticleSpawner(id);
3441 SendDeleteParticleSpawner(peer_id, id);
3444 bool Server::dynamicAddMedia(const std::string &filepath)
3446 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3447 if (m_media.find(filename) != m_media.end()) {
3448 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3449 << "\" already exists in media cache" << std::endl;
3453 // Load the file and add it to our media cache
3454 std::string filedata, raw_hash;
3455 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3459 // Push file to existing clients
3460 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3461 pkt << raw_hash << filename << (bool) true;
3462 pkt.putLongString(filedata);
3464 auto client_ids = m_clients.getClientIDs(CS_DefinitionsSent);
3465 for (session_t client_id : client_ids) {
3467 The network layer only guarantees ordered delivery inside a channel.
3468 Since the very next packet could be one that uses the media, we have
3469 to push the media over ALL channels to ensure it is processed before
3471 In practice this means we have to send it twice:
3473 - channel 0 (everything else: e.g. play_sound, object messages)
3475 m_clients.send(client_id, 1, &pkt, true);
3476 m_clients.send(client_id, 0, &pkt, true);
3482 // actions: time-reversed list
3483 // Return value: success/failure
3484 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3485 std::list<std::string> *log)
3487 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3488 ServerMap *map = (ServerMap*)(&m_env->getMap());
3490 // Fail if no actions to handle
3491 if (actions.empty()) {
3493 log->push_back("Nothing to do.");
3500 for (const RollbackAction &action : actions) {
3502 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3505 std::ostringstream os;
3506 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3507 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3509 log->push_back(os.str());
3511 std::ostringstream os;
3512 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3513 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3515 log->push_back(os.str());
3519 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3520 <<" failed"<<std::endl;
3522 // Call it done if less than half failed
3523 return num_failed <= num_tried/2;
3526 // IGameDef interface
3528 IItemDefManager *Server::getItemDefManager()
3533 const NodeDefManager *Server::getNodeDefManager()
3538 ICraftDefManager *Server::getCraftDefManager()
3543 u16 Server::allocateUnknownNodeId(const std::string &name)
3545 return m_nodedef->allocateDummy(name);
3548 IWritableItemDefManager *Server::getWritableItemDefManager()
3553 NodeDefManager *Server::getWritableNodeDefManager()
3558 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3563 const std::vector<ModSpec> & Server::getMods() const
3565 return m_modmgr->getMods();
3568 const ModSpec *Server::getModSpec(const std::string &modname) const
3570 return m_modmgr->getModSpec(modname);
3573 void Server::getModNames(std::vector<std::string> &modlist)
3575 m_modmgr->getModNames(modlist);
3578 std::string Server::getBuiltinLuaPath()
3580 return porting::path_share + DIR_DELIM + "builtin";
3583 std::string Server::getModStoragePath() const
3585 return m_path_world + DIR_DELIM + "mod_storage";
3588 v3f Server::findSpawnPos()
3590 ServerMap &map = m_env->getServerMap();
3592 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3593 return nodeposf * BS;
3595 bool is_good = false;
3596 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3597 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3599 // Try to find a good place a few times
3600 for (s32 i = 0; i < 4000 && !is_good; i++) {
3601 s32 range = MYMIN(1 + i, range_max);
3602 // We're going to try to throw the player to this position
3603 v2s16 nodepos2d = v2s16(
3604 -range + (myrand() % (range * 2)),
3605 -range + (myrand() % (range * 2)));
3606 // Get spawn level at point
3607 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3608 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3609 // signify an unsuitable spawn position, or if outside limits.
3610 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3611 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3614 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3615 // Consecutive empty nodes
3618 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3619 // avoid obstructions in already-generated mapblocks.
3620 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3621 // no obstructions, but mapgen decorations are generated after spawn so
3622 // the player may end up inside one.
3623 for (s32 i = 0; i < 8; i++) {
3624 v3s16 blockpos = getNodeBlockPos(nodepos);
3625 map.emergeBlock(blockpos, true);
3626 content_t c = map.getNode(nodepos).getContent();
3628 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3629 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3630 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3632 if (air_count >= 2) {
3633 // Spawn in lower empty node
3635 nodeposf = intToFloat(nodepos, BS);
3636 // Don't spawn the player outside map boundaries
3637 if (objectpos_over_limit(nodeposf))
3638 // Exit this loop, positions above are probably over limit
3641 // Good position found, cause an exit from main loop
3655 // No suitable spawn point found, return fallback 0,0,0
3656 return v3f(0.0f, 0.0f, 0.0f);
3659 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3661 if (delay == 0.0f) {
3662 // No delay, shutdown immediately
3663 m_shutdown_state.is_requested = true;
3664 // only print to the infostream, a chat message saying
3665 // "Server Shutting Down" is sent when the server destructs.
3666 infostream << "*** Immediate Server shutdown requested." << std::endl;
3667 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3668 // Negative delay, cancel shutdown if requested
3669 m_shutdown_state.reset();
3670 std::wstringstream ws;
3672 ws << L"*** Server shutdown canceled.";
3674 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3675 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3676 // m_shutdown_* are already handled, skip.
3678 } else if (delay > 0.0f) {
3679 // Positive delay, tell the clients when the server will shut down
3680 std::wstringstream ws;
3682 ws << L"*** Server shutting down in "
3683 << duration_to_string(myround(delay)).c_str()
3686 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3687 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3690 m_shutdown_state.trigger(delay, msg, reconnect);
3693 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3696 Try to get an existing player
3698 RemotePlayer *player = m_env->getPlayer(name);
3700 // If player is already connected, cancel
3701 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3702 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3707 If player with the wanted peer_id already exists, cancel.
3709 if (m_env->getPlayer(peer_id)) {
3710 infostream<<"emergePlayer(): Player with wrong name but same"
3711 " peer_id already exists"<<std::endl;
3716 player = new RemotePlayer(name, idef());
3719 bool newplayer = false;
3722 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3724 // Complete init with server parts
3725 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3726 player->protocol_version = proto_version;
3730 m_script->on_newplayer(playersao);
3736 bool Server::registerModStorage(ModMetadata *storage)
3738 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3739 errorstream << "Unable to register same mod storage twice. Storage name: "
3740 << storage->getModName() << std::endl;
3744 m_mod_storages[storage->getModName()] = storage;
3748 void Server::unregisterModStorage(const std::string &name)
3750 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3751 if (it != m_mod_storages.end()) {
3752 // Save unconditionaly on unregistration
3753 it->second->save(getModStoragePath());
3754 m_mod_storages.erase(name);
3758 void dedicated_server_loop(Server &server, bool &kill)
3760 verbosestream<<"dedicated_server_loop()"<<std::endl;
3762 IntervalLimiter m_profiler_interval;
3764 static thread_local const float steplen =
3765 g_settings->getFloat("dedicated_server_step");
3766 static thread_local const float profiler_print_interval =
3767 g_settings->getFloat("profiler_print_interval");
3770 * The dedicated server loop only does time-keeping (in Server::step) and
3771 * provides a way to main.cpp to kill the server externally (bool &kill).
3775 // This is kind of a hack but can be done like this
3776 // because server.step() is very light
3777 sleep_ms((int)(steplen*1000.0));
3778 server.step(steplen);
3780 if (server.isShutdownRequested() || kill)
3786 if (profiler_print_interval != 0) {
3787 if(m_profiler_interval.step(steplen, profiler_print_interval))
3789 infostream<<"Profiler:"<<std::endl;
3790 g_profiler->print(infostream);
3791 g_profiler->clear();
3796 infostream << "Dedicated server quitting" << std::endl;
3798 if (g_settings->getBool("server_announce"))
3799 ServerList::sendAnnounce(ServerList::AA_DELETE,
3800 server.m_bind_addr.getPort());
3809 bool Server::joinModChannel(const std::string &channel)
3811 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3812 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3815 bool Server::leaveModChannel(const std::string &channel)
3817 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3820 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3822 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3825 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3829 ModChannel* Server::getModChannel(const std::string &channel)
3831 return m_modchannel_mgr->getModChannel(channel);
3834 void Server::broadcastModChannelMessage(const std::string &channel,
3835 const std::string &message, session_t from_peer)
3837 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3841 if (message.size() > STRING_MAX_LEN) {
3842 warningstream << "ModChannel message too long, dropping before sending "
3843 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3844 << channel << ")" << std::endl;
3849 if (from_peer != PEER_ID_SERVER) {
3850 sender = getPlayerName(from_peer);
3853 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3854 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3855 resp_pkt << channel << sender << message;
3856 for (session_t peer_id : peers) {
3858 if (peer_id == from_peer)
3861 Send(peer_id, &resp_pkt);
3864 if (from_peer != PEER_ID_SERVER) {
3865 m_script->on_modchannel_message(channel, sender, message);
3869 void Server::loadTranslationLanguage(const std::string &lang_code)
3871 if (g_server_translations->count(lang_code))
3872 return; // Already loaded
3874 std::string suffix = "." + lang_code + ".tr";
3875 for (const auto &i : m_media) {
3876 if (str_ends_with(i.first, suffix)) {
3877 std::ifstream t(i.second.path);
3878 std::string data((std::istreambuf_iterator<char>(t)),
3879 std::istreambuf_iterator<char>());
3881 (*g_server_translations)[lang_code].loadTranslation(data);