diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index e49d7078e..7aad85ded 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2456,7 +2456,7 @@ void ServerLobby::startSelection(const Event *event) if (!has_peer_plays_game) { for (STKPeer* peer : always_spectate_peers) - peer->setAlwaysSpectate(false); + peer->setAlwaysSpectate(ASM_NONE); always_spectate_peers.clear(); } else @@ -2469,6 +2469,40 @@ void ServerLobby::startSelection(const Event *event) peer->setWaitingForGame(true); } + 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 in battle or + // soccer + std::sort(peers.begin(), peers.end(), + [](const std::shared_ptr& a, + const std::shared_ptr& 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; + } + } + } + for (const std::string& kart_erase : karts_erase) { m_available_kts.first.erase(kart_erase); @@ -2478,7 +2512,7 @@ void ServerLobby::startSelection(const Event *event) m_available_kts.second.erase(track_erase); } - unsigned max_player = 0; + max_player = 0; STKHost::get()->updatePlayers(&max_player); if (auto ai = m_ai_peer.lock()) { @@ -4684,6 +4718,7 @@ void ServerLobby::addWaitingPlayersToGame() if (!peer || !peer->isValidated()) continue; + peer->resetAlwaysSpectateFull(); peer->setWaitingForGame(false); peer->setSpectator(false); if (m_peers_ready.find(peer) == m_peers_ready.end()) @@ -5522,10 +5557,10 @@ void ServerLobby::handleServerCommand(Event* event, delete chat; return; } - peer->setAlwaysSpectate(true); + peer->setAlwaysSpectate(ASM_COMMAND); } else - peer->setAlwaysSpectate(false); + peer->setAlwaysSpectate(ASM_NONE); updatePlayerList(); } else if (argv[0] == "listserveraddon") diff --git a/src/network/stk_peer.cpp b/src/network/stk_peer.cpp index 92f0938f7..bfd6ea1d9 100644 --- a/src/network/stk_peer.cpp +++ b/src/network/stk_peer.cpp @@ -44,7 +44,7 @@ STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id) m_host_id = host_id; m_connected_time = StkTime::getMonoTimeMs(); m_validated.store(false); - m_always_spectate.store(false); + m_always_spectate.store(ASM_NONE); m_average_ping.store(0); m_packet_loss.store(0); m_waiting_for_game.store(true); diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index ce2c17cd0..3678d39de 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -61,6 +61,13 @@ enum AddonScore : int AS_TOTAL = 4, }; // AddonScore +enum AlwaysSpectateMode : uint8_t +{ + ASM_NONE = 0, //!< Default, not spectating at all + ASM_COMMAND = 1, //!< Set by player through command + ASM_FULL = 2, //!< Set by server because too many players joined +}; // AlwaysSpectateMode + /*! \class STKPeer * \brief Represents a peer. * This class is used to interface the ENetPeer structure. @@ -85,7 +92,7 @@ protected: std::atomic_bool m_warned_for_high_ping; - std::atomic_bool m_always_spectate; + std::atomic m_always_spectate; /** Host id of this peer. */ uint32_t m_host_id; @@ -292,10 +299,17 @@ public: // ------------------------------------------------------------------------ const SocketAddress& getAddress() const { return *m_socket_address.get(); } // ------------------------------------------------------------------------ - void setAlwaysSpectate(bool val) { m_always_spectate.store(val); } + void setAlwaysSpectate(AlwaysSpectateMode mode) + { m_always_spectate.store(mode); } // ------------------------------------------------------------------------ - bool alwaysSpectate() const { return m_always_spectate.load(); } - + bool alwaysSpectate() const + { return m_always_spectate.load() != ASM_NONE; } + // ------------------------------------------------------------------------ + void resetAlwaysSpectateFull() + { + if (m_always_spectate.load() == ASM_FULL) + m_always_spectate.store(ASM_NONE); + } }; // STKPeer #endif // STK_PEER_HPP