Make limit of players in game configurable (#4685)

This commit is contained in:
STK-Waldlaubsaengernest 2021-12-05 16:46:49 +01:00
parent d8af4bc17e
commit 97eb45b93b
4 changed files with 96 additions and 41 deletions

View File

@ -1827,6 +1827,7 @@ void ServerLobby::liveJoinRequest(Event* event)
peer->clearAvailableKartIDs();
if (!spectator)
{
auto spectators_by_limit = getSpectatorsByLimit();
setPlayerKarts(data, peer);
std::vector<int> used_id;
@ -1837,7 +1838,8 @@ void ServerLobby::liveJoinRequest(Event* event)
break;
used_id.push_back(id);
}
if (used_id.size() != peer->getPlayerProfiles().size())
if ((used_id.size() != peer->getPlayerProfiles().size()) ||
(spectators_by_limit.find(event->getPeerSP()) != spectators_by_limit.end()))
{
for (unsigned i = 0; i < peer->getPlayerProfiles().size(); i++)
peer->getPlayerProfiles()[i]->setKartName("");
@ -2526,35 +2528,19 @@ void ServerLobby::startSelection(const Event *event)
unsigned max_player = 0;
STKHost::get()->updatePlayers(&max_player);
if (max_player > 10 && (RaceManager::get()->isBattleMode() ||
RaceManager::get()->isSoccerMode()))
// Set late coming player to spectate if too many players
auto spectators_by_limit = getSpectatorsByLimit();
if (spectators_by_limit.size() == peers.size())
{
// Set late coming player to spectate if too many players in battle or
// soccer
std::sort(peers.begin(), peers.end(),
[](const std::shared_ptr<STKPeer>& a,
const std::shared_ptr<STKPeer>& b)
{ return a->getHostId() > b->getHostId(); });
int remove_player = max_player - 10;
for (unsigned i = 0; i < peers.size(); i++)
{
auto& peer = peers[i];
if (!peer->isValidated() || peer->isWaitingForGame())
continue;
peer->setAlwaysSpectate(ASM_FULL);
peer->setWaitingForGame(true);
always_spectate_peers.insert(peer.get());
remove_player -= (int)peer->getPlayerProfiles().size();
if (remove_player <= 0)
break;
// In case something goes wrong (all players need spectate)
if (i == peers.size() - 1)
{
Log::error("ServerLobby", "Too many players and cannot set "
"spectate for late coming players!");
return;
}
}
Log::error("ServerLobby", "Too many players and cannot set "
"spectate for late coming players!");
return;
}
for(auto &peer : spectators_by_limit)
{
peer->setAlwaysSpectate(ASM_FULL);
peer->setWaitingForGame(true);
always_spectate_peers.insert(peer.get());
}
for (const std::string& kart_erase : karts_erase)
@ -3976,6 +3962,9 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server)
if (profile->getPeer()->alwaysSpectate())
all_profiles_size--;
}
auto spectators_by_limit = getSpectatorsByLimit();
// N - 1 AI
auto ai_instance = m_ai_peer.lock();
if (supportsAI())
@ -4022,22 +4011,23 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server)
.addUInt8((uint8_t)all_profiles.size());
for (auto profile : all_profiles)
{
auto profile_name = profile->getName();
// get OS information
auto version_os = StringUtils::extractVersionOS(profile->getPeer()->getUserVersion());
std::string os_type_str = version_os.second;
// if mobile OS
if (os_type_str == "iOS" || os_type_str == "Android")
{ // Add a Mobile emoji for mobile OS
pl->addUInt32(profile->getHostId()).addUInt32(profile->getOnlineId())
.addUInt8(profile->getLocalPlayerId())
.encodeString(StringUtils::utf32ToWide({0x1F4F1}) + profile->getName());
}
else
{
pl->addUInt32(profile->getHostId()).addUInt32(profile->getOnlineId())
.addUInt8(profile->getLocalPlayerId())
.encodeString(profile->getName());
}
// Add a Mobile emoji for mobile OS
profile_name = StringUtils::utf32ToWide({ 0x1F4F1 }) + profile_name;
// Add an hourglass emoji for players waiting because of the player limit
if (spectators_by_limit.find(profile->getPeer()) != spectators_by_limit.end())
profile_name = StringUtils::utf32ToWide({ 0x231B }) + profile_name;
pl->addUInt32(profile->getHostId()).addUInt32(profile->getOnlineId())
.addUInt8(profile->getLocalPlayerId())
.encodeString(profile_name);
std::shared_ptr<STKPeer> p = profile->getPeer();
uint8_t boolean_combine = 0;
@ -5512,6 +5502,61 @@ void ServerLobby::clientSelectingAssetsWantsToBackLobby(Event* event)
delete server_info;
} // clientSelectingAssetsWantsToBackLobby
std::set<std::shared_ptr<STKPeer>> ServerLobby::getSpectatorsByLimit()
{
std::set<std::shared_ptr<STKPeer>> spectators_by_limit;
auto peers = STKHost::get()->getPeers();
std::set<std::shared_ptr<STKPeer>> always_spectate_peers;
int player_limit = ServerConfig::m_max_players_in_game;
// only 10 players allowed for battle or soccer
if (RaceManager::get()->isBattleMode() || RaceManager::get()->isSoccerMode())
player_limit = std::min(player_limit, 10);
unsigned ingame_players = 0, waiting_players = 0, total_players = 0;
STKHost::get()->updatePlayers(&ingame_players, &waiting_players, &total_players);
if (total_players <= player_limit)
return spectators_by_limit;
std::sort(peers.begin(), peers.end(),
[](const std::shared_ptr<STKPeer>& a,
const std::shared_ptr<STKPeer>& b)
{ return a->getHostId() < b->getHostId(); });
if (m_state.load() >= RACING)
{
for (auto &peer : peers)
if (peer->isSpectator())
ingame_players -= (int)peer->getPlayerProfiles().size();
}
int player_count = 0;
for (unsigned i = 0; i < peers.size(); i++)
{
auto& peer = peers[i];
if (!peer->isValidated())
continue;
if (m_state.load() < RACING)
{
if (peer->alwaysSpectate() || peer->isWaitingForGame())
continue;
player_count += (int)peer->getPlayerProfiles().size();
if (player_count > player_limit)
spectators_by_limit.insert(peer);
}
else
{
if (peer->isSpectator())
continue;
player_count += (int)peer->getPlayerProfiles().size();
if (peer->isWaitingForGame() && (player_count > player_limit || ingame_players >= player_limit))
spectators_by_limit.insert(peer);
}
}
return spectators_by_limit;
}
//-----------------------------------------------------------------------------
void ServerLobby::saveInitialItems(std::shared_ptr<NetworkItemManager> nim)
{

View File

@ -368,6 +368,7 @@ private:
void handleKartInfo(Event* event);
void clientInGameWantsToBackLobby(Event* event);
void clientSelectingAssetsWantsToBackLobby(Event* event);
std::set<std::shared_ptr<STKPeer>> getSpectatorsByLimit();
void kickPlayerWithReason(STKPeer* peer, const char* reason) const;
void testBannedForIP(STKPeer* peer) const;
void testBannedForIPv6(STKPeer* peer) const;

View File

@ -336,6 +336,9 @@ void loadServerLobbyFromConfig()
m_server_max_players > 10)
m_server_max_players = 10;
m_max_players_in_game = (m_max_players_in_game <= 0) ? m_server_max_players :
std::min(m_max_players_in_game, m_server_max_players);
if (m_ipv6_connection)
{
#ifndef ENABLE_IPV6
@ -352,7 +355,7 @@ void loadServerLobbyFromConfig()
}
if (m_owner_less)
{
if (m_min_start_game_players > m_server_max_players)
if (m_min_start_game_players > m_max_players_in_game)
m_min_start_game_players = 1;
if (!m_live_players)
m_team_choosing = false;

View File

@ -134,6 +134,12 @@ namespace ServerConfig
"Maximum number of players on the server, setting this to a value "
"greater than 8 can cause performance degradation."));
SERVER_CFG_PREFIX IntServerConfigParam m_max_players_in_game
SERVER_CFG_DEFAULT(IntServerConfigParam(0, "max-players-in-game",
"Maximum number of players in the game, all other players on "
"the server are spectators. Specify 0 to allow all players on "
"the server to play."));
SERVER_CFG_PREFIX StringServerConfigParam m_private_server_password
SERVER_CFG_DEFAULT(StringServerConfigParam("",
"private-server-password", "Password for private server, "