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 for connected nodeboxes
416 m_nodedef->mapNodeboxConnections();
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
722 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
726 std::vector<ActiveObjectMessage>* message_list = nullptr;
727 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
728 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;
734 message_list = n->second;
736 message_list->push_back(aom);
739 m_aom_buffer_counter->increment(buffered_messages.size());
742 const RemoteClientMap &clients = m_clients.getClientList();
743 // Route data to every client
744 for (const auto &client_it : clients) {
745 RemoteClient *client = client_it.second;
746 PlayerSAO *player = getPlayerSAO(client->peer_id);
747 std::string reliable_data;
748 std::string unreliable_data;
749 // Go through all objects in message buffer
750 for (const auto &buffered_message : buffered_messages) {
751 // If object does not exist or is not known by client, skip it
752 u16 id = buffered_message.first;
753 ServerActiveObject *sao = m_env->getActiveObject(id);
754 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
757 // Get message list of object
758 std::vector<ActiveObjectMessage>* list = buffered_message.second;
759 // Go through every message
760 for (const ActiveObjectMessage &aom : *list) {
761 // Send position updates to players who do not see the attachment
762 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
763 if (sao->getId() == player->getId())
766 // Do not send position updates for attached players
767 // as long the parent is known to the client
768 ServerActiveObject *parent = sao->getParent();
769 if (parent && client->m_known_objects.find(parent->getId()) !=
770 client->m_known_objects.end())
773 // Compose the full new data with header
774 std::string new_data;
777 writeU16((u8*)&buf[0], aom.id);
778 new_data.append(buf, 2);
780 new_data += serializeString(aom.datastring);
781 // Add data to buffer
783 reliable_data += new_data;
785 unreliable_data += new_data;
789 reliable_data and unreliable_data are now ready.
792 if (!reliable_data.empty()) {
793 SendActiveObjectMessages(client->peer_id, reliable_data);
796 if (!unreliable_data.empty()) {
797 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
802 // Clear buffered_messages
803 for (auto &buffered_message : buffered_messages) {
804 delete buffered_message.second;
809 Send queued-for-sending map edit events.
812 // We will be accessing the environment
813 MutexAutoLock lock(m_env_mutex);
815 // Don't send too many at a time
818 // Single change sending is disabled if queue size is not small
819 bool disable_single_change_sending = false;
820 if(m_unsent_map_edit_queue.size() >= 4)
821 disable_single_change_sending = true;
823 int event_count = m_unsent_map_edit_queue.size();
825 // We'll log the amount of each
828 std::list<v3s16> node_meta_updates;
830 while (!m_unsent_map_edit_queue.empty()) {
831 MapEditEvent* event = m_unsent_map_edit_queue.front();
832 m_unsent_map_edit_queue.pop();
834 // Players far away from the change are stored here.
835 // Instead of sending the changes, MapBlocks are set not sent
837 std::unordered_set<u16> far_players;
839 switch (event->type) {
842 prof.add("MEET_ADDNODE", 1);
843 sendAddNode(event->p, event->n, &far_players,
844 disable_single_change_sending ? 5 : 30,
845 event->type == MEET_ADDNODE);
847 case MEET_REMOVENODE:
848 prof.add("MEET_REMOVENODE", 1);
849 sendRemoveNode(event->p, &far_players,
850 disable_single_change_sending ? 5 : 30);
852 case MEET_BLOCK_NODE_METADATA_CHANGED: {
853 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
854 if (!event->is_private_change) {
855 // Don't send the change yet. Collect them to eliminate dupes.
856 node_meta_updates.remove(event->p);
857 node_meta_updates.push_back(event->p);
860 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
861 getNodeBlockPos(event->p))) {
862 block->raiseModified(MOD_STATE_WRITE_NEEDED,
863 MOD_REASON_REPORT_META_CHANGE);
868 prof.add("MEET_OTHER", 1);
869 for (const v3s16 &modified_block : event->modified_blocks) {
870 m_clients.markBlockposAsNotSent(modified_block);
874 prof.add("unknown", 1);
875 warningstream << "Server: Unknown MapEditEvent "
876 << ((u32)event->type) << std::endl;
881 Set blocks not sent to far players
883 if (!far_players.empty()) {
884 // Convert list format to that wanted by SetBlocksNotSent
885 std::map<v3s16, MapBlock*> modified_blocks2;
886 for (const v3s16 &modified_block : event->modified_blocks) {
887 modified_blocks2[modified_block] =
888 m_env->getMap().getBlockNoCreateNoEx(modified_block);
891 // Set blocks not sent
892 for (const u16 far_player : far_players) {
893 if (RemoteClient *client = getClient(far_player))
894 client->SetBlocksNotSent(modified_blocks2);
901 if (event_count >= 5) {
902 infostream << "Server: MapEditEvents:" << std::endl;
903 prof.print(infostream);
904 } else if (event_count != 0) {
905 verbosestream << "Server: MapEditEvents:" << std::endl;
906 prof.print(verbosestream);
909 // Send all metadata updates
910 if (node_meta_updates.size())
911 sendMetadataChanged(node_meta_updates);
915 Trigger emergethread (it somehow gets to a non-triggered but
916 bysy state sometimes)
919 float &counter = m_emergethread_trigger_timer;
921 if (counter >= 2.0) {
924 m_emerge->startThreads();
928 // Save map, players and auth stuff
930 float &counter = m_savemap_timer;
932 static thread_local const float save_interval =
933 g_settings->getFloat("server_map_save_interval");
934 if (counter >= save_interval) {
936 MutexAutoLock lock(m_env_mutex);
938 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
941 if (m_banmanager->isModified()) {
942 m_banmanager->save();
945 // Save changed parts of map
946 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
949 m_env->saveLoadedPlayers();
951 // Save environment metadata
956 m_shutdown_state.tick(dtime, this);
959 void Server::Receive()
969 In the first iteration *wait* for a packet, afterwards process
970 all packets that are immediately available (no waiting).
973 m_con->Receive(&pkt);
976 if (!m_con->TryReceive(&pkt))
980 peer_id = pkt.getPeerId();
981 m_packet_recv_counter->increment();
983 m_packet_recv_processed_counter->increment();
984 } catch (const con::InvalidIncomingDataException &e) {
985 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
986 << e.what() << std::endl;
987 } catch (const SerializationError &e) {
988 infostream << "Server::Receive(): SerializationError: what()="
989 << e.what() << std::endl;
990 } catch (const ClientStateError &e) {
991 errorstream << "ProcessData: peer=" << peer_id << " what()="
992 << e.what() << std::endl;
993 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
994 L"Try reconnecting or updating your client");
995 } catch (const con::PeerNotFoundException &e) {
997 } catch (const con::NoIncomingDataException &e) {
1003 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1005 std::string playername;
1006 PlayerSAO *playersao = NULL;
1009 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1011 playername = client->getName();
1012 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1014 } catch (std::exception &e) {
1020 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1022 // If failed, cancel
1023 if (!playersao || !player) {
1024 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1025 actionstream << "Server: Failed to emerge player \"" << playername
1026 << "\" (player allocated to an another client)" << std::endl;
1027 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1028 L"name. If your client closed unexpectedly, try again in "
1031 errorstream << "Server: " << playername << ": Failed to emerge player"
1033 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1039 Send complete position information
1041 SendMovePlayer(peer_id);
1044 SendPlayerPrivileges(peer_id);
1046 // Send inventory formspec
1047 SendPlayerInventoryFormspec(peer_id);
1050 SendInventory(playersao, false);
1052 // Send HP or death screen
1053 if (playersao->isDead())
1054 SendDeathscreen(peer_id, false, v3f(0,0,0));
1056 SendPlayerHPOrDie(playersao,
1057 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1060 SendPlayerBreath(playersao);
1066 Address addr = getPeerAddress(player->getPeerId());
1067 std::string ip_str = addr.serializeString();
1068 const std::vector<std::string> &names = m_clients.getPlayerNames();
1070 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1072 for (const std::string &name : names) {
1073 actionstream << name << " ";
1076 actionstream << player->getName() <<std::endl;
1081 inline void Server::handleCommand(NetworkPacket *pkt)
1083 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1084 (this->*opHandle.handler)(pkt);
1087 void Server::ProcessData(NetworkPacket *pkt)
1089 // Environment is locked first.
1090 MutexAutoLock envlock(m_env_mutex);
1092 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1093 u32 peer_id = pkt->getPeerId();
1096 Address address = getPeerAddress(peer_id);
1097 std::string addr_s = address.serializeString();
1099 if(m_banmanager->isIpBanned(addr_s)) {
1100 std::string ban_name = m_banmanager->getBanName(addr_s);
1101 infostream << "Server: A banned client tried to connect from "
1102 << addr_s << "; banned name was "
1103 << ban_name << std::endl;
1104 // This actually doesn't seem to transfer to the client
1105 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1106 + utf8_to_wide(ban_name));
1110 catch(con::PeerNotFoundException &e) {
1112 * no peer for this packet found
1113 * most common reason is peer timeout, e.g. peer didn't
1114 * respond for some time, your server was overloaded or
1117 infostream << "Server::ProcessData(): Canceling: peer "
1118 << peer_id << " not found" << std::endl;
1123 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1125 // Command must be handled into ToServerCommandHandler
1126 if (command >= TOSERVER_NUM_MSG_TYPES) {
1127 infostream << "Server: Ignoring unknown command "
1128 << command << std::endl;
1132 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1137 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1139 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1140 errorstream << "Server::ProcessData(): Cancelling: Peer"
1141 " serialization format invalid or not initialized."
1142 " Skipping incoming command=" << command << std::endl;
1146 /* Handle commands related to client startup */
1147 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1152 if (m_clients.getClientState(peer_id) < CS_Active) {
1153 if (command == TOSERVER_PLAYERPOS) return;
1155 errorstream << "Got packet command: " << command << " for peer id "
1156 << peer_id << " but client isn't active yet. Dropping packet "
1162 } catch (SendFailedException &e) {
1163 errorstream << "Server::ProcessData(): SendFailedException: "
1164 << "what=" << e.what()
1166 } catch (PacketError &e) {
1167 actionstream << "Server::ProcessData(): PacketError: "
1168 << "what=" << e.what()
1173 void Server::setTimeOfDay(u32 time)
1175 m_env->setTimeOfDay(time);
1176 m_time_of_day_send_timer = 0;
1179 void Server::onMapEditEvent(const MapEditEvent &event)
1181 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1184 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1187 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1189 std::vector<session_t> clients = m_clients.getClientIDs();
1191 // Set the modified blocks unsent for all the clients
1192 for (const session_t client_id : clients) {
1193 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1194 client->SetBlocksNotSent(block);
1199 void Server::peerAdded(con::Peer *peer)
1201 verbosestream<<"Server::peerAdded(): peer->id="
1202 <<peer->id<<std::endl;
1204 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1207 void Server::deletingPeer(con::Peer *peer, bool timeout)
1209 verbosestream<<"Server::deletingPeer(): peer->id="
1210 <<peer->id<<", timeout="<<timeout<<std::endl;
1212 m_clients.event(peer->id, CSE_Disconnect);
1213 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1216 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1218 *retval = m_con->getPeerStat(peer_id,type);
1219 return *retval != -1;
1222 bool Server::getClientInfo(
1231 std::string* vers_string,
1232 std::string* lang_code
1235 *state = m_clients.getClientState(peer_id);
1237 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1244 *uptime = client->uptime();
1245 *ser_vers = client->serialization_version;
1246 *prot_vers = client->net_proto_version;
1248 *major = client->getMajor();
1249 *minor = client->getMinor();
1250 *patch = client->getPatch();
1251 *vers_string = client->getFull();
1252 *lang_code = client->getLangCode();
1259 void Server::handlePeerChanges()
1261 while(!m_peer_change_queue.empty())
1263 con::PeerChange c = m_peer_change_queue.front();
1264 m_peer_change_queue.pop();
1266 verbosestream<<"Server: Handling peer change: "
1267 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1272 case con::PEER_ADDED:
1273 m_clients.CreateClient(c.peer_id);
1276 case con::PEER_REMOVED:
1277 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1281 FATAL_ERROR("Invalid peer change event received!");
1287 void Server::printToConsoleOnly(const std::string &text)
1290 m_admin_chat->outgoing_queue.push_back(
1291 new ChatEventChat("", utf8_to_wide(text)));
1293 std::cout << text << std::endl;
1297 void Server::Send(NetworkPacket *pkt)
1299 Send(pkt->getPeerId(), pkt);
1302 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1304 m_clients.send(peer_id,
1305 clientCommandFactoryTable[pkt->getCommand()].channel,
1307 clientCommandFactoryTable[pkt->getCommand()].reliable);
1310 void Server::SendMovement(session_t peer_id)
1312 std::ostringstream os(std::ios_base::binary);
1314 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1316 pkt << g_settings->getFloat("movement_acceleration_default");
1317 pkt << g_settings->getFloat("movement_acceleration_air");
1318 pkt << g_settings->getFloat("movement_acceleration_fast");
1319 pkt << g_settings->getFloat("movement_speed_walk");
1320 pkt << g_settings->getFloat("movement_speed_crouch");
1321 pkt << g_settings->getFloat("movement_speed_fast");
1322 pkt << g_settings->getFloat("movement_speed_climb");
1323 pkt << g_settings->getFloat("movement_speed_jump");
1324 pkt << g_settings->getFloat("movement_liquid_fluidity");
1325 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1326 pkt << g_settings->getFloat("movement_liquid_sink");
1327 pkt << g_settings->getFloat("movement_gravity");
1332 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1334 if (playersao->isImmortal())
1337 session_t peer_id = playersao->getPeerID();
1338 bool is_alive = playersao->getHP() > 0;
1341 SendPlayerHP(peer_id);
1343 DiePlayer(peer_id, reason);
1346 void Server::SendHP(session_t peer_id, u16 hp)
1348 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1353 void Server::SendBreath(session_t peer_id, u16 breath)
1355 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1356 pkt << (u16) breath;
1360 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1361 const std::string &custom_reason, bool reconnect)
1363 assert(reason < SERVER_ACCESSDENIED_MAX);
1365 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1367 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1368 pkt << custom_reason;
1369 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1370 reason == SERVER_ACCESSDENIED_CRASH)
1371 pkt << custom_reason << (u8)reconnect;
1375 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1377 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1382 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1383 v3f camera_point_target)
1385 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1386 pkt << set_camera_point_target << camera_point_target;
1390 void Server::SendItemDef(session_t peer_id,
1391 IItemDefManager *itemdef, u16 protocol_version)
1393 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1397 u32 length of the next item
1398 zlib-compressed serialized ItemDefManager
1400 std::ostringstream tmp_os(std::ios::binary);
1401 itemdef->serialize(tmp_os, protocol_version);
1402 std::ostringstream tmp_os2(std::ios::binary);
1403 compressZlib(tmp_os.str(), tmp_os2);
1404 pkt.putLongString(tmp_os2.str());
1407 verbosestream << "Server: Sending item definitions to id(" << peer_id
1408 << "): size=" << pkt.getSize() << std::endl;
1413 void Server::SendNodeDef(session_t peer_id,
1414 const NodeDefManager *nodedef, u16 protocol_version)
1416 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1420 u32 length of the next item
1421 zlib-compressed serialized NodeDefManager
1423 std::ostringstream tmp_os(std::ios::binary);
1424 nodedef->serialize(tmp_os, protocol_version);
1425 std::ostringstream tmp_os2(std::ios::binary);
1426 compressZlib(tmp_os.str(), tmp_os2);
1428 pkt.putLongString(tmp_os2.str());
1431 verbosestream << "Server: Sending node definitions to id(" << peer_id
1432 << "): size=" << pkt.getSize() << std::endl;
1438 Non-static send methods
1441 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1443 RemotePlayer *player = sao->getPlayer();
1445 // Do not send new format to old clients
1446 incremental &= player->protocol_version >= 38;
1448 UpdateCrafting(player);
1454 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1456 std::ostringstream os(std::ios::binary);
1457 sao->getInventory()->serialize(os, incremental);
1458 sao->getInventory()->setModified(false);
1459 player->setModified(true);
1461 const std::string &s = os.str();
1462 pkt.putRawString(s.c_str(), s.size());
1466 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1468 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1470 u8 type = message.type;
1471 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1473 if (peer_id != PEER_ID_INEXISTENT) {
1474 RemotePlayer *player = m_env->getPlayer(peer_id);
1480 m_clients.sendToAll(&pkt);
1484 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1485 const std::string &formname)
1487 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1488 if (formspec.empty()){
1489 //the client should close the formspec
1490 //but make sure there wasn't another one open in meantime
1491 const auto it = m_formspec_state_data.find(peer_id);
1492 if (it != m_formspec_state_data.end() && it->second == formname) {
1493 m_formspec_state_data.erase(peer_id);
1495 pkt.putLongString("");
1497 m_formspec_state_data[peer_id] = formname;
1498 pkt.putLongString(formspec);
1505 // Spawns a particle on peer with peer_id
1506 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1507 v3f pos, v3f velocity, v3f acceleration,
1508 float expirationtime, float size, bool collisiondetection,
1509 bool collision_removal, bool object_collision,
1510 bool vertical, const std::string &texture,
1511 const struct TileAnimationParams &animation, u8 glow)
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();
1519 for (const session_t client_id : clients) {
1520 RemotePlayer *player = m_env->getPlayer(client_id);
1524 PlayerSAO *sao = player->getPlayerSAO();
1528 // Do not send to distant clients
1529 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1532 SendSpawnParticle(client_id, player->protocol_version,
1533 pos, velocity, acceleration,
1534 expirationtime, size, collisiondetection, collision_removal,
1535 object_collision, vertical, texture, animation, glow);
1540 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1542 pkt << pos << velocity << acceleration << expirationtime
1543 << size << collisiondetection;
1544 pkt.putLongString(texture);
1546 pkt << collision_removal;
1547 // This is horrible but required (why are there two ways to serialize pkts?)
1548 std::ostringstream os(std::ios_base::binary);
1549 animation.serialize(os, protocol_version);
1550 pkt.putRawString(os.str());
1552 pkt << object_collision;
1557 // Adds a ParticleSpawner on peer with peer_id
1558 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1559 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1560 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1561 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1562 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1563 const struct TileAnimationParams &animation, u8 glow)
1565 if (peer_id == PEER_ID_INEXISTENT) {
1566 // This sucks and should be replaced:
1567 std::vector<session_t> clients = m_clients.getClientIDs();
1568 for (const session_t client_id : clients) {
1569 RemotePlayer *player = m_env->getPlayer(client_id);
1572 SendAddParticleSpawner(client_id, player->protocol_version,
1573 amount, spawntime, minpos, maxpos,
1574 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1575 minsize, maxsize, collisiondetection, collision_removal,
1576 object_collision, attached_id, vertical, texture, id,
1582 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1584 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1585 << minacc << maxacc << minexptime << maxexptime << minsize
1586 << maxsize << collisiondetection;
1588 pkt.putLongString(texture);
1590 pkt << id << vertical;
1591 pkt << collision_removal;
1593 // This is horrible but required
1594 std::ostringstream os(std::ios_base::binary);
1595 animation.serialize(os, protocol_version);
1596 pkt.putRawString(os.str());
1598 pkt << object_collision;
1603 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1605 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1607 // Ugly error in this packet
1610 if (peer_id != PEER_ID_INEXISTENT)
1613 m_clients.sendToAll(&pkt);
1617 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1619 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1621 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1622 << form->text << form->number << form->item << form->dir
1623 << form->align << form->offset << form->world_pos << form->size
1624 << form->z_index << form->text2;
1629 void Server::SendHUDRemove(session_t peer_id, u32 id)
1631 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1636 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1638 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1639 pkt << id << (u8) stat;
1643 case HUD_STAT_SCALE:
1644 case HUD_STAT_ALIGN:
1645 case HUD_STAT_OFFSET:
1646 pkt << *(v2f *) value;
1650 case HUD_STAT_TEXT2:
1651 pkt << *(std::string *) value;
1653 case HUD_STAT_WORLD_POS:
1654 pkt << *(v3f *) value;
1657 pkt << *(v2s32 *) value;
1659 case HUD_STAT_NUMBER:
1663 pkt << *(u32 *) value;
1670 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1672 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1674 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1676 pkt << flags << mask;
1681 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1683 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1684 pkt << param << value;
1688 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1690 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1692 // Handle prior clients here
1693 if (m_clients.getProtocolVersion(peer_id) < 39) {
1694 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1696 for (const std::string& texture : params.textures)
1699 pkt << params.clouds;
1700 } else { // Handle current clients and future clients
1701 pkt << params.bgcolor << params.type
1702 << params.clouds << params.fog_sun_tint
1703 << params.fog_moon_tint << params.fog_tint_type;
1705 if (params.type == "skybox") {
1706 pkt << (u16) params.textures.size();
1707 for (const std::string &texture : params.textures)
1709 } else if (params.type == "regular") {
1710 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1711 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1712 << params.sky_color.night_sky << params.sky_color.night_horizon
1713 << params.sky_color.indoors;
1720 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1722 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1723 pkt << params.visible << params.texture
1724 << params.tonemap << params.sunrise
1725 << params.sunrise_visible << params.scale;
1729 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1731 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1733 pkt << params.visible << params.texture
1734 << params.tonemap << params.scale;
1738 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1740 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1742 pkt << params.visible << params.count
1743 << params.starcolor << params.scale;
1748 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1750 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1751 pkt << params.density << params.color_bright << params.color_ambient
1752 << params.height << params.thickness << params.speed;
1756 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1759 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1762 pkt << do_override << (u16) (ratio * 65535);
1767 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1769 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1770 pkt << time << time_speed;
1772 if (peer_id == PEER_ID_INEXISTENT) {
1773 m_clients.sendToAll(&pkt);
1780 void Server::SendPlayerHP(session_t peer_id)
1782 PlayerSAO *playersao = getPlayerSAO(peer_id);
1785 SendHP(peer_id, playersao->getHP());
1786 m_script->player_event(playersao,"health_changed");
1788 // Send to other clients
1789 playersao->sendPunchCommand();
1792 void Server::SendPlayerBreath(PlayerSAO *sao)
1796 m_script->player_event(sao, "breath_changed");
1797 SendBreath(sao->getPeerID(), sao->getBreath());
1800 void Server::SendMovePlayer(session_t peer_id)
1802 RemotePlayer *player = m_env->getPlayer(peer_id);
1804 PlayerSAO *sao = player->getPlayerSAO();
1807 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1808 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1811 v3f pos = sao->getBasePosition();
1812 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1813 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1814 << " pitch=" << sao->getLookPitch()
1815 << " yaw=" << sao->getRotation().Y
1822 void Server::SendPlayerFov(session_t peer_id)
1824 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1826 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1827 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1832 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1833 f32 animation_speed)
1835 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1838 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1839 << animation_frames[3] << animation_speed;
1844 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1846 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1847 pkt << first << third;
1851 void Server::SendPlayerPrivileges(session_t peer_id)
1853 RemotePlayer *player = m_env->getPlayer(peer_id);
1855 if(player->getPeerId() == PEER_ID_INEXISTENT)
1858 std::set<std::string> privs;
1859 m_script->getAuth(player->getName(), NULL, &privs);
1861 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1862 pkt << (u16) privs.size();
1864 for (const std::string &priv : privs) {
1871 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1873 RemotePlayer *player = m_env->getPlayer(peer_id);
1875 if (player->getPeerId() == PEER_ID_INEXISTENT)
1878 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1879 pkt.putLongString(player->inventory_formspec);
1884 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1886 RemotePlayer *player = m_env->getPlayer(peer_id);
1888 if (player->getPeerId() == PEER_ID_INEXISTENT)
1891 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1892 pkt << player->formspec_prepend;
1896 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1898 // Radius inside which objects are active
1899 static thread_local const s16 radius =
1900 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1902 // Radius inside which players are active
1903 static thread_local const bool is_transfer_limited =
1904 g_settings->exists("unlimited_player_transfer_distance") &&
1905 !g_settings->getBool("unlimited_player_transfer_distance");
1907 static thread_local const s16 player_transfer_dist =
1908 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1910 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1911 radius : player_transfer_dist;
1913 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1917 std::queue<u16> removed_objects, added_objects;
1918 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1919 client->m_known_objects, removed_objects);
1920 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1921 client->m_known_objects, added_objects);
1923 int removed_count = removed_objects.size();
1924 int added_count = added_objects.size();
1926 if (removed_objects.empty() && added_objects.empty())
1932 // Handle removed objects
1933 writeU16((u8*)buf, removed_objects.size());
1934 data.append(buf, 2);
1935 while (!removed_objects.empty()) {
1937 u16 id = removed_objects.front();
1938 ServerActiveObject* obj = m_env->getActiveObject(id);
1940 // Add to data buffer for sending
1941 writeU16((u8*)buf, id);
1942 data.append(buf, 2);
1944 // Remove from known objects
1945 client->m_known_objects.erase(id);
1947 if (obj && obj->m_known_by_count > 0)
1948 obj->m_known_by_count--;
1950 removed_objects.pop();
1953 // Handle added objects
1954 writeU16((u8*)buf, added_objects.size());
1955 data.append(buf, 2);
1956 while (!added_objects.empty()) {
1958 u16 id = added_objects.front();
1959 ServerActiveObject *obj = m_env->getActiveObject(id);
1960 added_objects.pop();
1963 warningstream << FUNCTION_NAME << ": NULL object id="
1964 << (int)id << std::endl;
1969 u8 type = obj->getSendType();
1971 // Add to data buffer for sending
1972 writeU16((u8*)buf, id);
1973 data.append(buf, 2);
1974 writeU8((u8*)buf, type);
1975 data.append(buf, 1);
1977 data.append(serializeLongString(
1978 obj->getClientInitializationData(client->net_proto_version)));
1980 // Add to known objects
1981 client->m_known_objects.insert(id);
1983 obj->m_known_by_count++;
1986 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
1987 pkt.putRawString(data.c_str(), data.size());
1990 verbosestream << "Server::SendActiveObjectRemoveAdd: "
1991 << removed_count << " removed, " << added_count << " added, "
1992 << "packet size is " << pkt.getSize() << std::endl;
1995 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1998 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1999 datas.size(), peer_id);
2001 pkt.putRawString(datas.c_str(), datas.size());
2003 m_clients.send(pkt.getPeerId(),
2004 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2008 void Server::SendCSMRestrictionFlags(session_t peer_id)
2010 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2011 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2012 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2016 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2018 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2023 inline s32 Server::nextSoundId()
2025 s32 ret = m_next_sound_id;
2026 if (m_next_sound_id == INT32_MAX)
2027 m_next_sound_id = 0; // signed overflow is undefined
2033 s32 Server::playSound(const SimpleSoundSpec &spec,
2034 const ServerSoundParams ¶ms, bool ephemeral)
2036 // Find out initial position of sound
2037 bool pos_exists = false;
2038 v3f pos = params.getPos(m_env, &pos_exists);
2039 // If position is not found while it should be, cancel sound
2040 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2043 // Filter destination clients
2044 std::vector<session_t> dst_clients;
2045 if (!params.to_player.empty()) {
2046 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2048 infostream<<"Server::playSound: Player \""<<params.to_player
2049 <<"\" not found"<<std::endl;
2052 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2053 infostream<<"Server::playSound: Player \""<<params.to_player
2054 <<"\" not connected"<<std::endl;
2057 dst_clients.push_back(player->getPeerId());
2059 std::vector<session_t> clients = m_clients.getClientIDs();
2061 for (const session_t client_id : clients) {
2062 RemotePlayer *player = m_env->getPlayer(client_id);
2065 if (!params.exclude_player.empty() &&
2066 params.exclude_player == player->getName())
2069 PlayerSAO *sao = player->getPlayerSAO();
2074 if(sao->getBasePosition().getDistanceFrom(pos) >
2075 params.max_hear_distance)
2078 dst_clients.push_back(client_id);
2082 if(dst_clients.empty())
2087 ServerPlayingSound *psound = nullptr;
2089 id = -1; // old clients will still use this, so pick a reserved ID
2092 // The sound will exist as a reference in m_playing_sounds
2093 m_playing_sounds[id] = ServerPlayingSound();
2094 psound = &m_playing_sounds[id];
2095 psound->params = params;
2096 psound->spec = spec;
2099 float gain = params.gain * spec.gain;
2100 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2101 pkt << id << spec.name << gain
2102 << (u8) params.type << pos << params.object
2103 << params.loop << params.fade << params.pitch
2106 bool as_reliable = !ephemeral;
2108 for (const u16 dst_client : dst_clients) {
2110 psound->clients.insert(dst_client);
2111 m_clients.send(dst_client, 0, &pkt, as_reliable);
2115 void Server::stopSound(s32 handle)
2117 // Get sound reference
2118 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2119 m_playing_sounds.find(handle);
2120 if (i == m_playing_sounds.end())
2122 ServerPlayingSound &psound = i->second;
2124 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2127 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2128 si != psound.clients.end(); ++si) {
2130 m_clients.send(*si, 0, &pkt, true);
2132 // Remove sound reference
2133 m_playing_sounds.erase(i);
2136 void Server::fadeSound(s32 handle, float step, float gain)
2138 // Get sound reference
2139 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2140 m_playing_sounds.find(handle);
2141 if (i == m_playing_sounds.end())
2144 ServerPlayingSound &psound = i->second;
2145 psound.params.gain = gain;
2147 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2148 pkt << handle << step << gain;
2150 // Backwards compability
2151 bool play_sound = gain > 0;
2152 ServerPlayingSound compat_psound = psound;
2153 compat_psound.clients.clear();
2155 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2156 compat_pkt << handle;
2158 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2159 it != psound.clients.end();) {
2160 if (m_clients.getProtocolVersion(*it) >= 32) {
2162 m_clients.send(*it, 0, &pkt, true);
2165 compat_psound.clients.insert(*it);
2167 m_clients.send(*it, 0, &compat_pkt, true);
2168 psound.clients.erase(it++);
2172 // Remove sound reference
2173 if (!play_sound || psound.clients.empty())
2174 m_playing_sounds.erase(i);
2176 if (play_sound && !compat_psound.clients.empty()) {
2177 // Play new sound volume on older clients
2178 playSound(compat_psound.spec, compat_psound.params);
2182 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2185 float maxd = far_d_nodes * BS;
2186 v3f p_f = intToFloat(p, BS);
2187 v3s16 block_pos = getNodeBlockPos(p);
2189 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2192 std::vector<session_t> clients = m_clients.getClientIDs();
2195 for (session_t client_id : clients) {
2196 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2200 RemotePlayer *player = m_env->getPlayer(client_id);
2201 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2203 // If player is far away, only set modified blocks not sent
2204 if (!client->isBlockSent(block_pos) || (sao &&
2205 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2207 far_players->emplace(client_id);
2209 client->SetBlockNotSent(block_pos);
2214 m_clients.send(client_id, 0, &pkt, true);
2220 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2221 float far_d_nodes, bool remove_metadata)
2223 float maxd = far_d_nodes * BS;
2224 v3f p_f = intToFloat(p, BS);
2225 v3s16 block_pos = getNodeBlockPos(p);
2227 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2228 pkt << p << n.param0 << n.param1 << n.param2
2229 << (u8) (remove_metadata ? 0 : 1);
2231 std::vector<session_t> clients = m_clients.getClientIDs();
2234 for (session_t client_id : clients) {
2235 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2239 RemotePlayer *player = m_env->getPlayer(client_id);
2240 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2242 // If player is far away, only set modified blocks not sent
2243 if (!client->isBlockSent(block_pos) || (sao &&
2244 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2246 far_players->emplace(client_id);
2248 client->SetBlockNotSent(block_pos);
2253 m_clients.send(client_id, 0, &pkt, true);
2259 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2261 float maxd = far_d_nodes * BS;
2262 NodeMetadataList meta_updates_list(false);
2263 std::vector<session_t> clients = m_clients.getClientIDs();
2267 for (session_t i : clients) {
2268 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2272 ServerActiveObject *player = m_env->getActiveObject(i);
2273 v3f player_pos = player ? player->getBasePosition() : v3f();
2275 for (const v3s16 &pos : meta_updates) {
2276 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2281 v3s16 block_pos = getNodeBlockPos(pos);
2282 if (!client->isBlockSent(block_pos) || (player &&
2283 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2284 client->SetBlockNotSent(block_pos);
2288 // Add the change to send list
2289 meta_updates_list.set(pos, meta);
2291 if (meta_updates_list.size() == 0)
2294 // Send the meta changes
2295 std::ostringstream os(std::ios::binary);
2296 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2297 std::ostringstream oss(std::ios::binary);
2298 compressZlib(os.str(), oss);
2300 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2301 pkt.putLongString(oss.str());
2302 m_clients.send(i, 0, &pkt, true);
2304 meta_updates_list.clear();
2310 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2311 u16 net_proto_version)
2314 Create a packet with the block in the right format
2317 std::ostringstream os(std::ios_base::binary);
2318 block->serialize(os, ver, false);
2319 block->serializeNetworkSpecific(os);
2320 std::string s = os.str();
2322 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2324 pkt << block->getPos();
2325 pkt.putRawString(s.c_str(), s.size());
2329 void Server::SendBlocks(float dtime)
2331 MutexAutoLock envlock(m_env_mutex);
2332 //TODO check if one big lock could be faster then multiple small ones
2334 std::vector<PrioritySortedBlockTransfer> queue;
2336 u32 total_sending = 0;
2339 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2341 std::vector<session_t> clients = m_clients.getClientIDs();
2344 for (const session_t client_id : clients) {
2345 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2350 total_sending += client->getSendingCount();
2351 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2357 // Lowest priority number comes first.
2358 // Lowest is most important.
2359 std::sort(queue.begin(), queue.end());
2363 // Maximal total count calculation
2364 // The per-client block sends is halved with the maximal online users
2365 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2366 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2368 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2369 Map &map = m_env->getMap();
2371 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2372 if (total_sending >= max_blocks_to_send)
2375 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2379 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2384 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2385 client->net_proto_version);
2387 client->SentBlock(block_to_send.pos);
2393 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2395 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2400 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2401 if (!client || client->isBlockSent(blockpos)) {
2405 SendBlockNoLock(peer_id, block, client->serialization_version,
2406 client->net_proto_version);
2412 void Server::fillMediaCache()
2414 infostream<<"Server: Calculating media file checksums"<<std::endl;
2416 // Collect all media file paths
2417 std::vector<std::string> paths;
2418 m_modmgr->getModsMediaPaths(paths);
2419 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2420 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2422 // Collect media file information from paths into cache
2423 for (const std::string &mediapath : paths) {
2424 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2425 for (const fs::DirListNode &dln : dirlist) {
2426 if (dln.dir) // Ignode dirs
2428 std::string filename = dln.name;
2429 // If name contains illegal characters, ignore the file
2430 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2431 infostream<<"Server: ignoring illegal file name: \""
2432 << filename << "\"" << std::endl;
2435 // If name is not in a supported format, ignore it
2436 const char *supported_ext[] = {
2437 ".png", ".jpg", ".bmp", ".tga",
2438 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2440 ".x", ".b3d", ".md2", ".obj",
2441 // Custom translation file format
2445 if (removeStringEnd(filename, supported_ext).empty()){
2446 infostream << "Server: ignoring unsupported file extension: \""
2447 << filename << "\"" << std::endl;
2450 // Ok, attempt to load the file and add to cache
2451 std::string filepath;
2452 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2455 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2457 errorstream << "Server::fillMediaCache(): Could not open \""
2458 << filename << "\" for reading" << std::endl;
2461 std::ostringstream tmp_os(std::ios_base::binary);
2465 fis.read(buf, 1024);
2466 std::streamsize len = fis.gcount();
2467 tmp_os.write(buf, len);
2476 errorstream<<"Server::fillMediaCache(): Failed to read \""
2477 << filename << "\"" << std::endl;
2480 if(tmp_os.str().length() == 0) {
2481 errorstream << "Server::fillMediaCache(): Empty file \""
2482 << filepath << "\"" << std::endl;
2487 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2489 unsigned char *digest = sha1.getDigest();
2490 std::string sha1_base64 = base64_encode(digest, 20);
2491 std::string sha1_hex = hex_encode((char*)digest, 20);
2495 m_media[filename] = MediaInfo(filepath, sha1_base64);
2496 verbosestream << "Server: " << sha1_hex << " is " << filename
2502 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2505 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2508 std::string lang_suffix;
2509 lang_suffix.append(".").append(lang_code).append(".tr");
2510 for (const auto &i : m_media) {
2511 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2518 for (const auto &i : m_media) {
2519 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2521 pkt << i.first << i.second.sha1_digest;
2524 pkt << g_settings->get("remote_media");
2527 verbosestream << "Server: Announcing files to id(" << peer_id
2528 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2531 struct SendableMedia
2537 SendableMedia(const std::string &name_="", const std::string &path_="",
2538 const std::string &data_=""):
2545 void Server::sendRequestedMedia(session_t peer_id,
2546 const std::vector<std::string> &tosend)
2548 verbosestream<<"Server::sendRequestedMedia(): "
2549 <<"Sending files to client"<<std::endl;
2553 // Put 5kB in one bunch (this is not accurate)
2554 u32 bytes_per_bunch = 5000;
2556 std::vector< std::vector<SendableMedia> > file_bunches;
2557 file_bunches.emplace_back();
2559 u32 file_size_bunch_total = 0;
2561 for (const std::string &name : tosend) {
2562 if (m_media.find(name) == m_media.end()) {
2563 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2564 <<"unknown file \""<<(name)<<"\""<<std::endl;
2568 //TODO get path + name
2569 std::string tpath = m_media[name].path;
2572 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2574 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2575 <<tpath<<"\" for reading"<<std::endl;
2578 std::ostringstream tmp_os(std::ios_base::binary);
2582 fis.read(buf, 1024);
2583 std::streamsize len = fis.gcount();
2584 tmp_os.write(buf, len);
2585 file_size_bunch_total += len;
2594 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2595 <<name<<"\""<<std::endl;
2598 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2599 <<tname<<"\""<<std::endl;*/
2601 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2603 // Start next bunch if got enough data
2604 if(file_size_bunch_total >= bytes_per_bunch) {
2605 file_bunches.emplace_back();
2606 file_size_bunch_total = 0;
2611 /* Create and send packets */
2613 u16 num_bunches = file_bunches.size();
2614 for (u16 i = 0; i < num_bunches; i++) {
2617 u16 total number of texture bunches
2618 u16 index of this bunch
2619 u32 number of files in this bunch
2628 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2629 pkt << num_bunches << i << (u32) file_bunches[i].size();
2631 for (const SendableMedia &j : file_bunches[i]) {
2633 pkt.putLongString(j.data);
2636 verbosestream << "Server::sendRequestedMedia(): bunch "
2637 << i << "/" << num_bunches
2638 << " files=" << file_bunches[i].size()
2639 << " size=" << pkt.getSize() << std::endl;
2644 void Server::sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id)
2646 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2650 pkt << false; // Remove inventory
2652 pkt << true; // Update inventory
2654 // Serialization & NetworkPacket isn't a love story
2655 std::ostringstream os(std::ios_base::binary);
2656 inventory->serialize(os);
2657 inventory->setModified(false);
2659 const std::string &os_str = os.str();
2660 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2661 pkt.putRawString(os_str);
2664 if (peer_id == PEER_ID_INEXISTENT)
2665 m_clients.sendToAll(&pkt);
2670 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2672 // Lookup player name, to filter detached inventories just after
2673 std::string peer_name;
2674 if (peer_id != PEER_ID_INEXISTENT) {
2675 peer_name = getClient(peer_id, CS_Created)->getName();
2678 auto send_cb = [this, peer_id](const std::string &name, Inventory *inv) {
2679 sendDetachedInventory(inv, name, peer_id);
2682 m_inventory_mgr->sendDetachedInventories(peer_name, incremental, send_cb);
2689 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2691 PlayerSAO *playersao = getPlayerSAO(peer_id);
2694 infostream << "Server::DiePlayer(): Player "
2695 << playersao->getPlayer()->getName()
2696 << " dies" << std::endl;
2698 playersao->setHP(0, reason);
2699 playersao->clearParentAttachment();
2701 // Trigger scripted stuff
2702 m_script->on_dieplayer(playersao, reason);
2704 SendPlayerHP(peer_id);
2705 SendDeathscreen(peer_id, false, v3f(0,0,0));
2708 void Server::RespawnPlayer(session_t peer_id)
2710 PlayerSAO *playersao = getPlayerSAO(peer_id);
2713 infostream << "Server::RespawnPlayer(): Player "
2714 << playersao->getPlayer()->getName()
2715 << " respawns" << std::endl;
2717 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2718 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2719 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2721 bool repositioned = m_script->on_respawnplayer(playersao);
2722 if (!repositioned) {
2723 // setPos will send the new position to client
2724 playersao->setPos(findSpawnPos());
2727 SendPlayerHP(peer_id);
2731 void Server::DenySudoAccess(session_t peer_id)
2733 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2738 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2739 const std::string &str_reason, bool reconnect)
2741 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2743 m_clients.event(peer_id, CSE_SetDenied);
2744 DisconnectPeer(peer_id);
2748 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2749 const std::string &custom_reason)
2751 SendAccessDenied(peer_id, reason, custom_reason);
2752 m_clients.event(peer_id, CSE_SetDenied);
2753 DisconnectPeer(peer_id);
2756 // 13/03/15: remove this function when protocol version 25 will become
2757 // the minimum version for MT users, maybe in 1 year
2758 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2760 SendAccessDenied_Legacy(peer_id, reason);
2761 m_clients.event(peer_id, CSE_SetDenied);
2762 DisconnectPeer(peer_id);
2765 void Server::DisconnectPeer(session_t peer_id)
2767 m_modchannel_mgr->leaveAllChannels(peer_id);
2768 m_con->DisconnectPeer(peer_id);
2771 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2774 RemoteClient* client = getClient(peer_id, CS_Invalid);
2776 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2778 // Right now, the auth mechs don't change between login and sudo mode.
2779 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2780 client->allowed_sudo_mechs = sudo_auth_mechs;
2782 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2783 << g_settings->getFloat("dedicated_server_step")
2787 m_clients.event(peer_id, CSE_AuthAccept);
2789 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2791 // We only support SRP right now
2792 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2794 resp_pkt << sudo_auth_mechs;
2796 m_clients.event(peer_id, CSE_SudoSuccess);
2800 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2802 std::wstring message;
2805 Clear references to playing sounds
2807 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2808 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2809 ServerPlayingSound &psound = i->second;
2810 psound.clients.erase(peer_id);
2811 if (psound.clients.empty())
2812 m_playing_sounds.erase(i++);
2817 // clear formspec info so the next client can't abuse the current state
2818 m_formspec_state_data.erase(peer_id);
2820 RemotePlayer *player = m_env->getPlayer(peer_id);
2822 /* Run scripts and remove from environment */
2824 PlayerSAO *playersao = player->getPlayerSAO();
2827 playersao->clearChildAttachments();
2828 playersao->clearParentAttachment();
2830 // inform connected clients
2831 const std::string &player_name = player->getName();
2832 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2833 // (u16) 1 + std::string represents a vector serialization representation
2834 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2835 m_clients.sendToAll(¬ice);
2837 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2839 playersao->disconnected();
2846 if (player && reason != CDR_DENY) {
2847 std::ostringstream os(std::ios_base::binary);
2848 std::vector<session_t> clients = m_clients.getClientIDs();
2850 for (const session_t client_id : clients) {
2852 RemotePlayer *player = m_env->getPlayer(client_id);
2856 // Get name of player
2857 os << player->getName() << " ";
2860 std::string name = player->getName();
2861 actionstream << name << " "
2862 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2863 << " List of players: " << os.str() << std::endl;
2865 m_admin_chat->outgoing_queue.push_back(
2866 new ChatEventNick(CET_NICK_REMOVE, name));
2870 MutexAutoLock env_lock(m_env_mutex);
2871 m_clients.DeleteClient(peer_id);
2875 // Send leave chat message to all remaining clients
2876 if (!message.empty()) {
2877 SendChatMessage(PEER_ID_INEXISTENT,
2878 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2882 void Server::UpdateCrafting(RemotePlayer *player)
2884 InventoryList *clist = player->inventory.getList("craft");
2885 if (!clist || clist->getSize() == 0)
2888 if (!clist->checkModified())
2891 // Get a preview for crafting
2893 InventoryLocation loc;
2894 loc.setPlayer(player->getName());
2895 std::vector<ItemStack> output_replacements;
2896 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2897 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2900 InventoryList *plist = player->inventory.getList("craftpreview");
2901 if (plist && plist->getSize() >= 1) {
2902 // Put the new preview in
2903 plist->changeItem(0, preview);
2907 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2909 if (evt->type == CET_NICK_ADD) {
2910 // The terminal informed us of its nick choice
2911 m_admin_nick = ((ChatEventNick *)evt)->nick;
2912 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2913 errorstream << "You haven't set up an account." << std::endl
2914 << "Please log in using the client as '"
2915 << m_admin_nick << "' with a secure password." << std::endl
2916 << "Until then, you can't execute admin tasks via the console," << std::endl
2917 << "and everybody can claim the user account instead of you," << std::endl
2918 << "giving them full control over this server." << std::endl;
2921 assert(evt->type == CET_CHAT);
2922 handleAdminChat((ChatEventChat *)evt);
2926 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2927 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2929 // If something goes wrong, this player is to blame
2930 RollbackScopeActor rollback_scope(m_rollback,
2931 std::string("player:") + name);
2933 if (g_settings->getBool("strip_color_codes"))
2934 wmessage = unescape_enriched(wmessage);
2937 switch (player->canSendChatMessage()) {
2938 case RPLAYER_CHATRESULT_FLOODING: {
2939 std::wstringstream ws;
2940 ws << L"You cannot send more messages. You are limited to "
2941 << g_settings->getFloat("chat_message_limit_per_10sec")
2942 << L" messages per 10 seconds.";
2945 case RPLAYER_CHATRESULT_KICK:
2946 DenyAccess_Legacy(player->getPeerId(),
2947 L"You have been kicked due to message flooding.");
2949 case RPLAYER_CHATRESULT_OK:
2952 FATAL_ERROR("Unhandled chat filtering result found.");
2956 if (m_max_chatmessage_length > 0
2957 && wmessage.length() > m_max_chatmessage_length) {
2958 return L"Your message exceed the maximum chat message limit set on the server. "
2959 L"It was refused. Send a shorter message";
2962 auto message = trim(wide_to_utf8(wmessage));
2963 if (message.find_first_of("\n\r") != std::wstring::npos) {
2964 return L"New lines are not permitted in chat messages";
2967 // Run script hook, exit if script ate the chat message
2968 if (m_script->on_chat_message(name, message))
2973 // Whether to send line to the player that sent the message, or to all players
2974 bool broadcast_line = true;
2976 if (check_shout_priv && !checkPriv(name, "shout")) {
2977 line += L"-!- You don't have permission to shout.";
2978 broadcast_line = false;
2981 Workaround for fixing chat on Android. Lua doesn't handle
2982 the Cyrillic alphabet and some characters on older Android devices
2985 line += L"<" + wname + L"> " + wmessage;
2987 line += narrow_to_wide(m_script->formatChatMessage(name,
2988 wide_to_narrow(wmessage)));
2993 Tell calling method to send the message to sender
2995 if (!broadcast_line)
2999 Send the message to others
3001 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
3003 std::vector<session_t> clients = m_clients.getClientIDs();
3006 Send the message back to the inital sender
3007 if they are using protocol version >= 29
3010 session_t peer_id_to_avoid_sending =
3011 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
3013 if (player && player->protocol_version >= 29)
3014 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
3016 for (u16 cid : clients) {
3017 if (cid != peer_id_to_avoid_sending)
3018 SendChatMessage(cid, ChatMessage(line));
3023 void Server::handleAdminChat(const ChatEventChat *evt)
3025 std::string name = evt->nick;
3026 std::wstring wname = utf8_to_wide(name);
3027 std::wstring wmessage = evt->evt_msg;
3029 std::wstring answer = handleChat(name, wname, wmessage);
3031 // If asked to send answer to sender
3032 if (!answer.empty()) {
3033 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3037 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3039 RemoteClient *client = getClientNoEx(peer_id,state_min);
3041 throw ClientNotFoundException("Client not found");
3045 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3047 return m_clients.getClientNoEx(peer_id, state_min);
3050 std::string Server::getPlayerName(session_t peer_id)
3052 RemotePlayer *player = m_env->getPlayer(peer_id);
3054 return "[id="+itos(peer_id)+"]";
3055 return player->getName();
3058 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3060 RemotePlayer *player = m_env->getPlayer(peer_id);
3063 return player->getPlayerSAO();
3066 std::wstring Server::getStatusString()
3068 std::wostringstream os(std::ios_base::binary);
3069 os << L"# Server: ";
3071 os << L"version=" << narrow_to_wide(g_version_string);
3073 os << L", uptime=" << m_uptime_counter->get();
3075 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3077 // Information about clients
3079 os << L", clients={";
3081 std::vector<session_t> clients = m_clients.getClientIDs();
3082 for (session_t client_id : clients) {
3083 RemotePlayer *player = m_env->getPlayer(client_id);
3085 // Get name of player
3086 std::wstring name = L"unknown";
3088 name = narrow_to_wide(player->getName());
3090 // Add name to information string
3101 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3102 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3104 if (!g_settings->get("motd").empty())
3105 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3110 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3112 std::set<std::string> privs;
3113 m_script->getAuth(name, NULL, &privs);
3117 bool Server::checkPriv(const std::string &name, const std::string &priv)
3119 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3120 return (privs.count(priv) != 0);
3123 void Server::reportPrivsModified(const std::string &name)
3126 std::vector<session_t> clients = m_clients.getClientIDs();
3127 for (const session_t client_id : clients) {
3128 RemotePlayer *player = m_env->getPlayer(client_id);
3129 reportPrivsModified(player->getName());
3132 RemotePlayer *player = m_env->getPlayer(name.c_str());
3135 SendPlayerPrivileges(player->getPeerId());
3136 PlayerSAO *sao = player->getPlayerSAO();
3139 sao->updatePrivileges(
3140 getPlayerEffectivePrivs(name),
3145 void Server::reportInventoryFormspecModified(const std::string &name)
3147 RemotePlayer *player = m_env->getPlayer(name.c_str());
3150 SendPlayerInventoryFormspec(player->getPeerId());
3153 void Server::reportFormspecPrependModified(const std::string &name)
3155 RemotePlayer *player = m_env->getPlayer(name.c_str());
3158 SendPlayerFormspecPrepend(player->getPeerId());
3161 void Server::setIpBanned(const std::string &ip, const std::string &name)
3163 m_banmanager->add(ip, name);
3166 void Server::unsetIpBanned(const std::string &ip_or_name)
3168 m_banmanager->remove(ip_or_name);
3171 std::string Server::getBanDescription(const std::string &ip_or_name)
3173 return m_banmanager->getBanDescription(ip_or_name);
3176 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3178 // m_env will be NULL if the server is initializing
3182 if (m_admin_nick == name && !m_admin_nick.empty()) {
3183 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3186 RemotePlayer *player = m_env->getPlayer(name);
3191 if (player->getPeerId() == PEER_ID_INEXISTENT)
3194 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3197 bool Server::showFormspec(const char *playername, const std::string &formspec,
3198 const std::string &formname)
3200 // m_env will be NULL if the server is initializing
3204 RemotePlayer *player = m_env->getPlayer(playername);
3208 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3212 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3217 u32 id = player->addHud(form);
3219 SendHUDAdd(player->getPeerId(), id, form);
3224 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3228 HudElement* todel = player->removeHud(id);
3235 SendHUDRemove(player->getPeerId(), id);
3239 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3244 SendHUDChange(player->getPeerId(), id, stat, data);
3248 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3253 SendHUDSetFlags(player->getPeerId(), flags, mask);
3254 player->hud_flags &= ~mask;
3255 player->hud_flags |= flags;
3257 PlayerSAO* playersao = player->getPlayerSAO();
3262 m_script->player_event(playersao, "hud_changed");
3266 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3271 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3274 player->setHotbarItemcount(hotbar_itemcount);
3275 std::ostringstream os(std::ios::binary);
3276 writeS32(os, hotbar_itemcount);
3277 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3281 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3286 player->setHotbarImage(name);
3287 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3290 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3295 player->setHotbarSelectedImage(name);
3296 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3299 Address Server::getPeerAddress(session_t peer_id)
3301 return m_con->GetPeerAddress(peer_id);
3304 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3305 v2s32 animation_frames[4], f32 frame_speed)
3307 sanity_check(player);
3308 player->setLocalAnimations(animation_frames, frame_speed);
3309 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3312 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3314 sanity_check(player);
3315 player->eye_offset_first = first;
3316 player->eye_offset_third = third;
3317 SendEyeOffset(player->getPeerId(), first, third);
3320 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3322 sanity_check(player);
3323 player->setSky(params);
3324 SendSetSky(player->getPeerId(), params);
3327 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3329 sanity_check(player);
3330 player->setSun(params);
3331 SendSetSun(player->getPeerId(), params);
3334 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3336 sanity_check(player);
3337 player->setMoon(params);
3338 SendSetMoon(player->getPeerId(), params);
3341 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3343 sanity_check(player);
3344 player->setStars(params);
3345 SendSetStars(player->getPeerId(), params);
3348 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3350 sanity_check(player);
3351 player->setCloudParams(params);
3352 SendCloudParams(player->getPeerId(), params);
3355 void Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3358 sanity_check(player);
3359 player->overrideDayNightRatio(do_override, ratio);
3360 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3363 void Server::notifyPlayers(const std::wstring &msg)
3365 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3368 void Server::spawnParticle(const std::string &playername, v3f pos,
3369 v3f velocity, v3f acceleration,
3370 float expirationtime, float size, bool
3371 collisiondetection, bool collision_removal, bool object_collision,
3372 bool vertical, const std::string &texture,
3373 const struct TileAnimationParams &animation, u8 glow)
3375 // m_env will be NULL if the server is initializing
3379 session_t peer_id = PEER_ID_INEXISTENT;
3381 if (!playername.empty()) {
3382 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3385 peer_id = player->getPeerId();
3386 proto_ver = player->protocol_version;
3389 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3390 expirationtime, size, collisiondetection, collision_removal,
3391 object_collision, vertical, texture, animation, glow);
3394 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3395 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3396 float minexptime, float maxexptime, float minsize, float maxsize,
3397 bool collisiondetection, bool collision_removal, bool object_collision,
3398 ServerActiveObject *attached, bool vertical, const std::string &texture,
3399 const std::string &playername, const struct TileAnimationParams &animation,
3402 // m_env will be NULL if the server is initializing
3406 session_t peer_id = PEER_ID_INEXISTENT;
3408 if (!playername.empty()) {
3409 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3412 peer_id = player->getPeerId();
3413 proto_ver = player->protocol_version;
3416 u16 attached_id = attached ? attached->getId() : 0;
3419 if (attached_id == 0)
3420 id = m_env->addParticleSpawner(spawntime);
3422 id = m_env->addParticleSpawner(spawntime, attached_id);
3424 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3425 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3426 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3427 collision_removal, object_collision, attached_id, vertical,
3428 texture, id, animation, glow);
3433 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3435 // m_env will be NULL if the server is initializing
3437 throw ServerError("Can't delete particle spawners during initialisation!");
3439 session_t peer_id = PEER_ID_INEXISTENT;
3440 if (!playername.empty()) {
3441 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3444 peer_id = player->getPeerId();
3447 m_env->deleteParticleSpawner(id);
3448 SendDeleteParticleSpawner(peer_id, id);
3451 // actions: time-reversed list
3452 // Return value: success/failure
3453 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3454 std::list<std::string> *log)
3456 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3457 ServerMap *map = (ServerMap*)(&m_env->getMap());
3459 // Fail if no actions to handle
3460 if (actions.empty()) {
3462 log->push_back("Nothing to do.");
3469 for (const RollbackAction &action : actions) {
3471 bool success = action.applyRevert(map, m_inventory_mgr.get(), this);
3474 std::ostringstream os;
3475 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3476 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3478 log->push_back(os.str());
3480 std::ostringstream os;
3481 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3482 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3484 log->push_back(os.str());
3488 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3489 <<" failed"<<std::endl;
3491 // Call it done if less than half failed
3492 return num_failed <= num_tried/2;
3495 // IGameDef interface
3497 IItemDefManager *Server::getItemDefManager()
3502 const NodeDefManager *Server::getNodeDefManager()
3507 ICraftDefManager *Server::getCraftDefManager()
3512 u16 Server::allocateUnknownNodeId(const std::string &name)
3514 return m_nodedef->allocateDummy(name);
3517 IWritableItemDefManager *Server::getWritableItemDefManager()
3522 NodeDefManager *Server::getWritableNodeDefManager()
3527 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3532 const std::vector<ModSpec> & Server::getMods() const
3534 return m_modmgr->getMods();
3537 const ModSpec *Server::getModSpec(const std::string &modname) const
3539 return m_modmgr->getModSpec(modname);
3542 void Server::getModNames(std::vector<std::string> &modlist)
3544 m_modmgr->getModNames(modlist);
3547 std::string Server::getBuiltinLuaPath()
3549 return porting::path_share + DIR_DELIM + "builtin";
3552 std::string Server::getModStoragePath() const
3554 return m_path_world + DIR_DELIM + "mod_storage";
3557 v3f Server::findSpawnPos()
3559 ServerMap &map = m_env->getServerMap();
3561 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3562 return nodeposf * BS;
3564 bool is_good = false;
3565 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3566 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3568 // Try to find a good place a few times
3569 for (s32 i = 0; i < 4000 && !is_good; i++) {
3570 s32 range = MYMIN(1 + i, range_max);
3571 // We're going to try to throw the player to this position
3572 v2s16 nodepos2d = v2s16(
3573 -range + (myrand() % (range * 2)),
3574 -range + (myrand() % (range * 2)));
3575 // Get spawn level at point
3576 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3577 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3578 // signify an unsuitable spawn position, or if outside limits.
3579 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3580 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3583 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3584 // Consecutive empty nodes
3587 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3588 // avoid obstructions in already-generated mapblocks.
3589 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3590 // no obstructions, but mapgen decorations are generated after spawn so
3591 // the player may end up inside one.
3592 for (s32 i = 0; i < 8; i++) {
3593 v3s16 blockpos = getNodeBlockPos(nodepos);
3594 map.emergeBlock(blockpos, true);
3595 content_t c = map.getNode(nodepos).getContent();
3597 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3598 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3599 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3601 if (air_count >= 2) {
3602 // Spawn in lower empty node
3604 nodeposf = intToFloat(nodepos, BS);
3605 // Don't spawn the player outside map boundaries
3606 if (objectpos_over_limit(nodeposf))
3607 // Exit this loop, positions above are probably over limit
3610 // Good position found, cause an exit from main loop
3624 // No suitable spawn point found, return fallback 0,0,0
3625 return v3f(0.0f, 0.0f, 0.0f);
3628 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3630 if (delay == 0.0f) {
3631 // No delay, shutdown immediately
3632 m_shutdown_state.is_requested = true;
3633 // only print to the infostream, a chat message saying
3634 // "Server Shutting Down" is sent when the server destructs.
3635 infostream << "*** Immediate Server shutdown requested." << std::endl;
3636 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3637 // Negative delay, cancel shutdown if requested
3638 m_shutdown_state.reset();
3639 std::wstringstream ws;
3641 ws << L"*** Server shutdown canceled.";
3643 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3644 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3645 // m_shutdown_* are already handled, skip.
3647 } else if (delay > 0.0f) {
3648 // Positive delay, tell the clients when the server will shut down
3649 std::wstringstream ws;
3651 ws << L"*** Server shutting down in "
3652 << duration_to_string(myround(delay)).c_str()
3655 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3656 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3659 m_shutdown_state.trigger(delay, msg, reconnect);
3662 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3665 Try to get an existing player
3667 RemotePlayer *player = m_env->getPlayer(name);
3669 // If player is already connected, cancel
3670 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3671 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3676 If player with the wanted peer_id already exists, cancel.
3678 if (m_env->getPlayer(peer_id)) {
3679 infostream<<"emergePlayer(): Player with wrong name but same"
3680 " peer_id already exists"<<std::endl;
3685 player = new RemotePlayer(name, idef());
3688 bool newplayer = false;
3691 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3693 // Complete init with server parts
3694 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3695 player->protocol_version = proto_version;
3699 m_script->on_newplayer(playersao);
3705 bool Server::registerModStorage(ModMetadata *storage)
3707 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3708 errorstream << "Unable to register same mod storage twice. Storage name: "
3709 << storage->getModName() << std::endl;
3713 m_mod_storages[storage->getModName()] = storage;
3717 void Server::unregisterModStorage(const std::string &name)
3719 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3720 if (it != m_mod_storages.end()) {
3721 // Save unconditionaly on unregistration
3722 it->second->save(getModStoragePath());
3723 m_mod_storages.erase(name);
3727 void dedicated_server_loop(Server &server, bool &kill)
3729 verbosestream<<"dedicated_server_loop()"<<std::endl;
3731 IntervalLimiter m_profiler_interval;
3733 static thread_local const float steplen =
3734 g_settings->getFloat("dedicated_server_step");
3735 static thread_local const float profiler_print_interval =
3736 g_settings->getFloat("profiler_print_interval");
3739 * The dedicated server loop only does time-keeping (in Server::step) and
3740 * provides a way to main.cpp to kill the server externally (bool &kill).
3744 // This is kind of a hack but can be done like this
3745 // because server.step() is very light
3746 sleep_ms((int)(steplen*1000.0));
3747 server.step(steplen);
3749 if (server.isShutdownRequested() || kill)
3755 if (profiler_print_interval != 0) {
3756 if(m_profiler_interval.step(steplen, profiler_print_interval))
3758 infostream<<"Profiler:"<<std::endl;
3759 g_profiler->print(infostream);
3760 g_profiler->clear();
3765 infostream << "Dedicated server quitting" << std::endl;
3767 if (g_settings->getBool("server_announce"))
3768 ServerList::sendAnnounce(ServerList::AA_DELETE,
3769 server.m_bind_addr.getPort());
3778 bool Server::joinModChannel(const std::string &channel)
3780 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3781 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3784 bool Server::leaveModChannel(const std::string &channel)
3786 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3789 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3791 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3794 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3798 ModChannel* Server::getModChannel(const std::string &channel)
3800 return m_modchannel_mgr->getModChannel(channel);
3803 void Server::broadcastModChannelMessage(const std::string &channel,
3804 const std::string &message, session_t from_peer)
3806 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3810 if (message.size() > STRING_MAX_LEN) {
3811 warningstream << "ModChannel message too long, dropping before sending "
3812 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3813 << channel << ")" << std::endl;
3818 if (from_peer != PEER_ID_SERVER) {
3819 sender = getPlayerName(from_peer);
3822 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3823 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3824 resp_pkt << channel << sender << message;
3825 for (session_t peer_id : peers) {
3827 if (peer_id == from_peer)
3830 Send(peer_id, &resp_pkt);
3833 if (from_peer != PEER_ID_SERVER) {
3834 m_script->on_modchannel_message(channel, sender, message);
3838 void Server::loadTranslationLanguage(const std::string &lang_code)
3840 if (g_server_translations->count(lang_code))
3841 return; // Already loaded
3843 std::string suffix = "." + lang_code + ".tr";
3844 for (const auto &i : m_media) {
3845 if (str_ends_with(i.first, suffix)) {
3846 std::ifstream t(i.second.path);
3847 std::string data((std::istreambuf_iterator<char>(t)),
3848 std::istreambuf_iterator<char>());
3850 (*g_server_translations)[lang_code].loadTranslation(data);