From 3df0aecf7b52c0f822bb1b811ba79708ad2b3b27 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 10 Aug 2024 20:31:39 +0400 Subject: [PATCH] Fix #4997 In startSelection, assets are erased only after the spectators are determined. If a spectator doesn't have the picked map, it's not loaded, but the spectator mode stays afterwards. --- src/network/protocols/server_lobby.cpp | 40 ++++++++++++++++++++++---- src/network/stk_peer.hpp | 3 ++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 12092553663..245b197f195 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -968,9 +968,30 @@ void ServerLobby::asynchronousUpdate() m_item_seed = (uint32_t)StkTime::getTimeSinceEpoch(); ItemManager::updateRandomSeed(m_item_seed); m_game_setup->setRace(winner_vote); + + // For spectators that don't have the track, remember their + // spectate mode and don't load the track + std::string track_name = winner_vote.m_track_name; + auto peers = STKHost::get()->getPeers(); + std::map, + AlwaysSpectateMode> previous_spectate_mode; + for (auto peer : peers) + { + if (peer->alwaysSpectate() && + peer->getClientAssets().second.count(track_name) == 0) + { + previous_spectate_mode[peer] = peer->getAlwaysSpectate(); + peer->setAlwaysSpectate(ASM_NONE); + peer->setWaitingForGame(true); + m_peers_ready.erase(peer); + } + } bool has_always_on_spectators = false; auto players = STKHost::get() ->getPlayersForNewGame(&has_always_on_spectators); + for (auto& p: previous_spectate_mode) + if (p.first) + p.first->setAlwaysSpectate(p.second); auto ai_instance = m_ai_peer.lock(); if (supportsAI()) { @@ -1861,8 +1882,7 @@ void ServerLobby::startSelection(const Event *event) } } - // Remove karts / tracks from server that are not supported on all clients - std::set karts_erase, tracks_erase; + // Find if there are peers playing the game auto peers = STKHost::get()->getPeers(); std::set always_spectate_peers; bool has_peer_plays_game = false; @@ -1870,8 +1890,6 @@ void ServerLobby::startSelection(const Event *event) { if (!peer->isValidated() || peer->isWaitingForGame()) continue; - peer->eraseServerKarts(m_available_kts.first, karts_erase); - peer->eraseServerTracks(m_available_kts.second, tracks_erase); if (peer->alwaysSpectate()) always_spectate_peers.insert(peer.get()); else if (!peer->isAIPeer()) @@ -1906,13 +1924,25 @@ void ServerLobby::startSelection(const Event *event) "spectate for late coming players!"); return; } - for(auto &peer : spectators_by_limit) + for (auto &peer : spectators_by_limit) { peer->setAlwaysSpectate(ASM_FULL); peer->setWaitingForGame(true); always_spectate_peers.insert(peer.get()); } + // Remove karts / tracks from server that are not supported + // on all clients that are playing + std::set karts_erase, tracks_erase; + for (auto peer : peers) + { + // Spectators won't remove maps as they are already waiting for game + if (!peer->isValidated() || peer->isWaitingForGame()) + continue; + peer->eraseServerKarts(m_available_kts.first, karts_erase); + peer->eraseServerTracks(m_available_kts.second, tracks_erase); + } + for (const std::string& kart_erase : karts_erase) { m_available_kts.first.erase(kart_erase); diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index 3678d39de38..3bfe4a652fa 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -302,6 +302,9 @@ class STKPeer : public NoCopy void setAlwaysSpectate(AlwaysSpectateMode mode) { m_always_spectate.store(mode); } // ------------------------------------------------------------------------ + AlwaysSpectateMode getAlwaysSpectate() const + { return (AlwaysSpectateMode)m_always_spectate.load(); } + // ------------------------------------------------------------------------ bool alwaysSpectate() const { return m_always_spectate.load() != ASM_NONE; } // ------------------------------------------------------------------------