diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index f3f4a9925..d89807842 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -47,6 +47,7 @@ #include "network/protocols/connect_to_server.hpp" #include "network/protocols/game_protocol.hpp" #include "network/protocols/game_events_protocol.hpp" +#include "network/protocols/server_lobby.hpp" #include "network/protocol_manager.hpp" #include "network/race_event_manager.hpp" #include "network/server.hpp" @@ -622,7 +623,11 @@ void ClientLobby::connectionAccepted(Event* event) MessageQueue::add(MessageQueue::MT_GENERIC, msg); } - STKHost::get()->setMyHostId(data.getUInt32()); + uint32_t host_id = data.getUInt32(); + STKHost::get()->setMyHostId(host_id); + if (auto sl = LobbyProtocol::getByType(PT_CHILD)) + sl->setClientServerHostId(host_id); + assert(!NetworkConfig::get()->isAddingNetworkPlayers()); uint32_t server_version = data.getUInt32(); NetworkConfig::get()->setJoinedServerVersion(server_version); @@ -1182,6 +1187,12 @@ void ClientLobby::backToLobby(Event *event) // I18N: Error message shown if only 1 player remains in network msg = _("Only 1 player remaining, returning to lobby."); break; + case BLR_SERVER_ONWER_QUITED_THE_GAME: + // I18N: Error message shown when all players will go back to lobby + // when server owner quited the game + if (!STKHost::get()->isClientServer()) + msg = _("Server owner quited the game."); + break; default: break; } diff --git a/src/network/protocols/client_lobby.hpp b/src/network/protocols/client_lobby.hpp index 8ccec3aa9..23ffbb433 100644 --- a/src/network/protocols/client_lobby.hpp +++ b/src/network/protocols/client_lobby.hpp @@ -185,6 +185,7 @@ public: { return m_ranking_changes; } void handleClientCommand(const std::string& cmd); void updateAssetsToServer(); + ClientState getCurrentState() const { return m_state.load(); } }; #endif // CLIENT_LOBBY_HPP diff --git a/src/network/protocols/lobby_protocol.hpp b/src/network/protocols/lobby_protocol.hpp index a08065d12..b5ff3a409 100644 --- a/src/network/protocols/lobby_protocol.hpp +++ b/src/network/protocols/lobby_protocol.hpp @@ -98,7 +98,8 @@ public: BLR_NONE = 0, BLR_NO_GAME_FOR_LIVE_JOIN = 1, BLR_NO_PLACE_FOR_LIVE_JOIN = 2, - BLR_ONE_PLAYER_IN_RANKED_MATCH = 3 + BLR_ONE_PLAYER_IN_RANKED_MATCH = 3, + BLR_SERVER_ONWER_QUITED_THE_GAME = 4 }; protected: diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c1ce91701..a20eaa578 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -170,6 +170,7 @@ sqlite3_extension_init(sqlite3* db, char** pzErrMsg, */ ServerLobby::ServerLobby() : LobbyProtocol() { + m_client_server_host_id.store(0); m_lobby_players.store(0); std::vector all_k = kart_properties_manager->getKartsInGroup("standard"); @@ -5063,6 +5064,37 @@ void ServerLobby::clientInGameWantsToBackLobby(Event* event) return; } + if (m_process_type == PT_CHILD && + event->getPeer()->getHostId() == m_client_server_host_id.load()) + { + // For child server the remaining client cannot go on player when the + // server owner quited the game (because the world will be deleted), so + // we reset all players + auto pm = ProtocolManager::lock(); + if (RaceEventManager::get()) + { + RaceEventManager::get()->stop(); + pm->findAndTerminate(PROTOCOL_GAME_EVENTS); + } + auto gp = GameProtocol::lock(); + if (gp) + { + auto lock = gp->acquireWorldDeletingMutex(); + pm->findAndTerminate(PROTOCOL_CONTROLLER_EVENTS); + exitGameState(); + } + else + exitGameState(); + NetworkString* back_to_lobby = getNetworkString(2); + back_to_lobby->setSynchronous(true); + back_to_lobby->addUInt8(LE_BACK_LOBBY) + .addUInt8(BLR_SERVER_ONWER_QUITED_THE_GAME); + sendMessageToPeersInServer(back_to_lobby, /*reliable*/true); + delete back_to_lobby; + m_rs_state.store(RS_ASYNC_RESET); + return; + } + for (const int id : peer->getAvailableKartIDs()) { RemoteKartInfo& rki = RaceManager::get()->getKartInfo(id); @@ -5116,6 +5148,21 @@ void ServerLobby::clientSelectingAssetsWantsToBackLobby(Event* event) return; } + if (m_process_type == PT_CHILD && + event->getPeer()->getHostId() == m_client_server_host_id.load()) + { + NetworkString* back_to_lobby = getNetworkString(2); + back_to_lobby->setSynchronous(true); + back_to_lobby->addUInt8(LE_BACK_LOBBY) + .addUInt8(BLR_SERVER_ONWER_QUITED_THE_GAME); + sendMessageToPeersInServer(back_to_lobby, /*reliable*/true); + delete back_to_lobby; + resetVotingTime(); + resetServer(); + m_rs_state.store(RS_NONE); + return; + } + m_peers_ready.erase(peer); peer->setWaitingForGame(true); peer->setSpectator(false); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 134977fc5..97f8fd67e 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -212,6 +212,8 @@ private: std::atomic m_server_id_online; + std::atomic m_client_server_host_id; + std::atomic m_difficulty; std::atomic m_game_mode; @@ -389,6 +391,7 @@ public: bool isAIProfile(const std::shared_ptr& npp) const { return m_ai_profiles.find(npp) != m_ai_profiles.end(); } uint32_t getServerIdOnline() const { return m_server_id_online; } + void setClientServerHostId(uint32_t id) { m_client_server_host_id = id; } }; // class ServerLobby #endif // SERVER_LOBBY_HPP