diff --git a/config.lua.dist b/config.lua.dist index 65adee897b..23e5571b88 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -20,6 +20,7 @@ expFromPlayersLevelRange = 75 -- NOTE: maxPlayers set to 0 means no limit -- NOTE: allowWalkthrough is only applicable to players -- NOTE: two-factor auth requires token and timestamp in session key +-- NOTE: statusCountMaxPlayersPerIp allows you to only count up to X players per IP in status response (0 = disabled) ip = "127.0.0.1" bindOnlyGlobalAddress = false loginProtocolPort = 7171 @@ -33,6 +34,7 @@ allowClones = false allowWalkthrough = true serverName = "Forgotten" statusTimeout = 5000 +statusCountMaxPlayersPerIp = 0 replaceKickOnLogin = true maxPacketsPerSecond = 25 enableTwoFactorAuth = true diff --git a/src/configmanager.cpp b/src/configmanager.cpp index 14c0731aa3..047cf43158 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -272,6 +272,7 @@ bool ConfigManager::load() integer[PROTECTION_LEVEL] = getGlobalNumber(L, "protectionLevel", 1); integer[DEATH_LOSE_PERCENT] = getGlobalNumber(L, "deathLosePercent", -1); integer[STATUSQUERY_TIMEOUT] = getGlobalNumber(L, "statusTimeout", 5000); + integer[STATUS_COUNT_MAX_PLAYERS_PER_IP] = getGlobalNumber(L, "statusCountMaxPlayersPerIp", 0); integer[FRAG_TIME] = getGlobalNumber(L, "timeToDecreaseFrags", 24 * 60 * 60); integer[WHITE_SKULL_TIME] = getGlobalNumber(L, "whiteSkullTime", 15 * 60); integer[STAIRHOP_DELAY] = getGlobalNumber(L, "stairJumpExhaustion", 2000); diff --git a/src/configmanager.h b/src/configmanager.h index 2ee4541304..0b7d1e7386 100644 --- a/src/configmanager.h +++ b/src/configmanager.h @@ -98,6 +98,7 @@ enum integer_config_t PROTECTION_LEVEL, DEATH_LOSE_PERCENT, STATUSQUERY_TIMEOUT, + STATUS_COUNT_MAX_PLAYERS_PER_IP, FRAG_TIME, WHITE_SKULL_TIME, GAME_PORT, diff --git a/src/protocolstatus.cpp b/src/protocolstatus.cpp index e8434a3c35..064c1a5dfb 100644 --- a/src/protocolstatus.cpp +++ b/src/protocolstatus.cpp @@ -9,6 +9,8 @@ #include "game.h" #include "outputmessage.h" +#include + extern Game g_game; std::map ProtocolStatus::ipConnectMap; @@ -104,7 +106,25 @@ void ProtocolStatus::sendStatusString() owner.append_attribute("email") = getString(ConfigManager::OWNER_EMAIL).c_str(); pugi::xml_node players = tsqp.append_child("players"); - players.append_attribute("online") = std::to_string(g_game.getPlayersOnline()).c_str(); + + uint32_t reportableOnlinePlayerCount = 0; + uint32_t maxPlayersPerIp = getNumber(ConfigManager::STATUS_COUNT_MAX_PLAYERS_PER_IP); + if (maxPlayersPerIp > 0) { + std::map playersPerIp; + for (const auto& it : g_game.getPlayers()) { + if (!it.second->getIP().is_unspecified()) { + ++playersPerIp[it.second->getIP()]; + } + } + + for (auto& p : playersPerIp | std::views::values) { + reportableOnlinePlayerCount += std::min(p, maxPlayersPerIp); + } + } else { + reportableOnlinePlayerCount = g_game.getPlayersOnline(); + } + + players.append_attribute("online") = std::to_string(reportableOnlinePlayerCount).c_str(); players.append_attribute("max") = std::to_string(getNumber(ConfigManager::MAX_PLAYERS)).c_str(); players.append_attribute("peak") = std::to_string(g_game.getPlayersRecord()).c_str();