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::SendRedirect(session_t peer_id, const std::string address, u16 port)
1381 NetworkPacket pkt(TOCLIENT_REDIRECT, 0, peer_id);
1382 pkt << address << port;
1386 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1387 v3f camera_point_target)
1389 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1390 pkt << set_camera_point_target << camera_point_target;
1394 void Server::SendItemDef(session_t peer_id,
1395 IItemDefManager *itemdef, u16 protocol_version)
1397 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1401 u32 length of the next item
1402 zlib-compressed serialized ItemDefManager
1404 std::ostringstream tmp_os(std::ios::binary);
1405 itemdef->serialize(tmp_os, protocol_version);
1406 std::ostringstream tmp_os2(std::ios::binary);
1407 compressZlib(tmp_os.str(), tmp_os2);
1408 pkt.putLongString(tmp_os2.str());
1411 verbosestream << "Server: Sending item definitions to id(" << peer_id
1412 << "): size=" << pkt.getSize() << std::endl;
1417 void Server::SendNodeDef(session_t peer_id,
1418 const NodeDefManager *nodedef, u16 protocol_version)
1420 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1424 u32 length of the next item
1425 zlib-compressed serialized NodeDefManager
1427 std::ostringstream tmp_os(std::ios::binary);
1428 nodedef->serialize(tmp_os, protocol_version);
1429 std::ostringstream tmp_os2(std::ios::binary);
1430 compressZlib(tmp_os.str(), tmp_os2);
1432 pkt.putLongString(tmp_os2.str());
1435 verbosestream << "Server: Sending node definitions to id(" << peer_id
1436 << "): size=" << pkt.getSize() << std::endl;
1442 Non-static send methods
1445 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1447 RemotePlayer *player = sao->getPlayer();
1449 // Do not send new format to old clients
1450 incremental &= player->protocol_version >= 38;
1452 UpdateCrafting(player);
1458 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1460 std::ostringstream os(std::ios::binary);
1461 sao->getInventory()->serialize(os, incremental);
1462 sao->getInventory()->setModified(false);
1463 player->setModified(true);
1465 const std::string &s = os.str();
1466 pkt.putRawString(s.c_str(), s.size());
1470 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1472 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1474 u8 type = message.type;
1475 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1477 if (peer_id != PEER_ID_INEXISTENT) {
1478 RemotePlayer *player = m_env->getPlayer(peer_id);
1484 m_clients.sendToAll(&pkt);
1488 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1489 const std::string &formname)
1491 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1492 if (formspec.empty()){
1493 //the client should close the formspec
1494 //but make sure there wasn't another one open in meantime
1495 const auto it = m_formspec_state_data.find(peer_id);
1496 if (it != m_formspec_state_data.end() && it->second == formname) {
1497 m_formspec_state_data.erase(peer_id);
1499 pkt.putLongString("");
1501 m_formspec_state_data[peer_id] = formname;
1502 pkt.putLongString(formspec);
1509 // Spawns a particle on peer with peer_id
1510 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1511 const ParticleParameters &p)
1513 static thread_local const float radius =
1514 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1516 if (peer_id == PEER_ID_INEXISTENT) {
1517 std::vector<session_t> clients = m_clients.getClientIDs();
1518 const v3f pos = p.pos * BS;
1519 const float radius_sq = radius * radius;
1521 for (const session_t client_id : clients) {
1522 RemotePlayer *player = m_env->getPlayer(client_id);
1526 PlayerSAO *sao = player->getPlayerSAO();
1530 // Do not send to distant clients
1531 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1534 SendSpawnParticle(client_id, player->protocol_version, p);
1538 assert(protocol_version != 0);
1540 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1543 // NetworkPacket and iostreams are incompatible...
1544 std::ostringstream oss(std::ios_base::binary);
1545 p.serialize(oss, protocol_version);
1546 pkt.putRawString(oss.str());
1552 // Adds a ParticleSpawner on peer with peer_id
1553 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1554 const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
1556 static thread_local const float radius =
1557 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1559 if (peer_id == PEER_ID_INEXISTENT) {
1560 std::vector<session_t> clients = m_clients.getClientIDs();
1561 const v3f pos = (p.minpos + p.maxpos) / 2.0f * BS;
1562 const float radius_sq = radius * radius;
1563 /* Don't send short-lived spawners to distant players.
1564 * This could be replaced with proper tracking at some point. */
1565 const bool distance_check = !attached_id && p.time <= 1.0f;
1567 for (const session_t client_id : clients) {
1568 RemotePlayer *player = m_env->getPlayer(client_id);
1572 if (distance_check) {
1573 PlayerSAO *sao = player->getPlayerSAO();
1576 if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
1580 SendAddParticleSpawner(client_id, player->protocol_version,
1581 p, attached_id, id);
1585 assert(protocol_version != 0);
1587 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
1589 pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
1590 << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
1591 << p.minsize << p.maxsize << p.collisiondetection;
1593 pkt.putLongString(p.texture);
1595 pkt << id << p.vertical << p.collision_removal << attached_id;
1597 std::ostringstream os(std::ios_base::binary);
1598 p.animation.serialize(os, protocol_version);
1599 pkt.putRawString(os.str());
1601 pkt << p.glow << p.object_collision;
1602 pkt << p.node.param0 << p.node.param2 << p.node_tile;
1607 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1609 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1613 if (peer_id != PEER_ID_INEXISTENT)
1616 m_clients.sendToAll(&pkt);
1620 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1622 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1624 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1625 << form->text << form->number << form->item << form->dir
1626 << form->align << form->offset << form->world_pos << form->size
1627 << form->z_index << form->text2;
1632 void Server::SendHUDRemove(session_t peer_id, u32 id)
1634 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1639 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1641 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1642 pkt << id << (u8) stat;
1646 case HUD_STAT_SCALE:
1647 case HUD_STAT_ALIGN:
1648 case HUD_STAT_OFFSET:
1649 pkt << *(v2f *) value;
1653 case HUD_STAT_TEXT2:
1654 pkt << *(std::string *) value;
1656 case HUD_STAT_WORLD_POS:
1657 pkt << *(v3f *) value;
1660 pkt << *(v2s32 *) value;
1662 case HUD_STAT_NUMBER:
1666 pkt << *(u32 *) value;
1673 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1675 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1677 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1679 pkt << flags << mask;
1684 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1686 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1687 pkt << param << value;
1691 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1693 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1695 // Handle prior clients here
1696 if (m_clients.getProtocolVersion(peer_id) < 39) {
1697 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1699 for (const std::string& texture : params.textures)
1702 pkt << params.clouds;
1703 } else { // Handle current clients and future clients
1704 pkt << params.bgcolor << params.type
1705 << params.clouds << params.fog_sun_tint
1706 << params.fog_moon_tint << params.fog_tint_type;
1708 if (params.type == "skybox") {
1709 pkt << (u16) params.textures.size();
1710 for (const std::string &texture : params.textures)
1712 } else if (params.type == "regular") {
1713 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1714 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1715 << params.sky_color.night_sky << params.sky_color.night_horizon
1716 << params.sky_color.indoors;
1723 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1725 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1726 pkt << params.visible << params.texture
1727 << params.tonemap << params.sunrise
1728 << params.sunrise_visible << params.scale;
1732 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1734 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1736 pkt << params.visible << params.texture
1737 << params.tonemap << params.scale;
1741 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1743 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1745 pkt << params.visible << params.count
1746 << params.starcolor << params.scale;
1751 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1753 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1754 pkt << params.density << params.color_bright << params.color_ambient
1755 << params.height << params.thickness << params.speed;
1759 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1762 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1765 pkt << do_override << (u16) (ratio * 65535);
1770 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1772 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1773 pkt << time << time_speed;
1775 if (peer_id == PEER_ID_INEXISTENT) {
1776 m_clients.sendToAll(&pkt);
1783 void Server::SendPlayerHP(session_t peer_id)
1785 PlayerSAO *playersao = getPlayerSAO(peer_id);
1788 SendHP(peer_id, playersao->getHP());
1789 m_script->player_event(playersao,"health_changed");
1791 // Send to other clients
1792 playersao->sendPunchCommand();
1795 void Server::SendPlayerBreath(PlayerSAO *sao)
1799 m_script->player_event(sao, "breath_changed");
1800 SendBreath(sao->getPeerID(), sao->getBreath());
1803 void Server::SendMovePlayer(session_t peer_id)
1805 RemotePlayer *player = m_env->getPlayer(peer_id);
1807 PlayerSAO *sao = player->getPlayerSAO();
1810 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1811 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1814 v3f pos = sao->getBasePosition();
1815 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1816 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1817 << " pitch=" << sao->getLookPitch()
1818 << " yaw=" << sao->getRotation().Y
1825 void Server::SendPlayerFov(session_t peer_id)
1827 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1829 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1830 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1835 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1836 f32 animation_speed)
1838 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1841 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1842 << animation_frames[3] << animation_speed;
1847 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1849 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1850 pkt << first << third;
1854 void Server::SendPlayerPrivileges(session_t peer_id)
1856 RemotePlayer *player = m_env->getPlayer(peer_id);
1858 if(player->getPeerId() == PEER_ID_INEXISTENT)
1861 std::set<std::string> privs;
1862 m_script->getAuth(player->getName(), NULL, &privs);
1864 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1865 pkt << (u16) privs.size();
1867 for (const std::string &priv : privs) {
1874 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1876 RemotePlayer *player = m_env->getPlayer(peer_id);
1878 if (player->getPeerId() == PEER_ID_INEXISTENT)
1881 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1882 pkt.putLongString(player->inventory_formspec);
1887 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1889 RemotePlayer *player = m_env->getPlayer(peer_id);
1891 if (player->getPeerId() == PEER_ID_INEXISTENT)
1894 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1895 pkt << player->formspec_prepend;
1899 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1901 // Radius inside which objects are active
1902 static thread_local const s16 radius =
1903 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1905 // Radius inside which players are active
1906 static thread_local const bool is_transfer_limited =
1907 g_settings->exists("unlimited_player_transfer_distance") &&
1908 !g_settings->getBool("unlimited_player_transfer_distance");
1910 static thread_local const s16 player_transfer_dist =
1911 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1913 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1914 radius : player_transfer_dist;
1916 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1920 std::queue<u16> removed_objects, added_objects;
1921 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1922 client->m_known_objects, removed_objects);
1923 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1924 client->m_known_objects, added_objects);
1926 int removed_count = removed_objects.size();
1927 int added_count = added_objects.size();
1929 if (removed_objects.empty() && added_objects.empty())
1935 // Handle removed objects
1936 writeU16((u8*)buf, removed_objects.size());
1937 data.append(buf, 2);
1938 while (!removed_objects.empty()) {
1940 u16 id = removed_objects.front();
1941 ServerActiveObject* obj = m_env->getActiveObject(id);
1943 // Add to data buffer for sending
1944 writeU16((u8*)buf, id);
1945 data.append(buf, 2);
1947 // Remove from known objects
1948 client->m_known_objects.erase(id);
1950 if (obj && obj->m_known_by_count > 0)
1951 obj->m_known_by_count--;
1953 removed_objects.pop();
1956 // Handle added objects
1957 writeU16((u8*)buf, added_objects.size());
1958 data.append(buf, 2);
1959 while (!added_objects.empty()) {
1961 u16 id = added_objects.front();
1962 ServerActiveObject *obj = m_env->getActiveObject(id);
1963 added_objects.pop();
1966 warningstream << FUNCTION_NAME << ": NULL object id="
1967 << (int)id << std::endl;
1972 u8 type = obj->getSendType();
1974 // Add to data buffer for sending
1975 writeU16((u8*)buf, id);
1976 data.append(buf, 2);
1977 writeU8((u8*)buf, type);
1978 data.append(buf, 1);
1980 data.append(serializeLongString(
1981 obj->getClientInitializationData(client->net_proto_version)));
1983 // Add to known objects
1984 client->m_known_objects.insert(id);
1986 obj->m_known_by_count++;
1989 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
1990 pkt.putRawString(data.c_str(), data.size());
1993 verbosestream << "Server::SendActiveObjectRemoveAdd: "
1994 << removed_count << " removed, " << added_count << " added, "
1995 << "packet size is " << pkt.getSize() << std::endl;
1998 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2001 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2002 datas.size(), peer_id);
2004 pkt.putRawString(datas.c_str(), datas.size());
2006 m_clients.send(pkt.getPeerId(),
2007 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2011 void Server::SendCSMRestrictionFlags(session_t peer_id)
2013 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2014 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2015 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2019 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2021 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2026 inline s32 Server::nextSoundId()
2028 s32 ret = m_next_sound_id;
2029 if (m_next_sound_id == INT32_MAX)
2030 m_next_sound_id = 0; // signed overflow is undefined
2036 s32 Server::playSound(const SimpleSoundSpec &spec,
2037 const ServerSoundParams ¶ms, bool ephemeral)
2039 // Find out initial position of sound
2040 bool pos_exists = false;
2041 v3f pos = params.getPos(m_env, &pos_exists);
2042 // If position is not found while it should be, cancel sound
2043 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2046 // Filter destination clients
2047 std::vector<session_t> dst_clients;
2048 if (!params.to_player.empty()) {
2049 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2051 infostream<<"Server::playSound: Player \""<<params.to_player
2052 <<"\" not found"<<std::endl;
2055 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2056 infostream<<"Server::playSound: Player \""<<params.to_player
2057 <<"\" not connected"<<std::endl;
2060 dst_clients.push_back(player->getPeerId());
2062 std::vector<session_t> clients = m_clients.getClientIDs();
2064 for (const session_t client_id : clients) {
2065 RemotePlayer *player = m_env->getPlayer(client_id);
2068 if (!params.exclude_player.empty() &&
2069 params.exclude_player == player->getName())
2072 PlayerSAO *sao = player->getPlayerSAO();
2077 if(sao->getBasePosition().getDistanceFrom(pos) >
2078 params.max_hear_distance)
2081 dst_clients.push_back(client_id);
2085 if(dst_clients.empty())
2090 ServerPlayingSound *psound = nullptr;
2092 id = -1; // old clients will still use this, so pick a reserved ID
2095 // The sound will exist as a reference in m_playing_sounds
2096 m_playing_sounds[id] = ServerPlayingSound();
2097 psound = &m_playing_sounds[id];
2098 psound->params = params;
2099 psound->spec = spec;
2102 float gain = params.gain * spec.gain;
2103 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2104 pkt << id << spec.name << gain
2105 << (u8) params.type << pos << params.object
2106 << params.loop << params.fade << params.pitch
2109 bool as_reliable = !ephemeral;
2111 for (const u16 dst_client : dst_clients) {
2113 psound->clients.insert(dst_client);
2114 m_clients.send(dst_client, 0, &pkt, as_reliable);
2118 void Server::stopSound(s32 handle)
2120 // Get sound reference
2121 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2122 m_playing_sounds.find(handle);
2123 if (i == m_playing_sounds.end())
2125 ServerPlayingSound &psound = i->second;
2127 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2130 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2131 si != psound.clients.end(); ++si) {
2133 m_clients.send(*si, 0, &pkt, true);
2135 // Remove sound reference
2136 m_playing_sounds.erase(i);
2139 void Server::fadeSound(s32 handle, float step, float gain)
2141 // Get sound reference
2142 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2143 m_playing_sounds.find(handle);
2144 if (i == m_playing_sounds.end())
2147 ServerPlayingSound &psound = i->second;
2148 psound.params.gain = gain;
2150 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2151 pkt << handle << step << gain;
2153 // Backwards compability
2154 bool play_sound = gain > 0;
2155 ServerPlayingSound compat_psound = psound;
2156 compat_psound.clients.clear();
2158 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2159 compat_pkt << handle;
2161 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2162 it != psound.clients.end();) {
2163 if (m_clients.getProtocolVersion(*it) >= 32) {
2165 m_clients.send(*it, 0, &pkt, true);
2168 compat_psound.clients.insert(*it);
2170 m_clients.send(*it, 0, &compat_pkt, true);
2171 psound.clients.erase(it++);
2175 // Remove sound reference
2176 if (!play_sound || psound.clients.empty())
2177 m_playing_sounds.erase(i);
2179 if (play_sound && !compat_psound.clients.empty()) {
2180 // Play new sound volume on older clients
2181 playSound(compat_psound.spec, compat_psound.params);
2185 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2188 float maxd = far_d_nodes * BS;
2189 v3f p_f = intToFloat(p, BS);
2190 v3s16 block_pos = getNodeBlockPos(p);
2192 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2195 std::vector<session_t> clients = m_clients.getClientIDs();
2198 for (session_t client_id : clients) {
2199 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2203 RemotePlayer *player = m_env->getPlayer(client_id);
2204 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2206 // If player is far away, only set modified blocks not sent
2207 if (!client->isBlockSent(block_pos) || (sao &&
2208 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2210 far_players->emplace(client_id);
2212 client->SetBlockNotSent(block_pos);
2217 m_clients.send(client_id, 0, &pkt, true);
2223 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2224 float far_d_nodes, bool remove_metadata)
2226 float maxd = far_d_nodes * BS;
2227 v3f p_f = intToFloat(p, BS);
2228 v3s16 block_pos = getNodeBlockPos(p);
2230 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2231 pkt << p << n.param0 << n.param1 << n.param2
2232 << (u8) (remove_metadata ? 0 : 1);
2234 std::vector<session_t> clients = m_clients.getClientIDs();
2237 for (session_t client_id : clients) {
2238 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2242 RemotePlayer *player = m_env->getPlayer(client_id);
2243 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2245 // If player is far away, only set modified blocks not sent
2246 if (!client->isBlockSent(block_pos) || (sao &&
2247 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2249 far_players->emplace(client_id);
2251 client->SetBlockNotSent(block_pos);
2256 m_clients.send(client_id, 0, &pkt, true);
2262 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2264 float maxd = far_d_nodes * BS;
2265 NodeMetadataList meta_updates_list(false);
2266 std::vector<session_t> clients = m_clients.getClientIDs();
2270 for (session_t i : clients) {
2271 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2275 ServerActiveObject *player = m_env->getActiveObject(i);
2276 v3f player_pos = player ? player->getBasePosition() : v3f();
2278 for (const v3s16 &pos : meta_updates) {
2279 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2284 v3s16 block_pos = getNodeBlockPos(pos);
2285 if (!client->isBlockSent(block_pos) || (player &&
2286 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2287 client->SetBlockNotSent(block_pos);
2291 // Add the change to send list
2292 meta_updates_list.set(pos, meta);
2294 if (meta_updates_list.size() == 0)
2297 // Send the meta changes
2298 std::ostringstream os(std::ios::binary);
2299 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2300 std::ostringstream oss(std::ios::binary);
2301 compressZlib(os.str(), oss);
2303 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2304 pkt.putLongString(oss.str());
2305 m_clients.send(i, 0, &pkt, true);
2307 meta_updates_list.clear();
2313 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2314 u16 net_proto_version)
2317 Create a packet with the block in the right format
2320 std::ostringstream os(std::ios_base::binary);
2321 block->serialize(os, ver, false);
2322 block->serializeNetworkSpecific(os);
2323 std::string s = os.str();
2325 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2327 pkt << block->getPos();
2328 pkt.putRawString(s.c_str(), s.size());
2332 void Server::SendBlocks(float dtime)
2334 MutexAutoLock envlock(m_env_mutex);
2335 //TODO check if one big lock could be faster then multiple small ones
2337 std::vector<PrioritySortedBlockTransfer> queue;
2339 u32 total_sending = 0;
2342 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2344 std::vector<session_t> clients = m_clients.getClientIDs();
2347 for (const session_t client_id : clients) {
2348 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2353 total_sending += client->getSendingCount();
2354 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2360 // Lowest priority number comes first.
2361 // Lowest is most important.
2362 std::sort(queue.begin(), queue.end());
2366 // Maximal total count calculation
2367 // The per-client block sends is halved with the maximal online users
2368 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2369 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2371 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2372 Map &map = m_env->getMap();
2374 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2375 if (total_sending >= max_blocks_to_send)
2378 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2382 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2387 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2388 client->net_proto_version);
2390 client->SentBlock(block_to_send.pos);
2396 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2398 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2403 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2404 if (!client || client->isBlockSent(blockpos)) {
2408 SendBlockNoLock(peer_id, block, client->serialization_version,
2409 client->net_proto_version);
2415 bool Server::addMediaFile(const std::string &filename,
2416 const std::string &filepath, std::string *filedata_to,
2417 std::string *digest_to)
2419 // If name contains illegal characters, ignore the file
2420 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2421 infostream << "Server: ignoring illegal file name: \""
2422 << filename << "\"" << std::endl;
2425 // If name is not in a supported format, ignore it
2426 const char *supported_ext[] = {
2427 ".png", ".jpg", ".bmp", ".tga",
2428 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2430 ".x", ".b3d", ".md2", ".obj",
2431 // Custom translation file format
2435 if (removeStringEnd(filename, supported_ext).empty()) {
2436 infostream << "Server: ignoring unsupported file extension: \""
2437 << filename << "\"" << std::endl;
2440 // Ok, attempt to load the file and add to cache
2443 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2445 errorstream << "Server::addMediaFile(): Could not open \""
2446 << filename << "\" for reading" << std::endl;
2449 std::string filedata;
2453 fis.read(buf, sizeof(buf));
2454 std::streamsize len = fis.gcount();
2455 filedata.append(buf, len);
2464 errorstream << "Server::addMediaFile(): Failed to read \""
2465 << filename << "\"" << std::endl;
2467 } else if (filedata.empty()) {
2468 errorstream << "Server::addMediaFile(): Empty file \""
2469 << filepath << "\"" << std::endl;
2474 sha1.addBytes(filedata.c_str(), filedata.length());
2476 unsigned char *digest = sha1.getDigest();
2477 std::string sha1_base64 = base64_encode(digest, 20);
2478 std::string sha1_hex = hex_encode((char*) digest, 20);
2480 *digest_to = std::string((char*) digest, 20);
2484 m_media[filename] = MediaInfo(filepath, sha1_base64);
2485 verbosestream << "Server: " << sha1_hex << " is " << filename
2489 *filedata_to = std::move(filedata);
2493 void Server::fillMediaCache()
2495 infostream << "Server: Calculating media file checksums" << std::endl;
2497 // Collect all media file paths
2498 std::vector<std::string> paths;
2499 m_modmgr->getModsMediaPaths(paths);
2500 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2501 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2503 // Collect media file information from paths into cache
2504 for (const std::string &mediapath : paths) {
2505 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2506 for (const fs::DirListNode &dln : dirlist) {
2507 if (dln.dir) // Ignore dirs
2509 std::string filepath = mediapath;
2510 filepath.append(DIR_DELIM).append(dln.name);
2511 addMediaFile(dln.name, filepath);
2515 infostream << "Server: " << m_media.size() << " media files collected" << std::endl;
2518 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2521 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2524 std::string lang_suffix;
2525 lang_suffix.append(".").append(lang_code).append(".tr");
2526 for (const auto &i : m_media) {
2527 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2534 for (const auto &i : m_media) {
2535 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2537 pkt << i.first << i.second.sha1_digest;
2540 pkt << g_settings->get("remote_media");
2543 verbosestream << "Server: Announcing files to id(" << peer_id
2544 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2547 struct SendableMedia
2553 SendableMedia(const std::string &name_="", const std::string &path_="",
2554 const std::string &data_=""):
2561 void Server::sendRequestedMedia(session_t peer_id,
2562 const std::vector<std::string> &tosend)
2564 verbosestream<<"Server::sendRequestedMedia(): "
2565 <<"Sending files to client"<<std::endl;
2569 // Put 5kB in one bunch (this is not accurate)
2570 u32 bytes_per_bunch = 5000;
2572 std::vector< std::vector<SendableMedia> > file_bunches;
2573 file_bunches.emplace_back();
2575 u32 file_size_bunch_total = 0;
2577 for (const std::string &name : tosend) {
2578 if (m_media.find(name) == m_media.end()) {
2579 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2580 <<"unknown file \""<<(name)<<"\""<<std::endl;
2584 //TODO get path + name
2585 std::string tpath = m_media[name].path;
2588 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2590 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2591 <<tpath<<"\" for reading"<<std::endl;
2594 std::ostringstream tmp_os(std::ios_base::binary);
2598 fis.read(buf, 1024);
2599 std::streamsize len = fis.gcount();
2600 tmp_os.write(buf, len);
2601 file_size_bunch_total += len;
2610 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2611 <<name<<"\""<<std::endl;
2614 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2615 <<tname<<"\""<<std::endl;*/
2617 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2619 // Start next bunch if got enough data
2620 if(file_size_bunch_total >= bytes_per_bunch) {
2621 file_bunches.emplace_back();
2622 file_size_bunch_total = 0;
2627 /* Create and send packets */
2629 u16 num_bunches = file_bunches.size();
2630 for (u16 i = 0; i < num_bunches; i++) {
2633 u16 total number of texture bunches
2634 u16 index of this bunch
2635 u32 number of files in this bunch
2644 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2645 pkt << num_bunches << i << (u32) file_bunches[i].size();
2647 for (const SendableMedia &j : file_bunches[i]) {
2649 pkt.putLongString(j.data);
2652 verbosestream << "Server::sendRequestedMedia(): bunch "
2653 << i << "/" << num_bunches
2654 << " files=" << file_bunches[i].size()
2655 << " size=" << pkt.getSize() << std::endl;
2660 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2662 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2666 pkt << false; // Remove inventory
2668 pkt << true; // Update inventory
2670 // Serialization & NetworkPacket isn't a love story
2671 std::ostringstream os(std::ios_base::binary);
2672 inventory->serialize(os);
2673 inventory->setModified(false);
2675 const std::string &os_str = os.str();
2676 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2677 pkt.putRawString(os_str);
2680 if (peer_id == PEER_ID_INEXISTENT)
2681 m_clients.sendToAll(&pkt);
2686 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2688 // Lookup player name, to filter detached inventories just after
2689 std::string peer_name;
2690 if (peer_id != PEER_ID_INEXISTENT) {
2691 peer_name = getClient(peer_id, CS_Created)->getName();
2694 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2695 sendDetachedInventory(inv, name, peer_id);
2698 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2705 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2707 PlayerSAO *playersao = getPlayerSAO(peer_id);
2710 infostream << "Server::DiePlayer(): Player "
2711 << playersao->getPlayer()->getName()
2712 << " dies" << std::endl;
2714 playersao->setHP(0, reason);
2715 playersao->clearParentAttachment();
2717 // Trigger scripted stuff
2718 m_script->on_dieplayer(playersao, reason);
2720 SendPlayerHP(peer_id);
2721 SendDeathscreen(peer_id, false, v3f(0,0,0));
2724 void Server::RespawnPlayer(session_t peer_id)
2726 PlayerSAO *playersao = getPlayerSAO(peer_id);
2729 infostream << "Server::RespawnPlayer(): Player "
2730 << playersao->getPlayer()->getName()
2731 << " respawns" << std::endl;
2733 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2734 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2735 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2737 bool repositioned = m_script->on_respawnplayer(playersao);
2738 if (!repositioned) {
2739 // setPos will send the new position to client
2740 playersao->setPos(findSpawnPos());
2743 SendPlayerHP(peer_id);
2747 void Server::DenySudoAccess(session_t peer_id)
2749 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2754 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2755 const std::string &str_reason, bool reconnect)
2757 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2759 m_clients.event(peer_id, CSE_SetDenied);
2760 DisconnectPeer(peer_id);
2764 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2765 const std::string &custom_reason)
2767 SendAccessDenied(peer_id, reason, custom_reason);
2768 m_clients.event(peer_id, CSE_SetDenied);
2769 DisconnectPeer(peer_id);
2772 // 13/03/15: remove this function when protocol version 25 will become
2773 // the minimum version for MT users, maybe in 1 year
2774 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2776 SendAccessDenied_Legacy(peer_id, reason);
2777 m_clients.event(peer_id, CSE_SetDenied);
2778 DisconnectPeer(peer_id);
2781 void Server::DisconnectPeer(session_t peer_id)
2783 m_modchannel_mgr->leaveAllChannels(peer_id);
2784 m_con->DisconnectPeer(peer_id);
2787 void Server::RedirectPeer(session_t peer_id, const std::string address, u16 port)
2789 SendRedirect(peer_id, address, port);
2792 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2795 RemoteClient* client = getClient(peer_id, CS_Invalid);
2797 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2799 // Right now, the auth mechs don't change between login and sudo mode.
2800 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2801 client->allowed_sudo_mechs = sudo_auth_mechs;
2803 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2804 << g_settings->getFloat("dedicated_server_step")
2808 m_clients.event(peer_id, CSE_AuthAccept);
2810 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2812 // We only support SRP right now
2813 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2815 resp_pkt << sudo_auth_mechs;
2817 m_clients.event(peer_id, CSE_SudoSuccess);
2821 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2823 std::wstring message;
2826 Clear references to playing sounds
2828 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2829 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2830 ServerPlayingSound &psound = i->second;
2831 psound.clients.erase(peer_id);
2832 if (psound.clients.empty())
2833 m_playing_sounds.erase(i++);
2838 // clear formspec info so the next client can't abuse the current state
2839 m_formspec_state_data.erase(peer_id);
2841 RemotePlayer *player = m_env->getPlayer(peer_id);
2843 /* Run scripts and remove from environment */
2845 PlayerSAO *playersao = player->getPlayerSAO();
2848 playersao->clearChildAttachments();
2849 playersao->clearParentAttachment();
2851 // inform connected clients
2852 const std::string &player_name = player->getName();
2853 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2854 // (u16) 1 + std::string represents a vector serialization representation
2855 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2856 m_clients.sendToAll(¬ice);
2858 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2860 playersao->disconnected();
2867 if (player && reason != CDR_DENY) {
2868 std::ostringstream os(std::ios_base::binary);
2869 std::vector<session_t> clients = m_clients.getClientIDs();
2871 for (const session_t client_id : clients) {
2873 RemotePlayer *player = m_env->getPlayer(client_id);
2877 // Get name of player
2878 os << player->getName() << " ";
2881 std::string name = player->getName();
2882 actionstream << name << " "
2883 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2884 << " List of players: " << os.str() << std::endl;
2886 m_admin_chat->outgoing_queue.push_back(
2887 new ChatEventNick(CET_NICK_REMOVE, name));
2891 MutexAutoLock env_lock(m_env_mutex);
2892 m_clients.DeleteClient(peer_id);
2896 // Send leave chat message to all remaining clients
2897 if (!message.empty()) {
2898 SendChatMessage(PEER_ID_INEXISTENT,
2899 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2903 void Server::UpdateCrafting(RemotePlayer *player)
2905 InventoryList *clist = player->inventory.getList("craft");
2906 if (!clist || clist->getSize() == 0)
2909 if (!clist->checkModified())
2912 // Get a preview for crafting
2914 InventoryLocation loc;
2915 loc.setPlayer(player->getName());
2916 std::vector<ItemStack> output_replacements;
2917 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2918 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2921 InventoryList *plist = player->inventory.getList("craftpreview");
2922 if (plist && plist->getSize() >= 1) {
2923 // Put the new preview in
2924 plist->changeItem(0, preview);
2928 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2930 if (evt->type == CET_NICK_ADD) {
2931 // The terminal informed us of its nick choice
2932 m_admin_nick = ((ChatEventNick *)evt)->nick;
2933 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2934 errorstream << "You haven't set up an account." << std::endl
2935 << "Please log in using the client as '"
2936 << m_admin_nick << "' with a secure password." << std::endl
2937 << "Until then, you can't execute admin tasks via the console," << std::endl
2938 << "and everybody can claim the user account instead of you," << std::endl
2939 << "giving them full control over this server." << std::endl;
2942 assert(evt->type == CET_CHAT);
2943 handleAdminChat((ChatEventChat *)evt);
2947 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2948 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2950 // If something goes wrong, this player is to blame
2951 RollbackScopeActor rollback_scope(m_rollback,
2952 std::string("player:") + name);
2954 if (g_settings->getBool("strip_color_codes"))
2955 wmessage = unescape_enriched(wmessage);
2958 switch (player->canSendChatMessage()) {
2959 case RPLAYER_CHATRESULT_FLOODING: {
2960 std::wstringstream ws;
2961 ws << L"You cannot send more messages. You are limited to "
2962 << g_settings->getFloat("chat_message_limit_per_10sec")
2963 << L" messages per 10 seconds.";
2966 case RPLAYER_CHATRESULT_KICK:
2967 DenyAccess_Legacy(player->getPeerId(),
2968 L"You have been kicked due to message flooding.");
2970 case RPLAYER_CHATRESULT_OK:
2973 FATAL_ERROR("Unhandled chat filtering result found.");
2977 if (m_max_chatmessage_length > 0
2978 && wmessage.length() > m_max_chatmessage_length) {
2979 return L"Your message exceed the maximum chat message limit set on the server. "
2980 L"It was refused. Send a shorter message";
2983 auto message = trim(wide_to_utf8(wmessage));
2984 if (message.find_first_of("\n\r") != std::wstring::npos) {
2985 return L"New lines are not permitted in chat messages";
2988 // Run script hook, exit if script ate the chat message
2989 if (m_script->on_chat_message(name, message))
2994 // Whether to send line to the player that sent the message, or to all players
2995 bool broadcast_line = true;
2997 if (check_shout_priv && !checkPriv(name, "shout")) {
2998 line += L"-!- You don't have permission to shout.";
2999 broadcast_line = false;
3002 Workaround for fixing chat on Android. Lua doesn't handle
3003 the Cyrillic alphabet and some characters on older Android devices
3006 line += L"<" + wname + L"> " + wmessage;
3008 line += narrow_to_wide(m_script->formatChatMessage(name,
3009 wide_to_narrow(wmessage)));
3014 Tell calling method to send the message to sender
3016 if (!broadcast_line)
3020 Send the message to others
3022 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
3024 std::vector<session_t> clients = m_clients.getClientIDs();
3027 Send the message back to the inital sender
3028 if they are using protocol version >= 29
3031 session_t peer_id_to_avoid_sending =
3032 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
3034 if (player && player->protocol_version >= 29)
3035 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
3037 for (u16 cid : clients) {
3038 if (cid != peer_id_to_avoid_sending)
3039 SendChatMessage(cid, ChatMessage(line));
3044 void Server::handleAdminChat(const ChatEventChat *evt)
3046 std::string name = evt->nick;
3047 std::wstring wname = utf8_to_wide(name);
3048 std::wstring wmessage = evt->evt_msg;
3050 std::wstring answer = handleChat(name, wname, wmessage);
3052 // If asked to send answer to sender
3053 if (!answer.empty()) {
3054 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3058 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3060 RemoteClient *client = getClientNoEx(peer_id,state_min);
3062 throw ClientNotFoundException("Client not found");
3066 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3068 return m_clients.getClientNoEx(peer_id, state_min);
3071 std::string Server::getPlayerName(session_t peer_id)
3073 RemotePlayer *player = m_env->getPlayer(peer_id);
3075 return "[id="+itos(peer_id)+"]";
3076 return player->getName();
3079 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3081 RemotePlayer *player = m_env->getPlayer(peer_id);
3084 return player->getPlayerSAO();
3087 std::wstring Server::getStatusString()
3089 std::wostringstream os(std::ios_base::binary);
3090 os << L"# Server: ";
3092 os << L"version=" << narrow_to_wide(g_version_string);
3094 os << L", uptime=" << m_uptime_counter->get();
3096 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3098 // Information about clients
3100 os << L", clients={";
3102 std::vector<session_t> clients = m_clients.getClientIDs();
3103 for (session_t client_id : clients) {
3104 RemotePlayer *player = m_env->getPlayer(client_id);
3106 // Get name of player
3107 std::wstring name = L"unknown";
3109 name = narrow_to_wide(player->getName());
3111 // Add name to information string
3122 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3123 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3125 if (!g_settings->get("motd").empty())
3126 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3131 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3133 std::set<std::string> privs;
3134 m_script->getAuth(name, NULL, &privs);
3138 bool Server::checkPriv(const std::string &name, const std::string &priv)
3140 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3141 return (privs.count(priv) != 0);
3144 void Server::reportPrivsModified(const std::string &name)
3147 std::vector<session_t> clients = m_clients.getClientIDs();
3148 for (const session_t client_id : clients) {
3149 RemotePlayer *player = m_env->getPlayer(client_id);
3150 reportPrivsModified(player->getName());
3153 RemotePlayer *player = m_env->getPlayer(name.c_str());
3156 SendPlayerPrivileges(player->getPeerId());
3157 PlayerSAO *sao = player->getPlayerSAO();
3160 sao->updatePrivileges(
3161 getPlayerEffectivePrivs(name),
3166 void Server::reportInventoryFormspecModified(const std::string &name)
3168 RemotePlayer *player = m_env->getPlayer(name.c_str());
3171 SendPlayerInventoryFormspec(player->getPeerId());
3174 void Server::reportFormspecPrependModified(const std::string &name)
3176 RemotePlayer *player = m_env->getPlayer(name.c_str());
3179 SendPlayerFormspecPrepend(player->getPeerId());
3182 void Server::setIpBanned(const std::string &ip, const std::string &name)
3184 m_banmanager->add(ip, name);
3187 void Server::unsetIpBanned(const std::string &ip_or_name)
3189 m_banmanager->remove(ip_or_name);
3192 std::string Server::getBanDescription(const std::string &ip_or_name)
3194 return m_banmanager->getBanDescription(ip_or_name);
3197 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3199 // m_env will be NULL if the server is initializing
3203 if (m_admin_nick == name && !m_admin_nick.empty()) {
3204 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3207 RemotePlayer *player = m_env->getPlayer(name);
3212 if (player->getPeerId() == PEER_ID_INEXISTENT)
3215 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3218 bool Server::showFormspec(const char *playername, const std::string &formspec,
3219 const std::string &formname)
3221 // m_env will be NULL if the server is initializing
3225 RemotePlayer *player = m_env->getPlayer(playername);
3229 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3233 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3238 u32 id = player->addHud(form);
3240 SendHUDAdd(player->getPeerId(), id, form);
3245 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3249 HudElement* todel = player->removeHud(id);
3256 SendHUDRemove(player->getPeerId(), id);
3260 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3265 SendHUDChange(player->getPeerId(), id, stat, data);
3269 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3274 SendHUDSetFlags(player->getPeerId(), flags, mask);
3275 player->hud_flags &= ~mask;
3276 player->hud_flags |= flags;
3278 PlayerSAO* playersao = player->getPlayerSAO();
3283 m_script->player_event(playersao, "hud_changed");
3287 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3292 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3295 player->setHotbarItemcount(hotbar_itemcount);
3296 std::ostringstream os(std::ios::binary);
3297 writeS32(os, hotbar_itemcount);
3298 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3302 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3307 player->setHotbarImage(name);
3308 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3311 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3316 player->setHotbarSelectedImage(name);
3317 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3320 Address Server::getPeerAddress(session_t peer_id)
3322 return m_con->GetPeerAddress(peer_id);
3325 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3326 v2s32 animation_frames[4], f32 frame_speed)
3328 sanity_check(player);
3329 player->setLocalAnimations(animation_frames, frame_speed);
3330 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3333 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3335 sanity_check(player);
3336 player->eye_offset_first = first;
3337 player->eye_offset_third = third;
3338 SendEyeOffset(player->getPeerId(), first, third);
3341 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3343 sanity_check(player);
3344 player->setSky(params);
3345 SendSetSky(player->getPeerId(), params);
3348 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3350 sanity_check(player);
3351 player->setSun(params);
3352 SendSetSun(player->getPeerId(), params);
3355 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3357 sanity_check(player);
3358 player->setMoon(params);
3359 SendSetMoon(player->getPeerId(), params);
3362 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3364 sanity_check(player);
3365 player->setStars(params);
3366 SendSetStars(player->getPeerId(), params);
3369 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3371 sanity_check(player);
3372 player->setCloudParams(params);
3373 SendCloudParams(player->getPeerId(), params);
3376 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3379 sanity_check(player);
3380 player->overrideDayNightRatio(do_override, ratio);
3381 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3384 void Server::notifyPlayers(const std::wstring &msg)
3386 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3389 void Server::spawnParticle(const std::string &playername,
3390 const ParticleParameters &p)
3392 // m_env will be NULL if the server is initializing
3396 session_t peer_id = PEER_ID_INEXISTENT;
3398 if (!playername.empty()) {
3399 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3402 peer_id = player->getPeerId();
3403 proto_ver = player->protocol_version;
3406 SendSpawnParticle(peer_id, proto_ver, p);
3409 u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
3410 ServerActiveObject *attached, const std::string &playername)
3412 // m_env will be NULL if the server is initializing
3416 session_t peer_id = PEER_ID_INEXISTENT;
3418 if (!playername.empty()) {
3419 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3422 peer_id = player->getPeerId();
3423 proto_ver = player->protocol_version;
3426 u16 attached_id = attached ? attached->getId() : 0;
3429 if (attached_id == 0)
3430 id = m_env->addParticleSpawner(p.time);
3432 id = m_env->addParticleSpawner(p.time, attached_id);
3434 SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
3438 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3440 // m_env will be NULL if the server is initializing
3442 throw ServerError("Can't delete particle spawners during initialisation!");
3444 session_t peer_id = PEER_ID_INEXISTENT;
3445 if (!playername.empty()) {
3446 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3449 peer_id = player->getPeerId();
3452 m_env->deleteParticleSpawner(id);
3453 SendDeleteParticleSpawner(peer_id, id);
3456 bool Server::dynamicAddMedia(const std::string &filepath)
3458 std::string filename = fs::GetFilenameFromPath(filepath.c_str());
3459 if (m_media.find(filename) != m_media.end()) {
3460 errorstream << "Server::dynamicAddMedia(): file \"" << filename
3461 << "\" already exists in media cache" << std::endl;
3465 // Load the file and add it to our media cache
3466 std::string filedata, raw_hash;
3467 bool ok = addMediaFile(filename, filepath, &filedata, &raw_hash);
3471 // Push file to existing clients
3472 NetworkPacket pkt(TOCLIENT_MEDIA_PUSH, 0);
3473 pkt << raw_hash << filename << (bool) true;
3474 pkt.putLongString(filedata);
3476 auto client_ids = m_clients.getClientIDs(CS_DefinitionsSent);
3477 for (session_t client_id : client_ids) {
3479 The network layer only guarantees ordered delivery inside a channel.
3480 Since the very next packet could be one that uses the media, we have
3481 to push the media over ALL channels to ensure it is processed before
3483 In practice this means we have to send it twice:
3485 - channel 0 (everything else: e.g. play_sound, object messages)
3487 m_clients.send(client_id, 1, &pkt, true);
3488 m_clients.send(client_id, 0, &pkt, true);
3494 // actions: time-reversed list
3495 // Return value: success/failure
3496 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3497 std::list<std::string> *log)
3499 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3500 ServerMap *map = (ServerMap*)(&m_env->getMap());
3502 // Fail if no actions to handle
3503 if (actions.empty()) {
3505 log->push_back("Nothing to do.");
3512 for (const RollbackAction &action : actions) {
3514 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3517 std::ostringstream os;
3518 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3519 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3521 log->push_back(os.str());
3523 std::ostringstream os;
3524 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3525 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3527 log->push_back(os.str());
3531 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3532 <<" failed"<<std::endl;
3534 // Call it done if less than half failed
3535 return num_failed <= num_tried/2;
3538 // IGameDef interface
3540 IItemDefManager *Server::getItemDefManager()
3545 const NodeDefManager *Server::getNodeDefManager()
3550 ICraftDefManager *Server::getCraftDefManager()
3555 u16 Server::allocateUnknownNodeId(const std::string &name)
3557 return m_nodedef->allocateDummy(name);
3560 IWritableItemDefManager *Server::getWritableItemDefManager()
3565 NodeDefManager *Server::getWritableNodeDefManager()
3570 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3575 const std::vector<ModSpec> & Server::getMods() const
3577 return m_modmgr->getMods();
3580 const ModSpec *Server::getModSpec(const std::string &modname) const
3582 return m_modmgr->getModSpec(modname);
3585 void Server::getModNames(std::vector<std::string> &modlist)
3587 m_modmgr->getModNames(modlist);
3590 std::string Server::getBuiltinLuaPath()
3592 return porting::path_share + DIR_DELIM + "builtin";
3595 std::string Server::getModStoragePath() const
3597 return m_path_world + DIR_DELIM + "mod_storage";
3600 v3f Server::findSpawnPos()
3602 ServerMap &map = m_env->getServerMap();
3604 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3605 return nodeposf * BS;
3607 bool is_good = false;
3608 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3609 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3611 // Try to find a good place a few times
3612 for (s32 i = 0; i < 4000 && !is_good; i++) {
3613 s32 range = MYMIN(1 + i, range_max);
3614 // We're going to try to throw the player to this position
3615 v2s16 nodepos2d = v2s16(
3616 -range + (myrand() % (range * 2)),
3617 -range + (myrand() % (range * 2)));
3618 // Get spawn level at point
3619 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3620 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3621 // signify an unsuitable spawn position, or if outside limits.
3622 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3623 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3626 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3627 // Consecutive empty nodes
3630 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3631 // avoid obstructions in already-generated mapblocks.
3632 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3633 // no obstructions, but mapgen decorations are generated after spawn so
3634 // the player may end up inside one.
3635 for (s32 i = 0; i < 8; i++) {
3636 v3s16 blockpos = getNodeBlockPos(nodepos);
3637 map.emergeBlock(blockpos, true);
3638 content_t c = map.getNode(nodepos).getContent();
3640 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3641 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3642 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3644 if (air_count >= 2) {
3645 // Spawn in lower empty node
3647 nodeposf = intToFloat(nodepos, BS);
3648 // Don't spawn the player outside map boundaries
3649 if (objectpos_over_limit(nodeposf))
3650 // Exit this loop, positions above are probably over limit
3653 // Good position found, cause an exit from main loop
3667 // No suitable spawn point found, return fallback 0,0,0
3668 return v3f(0.0f, 0.0f, 0.0f);
3671 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3673 if (delay == 0.0f) {
3674 // No delay, shutdown immediately
3675 m_shutdown_state.is_requested = true;
3676 // only print to the infostream, a chat message saying
3677 // "Server Shutting Down" is sent when the server destructs.
3678 infostream << "*** Immediate Server shutdown requested." << std::endl;
3679 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3680 // Negative delay, cancel shutdown if requested
3681 m_shutdown_state.reset();
3682 std::wstringstream ws;
3684 ws << L"*** Server shutdown canceled.";
3686 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3687 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3688 // m_shutdown_* are already handled, skip.
3690 } else if (delay > 0.0f) {
3691 // Positive delay, tell the clients when the server will shut down
3692 std::wstringstream ws;
3694 ws << L"*** Server shutting down in "
3695 << duration_to_string(myround(delay)).c_str()
3698 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3699 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3702 m_shutdown_state.trigger(delay, msg, reconnect);
3705 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3708 Try to get an existing player
3710 RemotePlayer *player = m_env->getPlayer(name);
3712 // If player is already connected, cancel
3713 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3714 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3719 If player with the wanted peer_id already exists, cancel.
3721 if (m_env->getPlayer(peer_id)) {
3722 infostream<<"emergePlayer(): Player with wrong name but same"
3723 " peer_id already exists"<<std::endl;
3728 player = new RemotePlayer(name, idef());
3731 bool newplayer = false;
3734 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3736 // Complete init with server parts
3737 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3738 player->protocol_version = proto_version;
3742 m_script->on_newplayer(playersao);
3748 bool Server::registerModStorage(ModMetadata *storage)
3750 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3751 errorstream << "Unable to register same mod storage twice. Storage name: "
3752 << storage->getModName() << std::endl;
3756 m_mod_storages[storage->getModName()] = storage;
3760 void Server::unregisterModStorage(const std::string &name)
3762 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3763 if (it != m_mod_storages.end()) {
3764 // Save unconditionaly on unregistration
3765 it->second->save(getModStoragePath());
3766 m_mod_storages.erase(name);
3770 void dedicated_server_loop(Server &server, bool &kill)
3772 verbosestream<<"dedicated_server_loop()"<<std::endl;
3774 IntervalLimiter m_profiler_interval;
3776 static thread_local const float steplen =
3777 g_settings->getFloat("dedicated_server_step");
3778 static thread_local const float profiler_print_interval =
3779 g_settings->getFloat("profiler_print_interval");
3782 * The dedicated server loop only does time-keeping (in Server::step) and
3783 * provides a way to main.cpp to kill the server externally (bool &kill).
3787 // This is kind of a hack but can be done like this
3788 // because server.step() is very light
3789 sleep_ms((int)(steplen*1000.0));
3790 server.step(steplen);
3792 if (server.isShutdownRequested() || kill)
3798 if (profiler_print_interval != 0) {
3799 if(m_profiler_interval.step(steplen, profiler_print_interval))
3801 infostream<<"Profiler:"<<std::endl;
3802 g_profiler->print(infostream);
3803 g_profiler->clear();
3808 infostream << "Dedicated server quitting" << std::endl;
3810 if (g_settings->getBool("server_announce"))
3811 ServerList::sendAnnounce(ServerList::AA_DELETE,
3812 server.m_bind_addr.getPort());
3821 bool Server::joinModChannel(const std::string &channel)
3823 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3824 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3827 bool Server::leaveModChannel(const std::string &channel)
3829 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3832 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3834 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3837 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3841 ModChannel* Server::getModChannel(const std::string &channel)
3843 return m_modchannel_mgr->getModChannel(channel);
3846 void Server::broadcastModChannelMessage(const std::string &channel,
3847 const std::string &message, session_t from_peer)
3849 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3853 if (message.size() > STRING_MAX_LEN) {
3854 warningstream << "ModChannel message too long, dropping before sending "
3855 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3856 << channel << ")" << std::endl;
3861 if (from_peer != PEER_ID_SERVER) {
3862 sender = getPlayerName(from_peer);
3865 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3866 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3867 resp_pkt << channel << sender << message;
3868 for (session_t peer_id : peers) {
3870 if (peer_id == from_peer)
3873 Send(peer_id, &resp_pkt);
3876 if (from_peer != PEER_ID_SERVER) {
3877 m_script->on_modchannel_message(channel, sender, message);
3881 void Server::loadTranslationLanguage(const std::string &lang_code)
3883 if (g_server_translations->count(lang_code))
3884 return; // Already loaded
3886 std::string suffix = "." + lang_code + ".tr";
3887 for (const auto &i : m_media) {
3888 if (str_ends_with(i.first, suffix)) {
3889 std::ifstream t(i.second.path);
3890 std::string data((std::istreambuf_iterator<char>(t)),
3891 std::istreambuf_iterator<char>());
3893 (*g_server_translations)[lang_code].loadTranslation(data);