From 83921257a6c550273e73e715fb899a0fb7db76ab Mon Sep 17 00:00:00 2001
From: kimden <23140380+kimden@users.noreply.github.com>
Date: Thu, 29 Jan 2026 23:27:10 +0400
Subject: [PATCH] Add must-have-karts and similar
---
NETWORKING.md | 6 ++++++
src/network/server_config.hpp | 10 ++++++++++
src/utils/lobby_asset_manager.cpp | 31 +++++++++++++++++++++++++++++--
src/utils/lobby_asset_manager.hpp | 3 +++
4 files changed, 48 insertions(+), 2 deletions(-)
diff --git a/NETWORKING.md b/NETWORKING.md
index db98d3bc752..a3f096b72fc 100644
--- a/NETWORKING.md
+++ b/NETWORKING.md
@@ -148,9 +148,15 @@ A typical current server configuration xml that fits the current code version is
+
+
+
+
+
+
diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp
index d1d0097e5bf..f73368c12ed 100644
--- a/src/network/server_config.hpp
+++ b/src/network/server_config.hpp
@@ -296,11 +296,21 @@ namespace ServerConfig
"Clients below this value will be rejected from playing games. "
"It's determined by number of addon soccer fields in client"));
+ SERVER_CFG_PREFIX StringServerConfigParam m_must_have_karts_string
+ SERVER_CFG_DEFAULT(StringServerConfigParam("",
+ "must-have-karts", "Karts needed to enter the server, "
+ "leave empty for no restriction."));
+
SERVER_CFG_PREFIX StringServerConfigParam m_must_have_tracks_string
SERVER_CFG_DEFAULT(StringServerConfigParam("",
"must-have-tracks", "Tracks needed to enter the server, "
"leave empty for no restriction."));
+ SERVER_CFG_PREFIX StringServerConfigParam m_play_requirement_karts_string
+ SERVER_CFG_DEFAULT(StringServerConfigParam("",
+ "play-requirement-karts", "Karts needed to be able to play, "
+ "leave empty for no restriction."));
+
SERVER_CFG_PREFIX StringServerConfigParam m_play_requirement_tracks_string
SERVER_CFG_DEFAULT(StringServerConfigParam("",
"play-requirement-tracks", "Tracks needed to be able to play, "
diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp
index 5bf11455736..e23abbcb2da 100644
--- a/src/utils/lobby_asset_manager.cpp
+++ b/src/utils/lobby_asset_manager.cpp
@@ -376,8 +376,20 @@ bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer,
bool bad = false;
+ bool has_required_karts = true;
+ for (const std::string& required_kart: m_must_have_karts)
+ {
+ if (client_karts.find(required_kart) == client_karts.end())
+ {
+ has_required_karts = false;
+ bad = true;
+ Log::verbose("LobbyAssetManager", "Player does not have a required kart '%s'.", required_kart.c_str());
+ break;
+ }
+ }
+
bool has_required_tracks = true;
- for (const std::string& required_track : m_must_have_maps)
+ for (const std::string& required_track: m_must_have_maps)
{
if (client_tracks.find(required_track) == client_tracks.end())
{
@@ -578,6 +590,12 @@ std::string LobbyAssetManager::getRandomAddonMap() const
} // getRandomAddonMap
//-----------------------------------------------------------------------------
+void LobbyAssetManager::setMustHaveKarts(const std::string& input)
+{
+ m_must_have_karts = StringUtils::split(input, ' ', false);
+} // setMustHaveKarts
+//-----------------------------------------------------------------------------
+
void LobbyAssetManager::setMustHaveMaps(const std::string& input)
{
m_must_have_maps = StringUtils::split(input, ' ', false);
@@ -736,19 +754,28 @@ void LobbyAssetManager::initAvailableTracks()
{
m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string);
m_global_karts_filter = KartFilter(ServerConfig::m_only_played_karts_string);
+ setMustHaveKarts(ServerConfig::m_must_have_karts_string);
setMustHaveMaps(ServerConfig::m_must_have_tracks_string);
+ m_play_requirement_karts = StringUtils::split(
+ ServerConfig::m_play_requirement_karts_string, ' ', false);
m_play_requirement_tracks = StringUtils::split(
ServerConfig::m_play_requirement_tracks_string, ' ', false);
} // initAvailableTracks
//-----------------------------------------------------------------------------
+// Initially it was only for maps, but for the current purposes
+// I guess it's fine to list both karts and maps at once without separating
std::vector LobbyAssetManager::getMissingAssets(
std::shared_ptr peer) const
{
- if (m_play_requirement_tracks.empty())
+ if (m_play_requirement_karts.empty() && m_play_requirement_tracks.empty())
return {};
std::vector ans;
+ for (const std::string& required_kart : m_play_requirement_karts)
+ if (peer->getClientAssets().first.count(required_kart) == 0)
+ ans.push_back(required_kart);
+
for (const std::string& required_track : m_play_requirement_tracks)
if (peer->getClientAssets().second.count(required_track) == 0)
ans.push_back(required_track);
diff --git a/src/utils/lobby_asset_manager.hpp b/src/utils/lobby_asset_manager.hpp
index 6844ac4a1b6..6786d02c060 100644
--- a/src/utils/lobby_asset_manager.hpp
+++ b/src/utils/lobby_asset_manager.hpp
@@ -74,6 +74,7 @@ class LobbyAssetManager: public LobbyContextComponent
std::set getAvailableKarts() const
{ return m_available_kts.first; }
+ void setMustHaveKarts(const std::string& input);
void setMustHaveMaps(const std::string& input);
void gameFinishedOn(const std::string& map_name);
@@ -141,6 +142,7 @@ class LobbyAssetManager: public LobbyContextComponent
* with data in server first. */
std::pair, std::set > m_entering_kts;
+ std::vector m_must_have_karts;
std::vector m_must_have_maps;
std::vector m_map_history;
@@ -149,6 +151,7 @@ class LobbyAssetManager: public LobbyContextComponent
KartFilter m_global_karts_filter;
+ std::vector m_play_requirement_karts;
std::vector m_play_requirement_tracks;
float m_official_karts_play_threshold;