From 09eae7e25faff405c633f1f7f8cffa0a9579c95f Mon Sep 17 00:00:00 2001 From: hiker Date: Tue, 22 Nov 2016 17:57:15 +1100 Subject: [PATCH] Removed StartGameProtocol, and added the necessary states to the Lobby rooms. Added documentation of the FSM for the ServerLobby. --- sources.cmake | 2 +- src/modes/world_status.cpp | 29 +- src/modes/world_status.hpp | 2 +- src/network/network_console.cpp | 2 +- .../protocols/client_lobby_room_protocol.cpp | 66 +++-- .../protocols/client_lobby_room_protocol.hpp | 1 + src/network/protocols/lobby_room_protocol.cpp | 105 ++++++++ src/network/protocols/lobby_room_protocol.hpp | 20 +- .../protocols/server_lobby_room_protocol.cpp | 204 +++++++++++--- .../protocols/server_lobby_room_protocol.hpp | 27 +- src/network/protocols/start_game_protocol.cpp | 250 ------------------ src/network/protocols/start_game_protocol.hpp | 51 ---- .../protocols/synchronization_protocol.cpp | 16 +- src/network/race_config.cpp | 6 +- src/network/race_config.hpp | 2 +- src/network/race_event_manager.cpp | 19 -- src/network/race_event_manager.hpp | 1 - src/network/stk_host.cpp | 27 +- src/race/race_manager.cpp | 9 +- src/states_screens/network_kart_selection.cpp | 5 +- src/states_screens/networking_lobby.cpp | 2 +- 21 files changed, 399 insertions(+), 447 deletions(-) delete mode 100644 src/network/protocols/start_game_protocol.cpp delete mode 100644 src/network/protocols/start_game_protocol.hpp diff --git a/sources.cmake b/sources.cmake index ba4868d71..13db008ff 100644 --- a/sources.cmake +++ b/sources.cmake @@ -1,5 +1,5 @@ # Modify this file to change the last-modified date when you add/remove a file. -# This will then trigger a new cmake run automatically. +# This will then trigger a new cmake run automatically. file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp") file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp") file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*") diff --git a/src/modes/world_status.cpp b/src/modes/world_status.cpp index 2c84f4837..997651f4c 100644 --- a/src/modes/world_status.cpp +++ b/src/modes/world_status.cpp @@ -28,6 +28,7 @@ #include "karts/abstract_kart.hpp" #include "modes/world.hpp" #include "network/network_config.hpp" +#include "network/protocols/server_lobby_room_protocol.hpp" #include "network/race_event_manager.hpp" #include "tracks/track.hpp" @@ -181,7 +182,7 @@ void WorldStatus::updateTime(const float dt) { // In case of a networked race wait till all necessary protocols are // ready before progressing the timer - if (!m_ready_to_race) return; +// if (!m_ready_to_race) return; switch (m_phase) { @@ -247,19 +248,17 @@ void WorldStatus::updateTime(const float dt) // to the 'wait_for_server_phase', from which they will progress once // the notification is received. In all other cases (no networking or // server), immediately go to race start - if(!NetworkConfig::get()->isNetworking() || - NetworkConfig::get()->isServer() ) + if (NetworkConfig::get()->isNetworking()) { - // Notify the clients that they can start ready-set-go - if(NetworkConfig::get()->isServer()) - RaceEventManager::getInstance()->startReadySetGo(); - // The server will wait in 'wait_for_server' for clients - // to be ready before starting (using the same startReadySetGo - // callback). - if(!NetworkConfig::get()->isNetworking()) - m_server_is_ready = true; - } // if not networked - m_phase = WAIT_FOR_SERVER_PHASE; + LobbyRoomProtocol *p = LobbyRoomProtocol::get(); + p->finishedLoadingWorld(); + m_phase = WAIT_FOR_SERVER_PHASE; + } + else + { + m_phase = READY_PHASE; + startEngines(); + } return; // Don't increase time case WAIT_FOR_SERVER_PHASE: // On a client this phase waits for the server to be ready. On a @@ -279,17 +278,17 @@ void WorldStatus::updateTime(const float dt) // from the clients reach the server before the server actually // needs it. By running the server behind the clients the need // for rollbacks on the server is greatly reduced. - RaceEventManager::getInstance()->clientHasStarted(); + //RaceEventManager::getInstance()->clientHasStarted(); } m_phase = READY_PHASE; - startEngines(); // Receiving a 'startReadySetGo' message from the server triggers // a call to startReadySetGo() here, which will change the phase // (or state) of the finite state machine. return; // Don't increase time case READY_PHASE: + startEngines(); if (m_auxiliary_timer > 1.0) { diff --git a/src/modes/world_status.hpp b/src/modes/world_status.hpp index d94ede6c1..8938c8e8f 100644 --- a/src/modes/world_status.hpp +++ b/src/modes/world_status.hpp @@ -198,7 +198,7 @@ public: /** Get the time since start regardless of which way the clock counts */ float getTimeSinceStart() const { return m_count_up_timer; } // ------------------------------------------------------------------------ - void setReadyToRace() { m_ready_to_race = true; } + void setReadyToRace() { m_server_is_ready = true; } }; // WorldStatus diff --git a/src/network/network_console.cpp b/src/network/network_console.cpp index 73f06bc3c..8180907e1 100644 --- a/src/network/network_console.cpp +++ b/src/network/network_console.cpp @@ -80,7 +80,7 @@ void* NetworkConsole::mainLoop(void* data) { ServerLobbyRoomProtocol* protocol = dynamic_cast(LobbyRoomProtocol::get()); - protocol->startGame(); + protocol->signalRaceStartToClients(); } else if (str == "selection" && NetworkConfig::get()->isServer()) { diff --git a/src/network/protocols/client_lobby_room_protocol.cpp b/src/network/protocols/client_lobby_room_protocol.cpp index 444145b5a..7d6c610ed 100644 --- a/src/network/protocols/client_lobby_room_protocol.cpp +++ b/src/network/protocols/client_lobby_room_protocol.cpp @@ -23,7 +23,6 @@ #include "network/event.hpp" #include "network/network_config.hpp" #include "network/network_player_profile.hpp" -#include "network/protocols/start_game_protocol.hpp" #include "network/protocol_manager.hpp" #include "network/race_event_manager.hpp" #include "network/stk_host.hpp" @@ -62,7 +61,7 @@ void ClientLobbyRoomProtocol::setAddress(const TransportAddress &address) void ClientLobbyRoomProtocol::setup() { - m_setup = STKHost::get()->setupNewGame(); // create a new setup + m_game_setup = STKHost::get()->setupNewGame(); // create a new game setup m_state = NONE; } // setup @@ -210,7 +209,7 @@ void ClientLobbyRoomProtocol::doneWithResults() bool ClientLobbyRoomProtocol::notifyEvent(Event* event) { - assert(m_setup); // assert that the setup exists + assert(m_game_setup); // assert that the setup exists NetworkString &data = event->data(); assert(data.size()); // assert that data isn't empty @@ -220,6 +219,7 @@ bool ClientLobbyRoomProtocol::notifyEvent(Event* event) switch(message_type) { case LE_KART_SELECTION_UPDATE: kartSelectionUpdate(event); break; + case LE_LOAD_WORLD: loadWorld(); break; case LE_RACE_FINISHED: raceFinished(event); break; case LE_EXIT_RESULT: exitResultScreen(event); break; default: @@ -233,7 +233,7 @@ bool ClientLobbyRoomProtocol::notifyEvent(Event* event) bool ClientLobbyRoomProtocol::notifyEventAsynchronous(Event* event) { - assert(m_setup); // assert that the setup exists + assert(m_game_setup); // assert that the setup exists if (event->getType() == EVENT_TYPE_MESSAGE) { NetworkString &data = event->data(); @@ -362,12 +362,12 @@ void ClientLobbyRoomProtocol::newPlayer(Event* event) "The server notified me that I'm a new player in the " "room (not normal)."); } - else if (m_setup->getProfile(player_id) == NULL) + else if (m_game_setup->getProfile(player_id) == NULL) { Log::verbose("ClientLobbyRoomProtocol", "New player connected."); NetworkPlayerProfile* profile = new NetworkPlayerProfile(name, player_id, host_id); - m_setup->addPlayer(profile); + m_game_setup->addPlayer(profile); NetworkingLobby::getInstance()->addPlayer(profile); } else @@ -397,8 +397,8 @@ void ClientLobbyRoomProtocol::disconnectedPlayer(Event* event) while(data.size()>0) { const NetworkPlayerProfile *profile = - m_setup->getProfile(data.getUInt8()); - if (m_setup->removePlayer(profile)) + m_game_setup->getProfile(data.getUInt8()); + if (m_game_setup->removePlayer(profile)) { Log::info("ClientLobbyRoomProtocol", "Player %d removed successfully.", @@ -456,7 +456,7 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event) NetworkPlayerProfile* profile = new NetworkPlayerProfile(name, my_player_id, my_host_id); STKHost::get()->getGameSetup()->setLocalMaster(my_player_id); - m_setup->setNumLocalPlayers(1); + m_game_setup->setNumLocalPlayers(1); // connection token uint32_t token = data.getToken(); peer->setClientServerToken(token); @@ -472,7 +472,7 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event) NetworkPlayerProfile* profile2 = new NetworkPlayerProfile(name, player_id, host_id); - m_setup->addPlayer(profile2); + m_game_setup->addPlayer(profile2); // Inform the network lobby of all players so that the GUI can // show all currently connected players. NetworkingLobby::getInstance()->addPlayer(profile2); @@ -480,7 +480,7 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event) // Add self after other players so that player order is identical // on server and all clients. - m_setup->addPlayer(profile); + m_game_setup->addPlayer(profile); NetworkingLobby::getInstance()->addPlayer(profile); m_server = event->getPeer(); m_state = CONNECTED; @@ -574,12 +574,12 @@ void ClientLobbyRoomProtocol::kartSelectionUpdate(Event* event) uint8_t player_id = data.getUInt8(); std::string kart_name; data.decodeString(&kart_name); - if (!m_setup->isKartAvailable(kart_name)) + if (!m_game_setup->isKartAvailable(kart_name)) { Log::error("ClientLobbyRoomProtocol", "The updated kart is taken already."); } - m_setup->setPlayerKart(player_id, kart_name); + m_game_setup->setPlayerKart(player_id, kart_name); NetworkKartSelectionScreen::getInstance()->playerSelected(player_id, kart_name); } // kartSelectionUpdate @@ -593,10 +593,8 @@ race needs to be started. */ void ClientLobbyRoomProtocol::startGame(Event* event) { - const NetworkString &data = event->data(); m_state = PLAYING; - ProtocolManager::getInstance() - ->requestStart(new StartGameProtocol(m_setup)); + World::getWorld()->setReadyToRace(); Log::info("ClientLobbyRoomProtocol", "Starting new game"); } // startGame @@ -702,7 +700,7 @@ void ClientLobbyRoomProtocol::playerMajorVote(Event* event) return; uint8_t player_id = data.getUInt8(); uint8_t mode = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerMajorVote(player_id, mode); + m_game_setup->getRaceConfig()->setPlayerMajorVote(player_id, mode); } // playerMajorVote //----------------------------------------------------------------------------- @@ -722,7 +720,7 @@ void ClientLobbyRoomProtocol::playerRaceCountVote(Event* event) const NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t count = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerRaceCountVote(player_id, count); + m_game_setup->getRaceConfig()->setPlayerRaceCountVote(player_id, count); } // playerRaceCountVote //----------------------------------------------------------------------------- @@ -742,7 +740,7 @@ void ClientLobbyRoomProtocol::playerMinorVote(Event* event) const NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t minor = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerMinorVote(player_id, minor); + m_game_setup->getRaceConfig()->setPlayerMinorVote(player_id, minor); } // playerMinorVote //----------------------------------------------------------------------------- @@ -765,7 +763,7 @@ void ClientLobbyRoomProtocol::playerTrackVote(Event* event) uint8_t player_id = data.getUInt8(); uint8_t number = data.getUInt8(); int N = data.decodeString(&track_name); - m_setup->getRaceConfig()->setPlayerTrackVote(player_id, track_name, + m_game_setup->getRaceConfig()->setPlayerTrackVote(player_id, track_name, number); } // playerTrackVote @@ -788,7 +786,7 @@ void ClientLobbyRoomProtocol::playerReversedVote(Event* event) uint8_t player_id = data.getUInt8(); uint8_t reversed = data.getUInt8(); uint8_t number = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerReversedVote(player_id, reversed!=0, + m_game_setup->getRaceConfig()->setPlayerReversedVote(player_id, reversed!=0, number); } // playerReversedVote @@ -801,7 +799,7 @@ void ClientLobbyRoomProtocol::playerReversedVote(Event* event) * Byte 0 1 2 * ---------------------------------------- * Size | 1 | 1 | 1 | - * Data | player id | laps | track number (gp) | + * Data | player id | laps | track number (gp) | * ---------------------------------------- */ void ClientLobbyRoomProtocol::playerLapsVote(Event* event) @@ -811,7 +809,29 @@ void ClientLobbyRoomProtocol::playerLapsVote(Event* event) uint8_t player_id = data.getUInt8(); uint8_t laps = data.getUInt8(); uint8_t number = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerLapsVote(player_id, laps, number); + m_game_setup->getRaceConfig()->setPlayerLapsVote(player_id, laps, number); } // playerLapsVote //----------------------------------------------------------------------------- +/** Callback when the world is loaded. The client will inform the server + * that the players on this host are ready to start the race. It is called by + * the RaceManager after the world is loaded. + */ +void ClientLobbyRoomProtocol::finishedLoadingWorld() +{ + assert(STKHost::get()->getPeerCount() == 1); + std::vector players = + STKHost::get()->getMyPlayerProfiles(); + NetworkString *ns = getNetworkString(2); + ns->addUInt8(LE_CLIENT_LOADED_WORLD); + ns->addUInt8( uint8_t(players.size()) ) ; + for (unsigned int i = 0; i < players.size(); i++) + { + ns->addUInt8(players[i]->getGlobalPlayerId()); + Log::info("ClientLobbyRoomProtocol", + "Player %d ready, notifying server.", + players[i]->getGlobalPlayerId()); + } // for i < players.size() + sendToServer(ns, /*reliable*/true); + delete ns; +} // finishedLoadingWorld diff --git a/src/network/protocols/client_lobby_room_protocol.hpp b/src/network/protocols/client_lobby_room_protocol.hpp index 24c22676a..526fa60fb 100644 --- a/src/network/protocols/client_lobby_room_protocol.hpp +++ b/src/network/protocols/client_lobby_room_protocol.hpp @@ -68,6 +68,7 @@ public: virtual bool notifyEvent(Event* event) OVERRIDE; virtual bool notifyEventAsynchronous(Event* event) OVERRIDE; + virtual void finishedLoadingWorld() OVERRIDE; virtual void setup() OVERRIDE; virtual void update(float dt) OVERRIDE; virtual void asynchronousUpdate() OVERRIDE {} diff --git a/src/network/protocols/lobby_room_protocol.cpp b/src/network/protocols/lobby_room_protocol.cpp index 2b1933be1..9b5294436 100644 --- a/src/network/protocols/lobby_room_protocol.cpp +++ b/src/network/protocols/lobby_room_protocol.cpp @@ -19,6 +19,111 @@ #include "network/protocols/lobby_room_protocol.hpp" +#include "input/input_manager.hpp" +#include "input/device_manager.hpp" +#include "modes/world.hpp" +#include "network/network_player_profile.hpp" +#include "network/protocols/synchronization_protocol.hpp" +#include "network/race_event_manager.hpp" +#include "network/stk_host.hpp" +#include "race/race_manager.hpp" +#include "states_screens/state_manager.hpp" + LobbyRoomProtocol *LobbyRoomProtocol::m_lobby = NULL; +LobbyRoomProtocol::LobbyRoomProtocol(CallbackObject* callback_object) + : Protocol(PROTOCOL_LOBBY_ROOM, callback_object) +{ + m_game_setup = NULL; +} // LobbyRoomProtocol + +// ---------------------------------------------------------------------------- +LobbyRoomProtocol::~LobbyRoomProtocol() +{ +} // ~LobbyRoomProtocol + +//----------------------------------------------------------------------------- +/** Starts the sychronization protocol and the RaceEventManager. It then + * sets the player structures up, creates the active player, and loads + * the world. + * This is called on the client when the server informs them that + * the world can be loaded (LE_LOAD_WORLD) and on the server in state + * LOAD_WORLD (i.e. just after informing all clients). + */ +void LobbyRoomProtocol::loadWorld() +{ + Log::info("LobbyRoomProtocol", "Ready !"); + + Protocol *p = new SynchronizationProtocol(); + p->requestStart(); + Log::info("LobbyRoomProtocol", "SynchronizationProtocol started."); + + // Race startup sequence + // --------------------- + // This creates the network world. + RaceEventManager::getInstance()->start(); + + // The number of karts includes the AI karts, which are not supported atm + race_manager->setNumKarts(m_game_setup->getPlayerCount()); + + // Set number of global and local players. + race_manager->setNumPlayers(m_game_setup->getPlayerCount(), + m_game_setup->getNumLocalPlayers()); + + // Create the kart information for the race manager: + // ------------------------------------------------- + std::vector players = m_game_setup->getPlayers(); + int local_player_id = 0; + for (unsigned int i = 0; i < players.size(); i++) + { + NetworkPlayerProfile* profile = players[i]; + bool is_local = profile->isLocalPlayer(); + + // All non-local players are created here. This means all players + // on the server, and all non-local players on a client (the local + // karts are created in the NetworkingLobby). + if (!is_local) + { + // On the server no device or player profile is needed. + StateManager::get()->createActivePlayer(NULL, NULL); + } + + // Adjust the local player id so that local players have the numbers + // 0 to num-1; and all other karts start with num. This way the local + // players get the first ActivePlayers assigned (which have the + // corresponding device associated with it). + RemoteKartInfo rki(is_local ? local_player_id + : i - local_player_id + + STKHost::get()->getGameSetup()->getNumLocalPlayers(), + profile->getKartName(), + profile->getName(), + profile->getHostId(), + !is_local); + rki.setGlobalPlayerId(profile->getGlobalPlayerId()); + rki.setPerPlayerDifficulty(profile->getPerPlayerDifficulty()); + if (is_local) + { + rki.setLocalPlayerId(local_player_id); + local_player_id++; + } + + // Inform the race manager about the data for this kart. + race_manager->setPlayerKart(i, rki); + } // for i in players + + // Make sure that if there is only a single local player this player can + // use all input devices. + StateManager::ActivePlayer *ap = race_manager->getNumLocalPlayers()>1 + ? NULL + : StateManager::get()->getActivePlayer(0); + + input_manager->getDeviceManager()->setSinglePlayer(ap); + + Log::info("LobbyRoomProtocol", "Player configuration ready."); + + // Load the actual world. + m_game_setup->getRaceConfig()->loadWorld(); + World::getWorld()->setNetworkWorld(true); + +} // setupGame diff --git a/src/network/protocols/lobby_room_protocol.hpp b/src/network/protocols/lobby_room_protocol.hpp index 0d9d4ec98..f9aab049a 100644 --- a/src/network/protocols/lobby_room_protocol.hpp +++ b/src/network/protocols/lobby_room_protocol.hpp @@ -45,6 +45,8 @@ public: LE_NEW_PLAYER_CONNECTED, // inform client about new player LE_KART_SELECTION, // Player selected kart LE_PLAYER_DISCONNECTED, // Client disconnected + LE_CLIENT_LOADED_WORLD, // Client finished loading world + LE_LOAD_WORLD, // Clients should load world LE_START_RACE, // start race LE_START_SELECTION, // inform client to start selection LE_RACE_FINISHED, // race has finished, display result @@ -62,7 +64,7 @@ protected: static LobbyRoomProtocol *m_lobby; /** The game setup. */ - GameSetup* m_setup; + GameSetup* m_game_setup; public: @@ -85,16 +87,12 @@ public: // ------------------------------------------------------------------------ - LobbyRoomProtocol(CallbackObject* callback_object) - : Protocol(PROTOCOL_LOBBY_ROOM, callback_object) - { - m_setup = NULL; - } // LobbyRoomProtocol - // ------------------------------------------------------------------------ - virtual ~LobbyRoomProtocol() {} - // ------------------------------------------------------------------------ - virtual void setup() = 0; - virtual void update(float dt) = 0; + LobbyRoomProtocol(CallbackObject* callback_object); + virtual ~LobbyRoomProtocol(); + virtual void setup() = 0; + virtual void update(float dt) = 0; + virtual void finishedLoadingWorld() = 0; + virtual void loadWorld(); virtual void requestKartSelection(uint8_t player_id, const std::string &kart_name) { diff --git a/src/network/protocols/server_lobby_room_protocol.cpp b/src/network/protocols/server_lobby_room_protocol.cpp index d6cb8708d..faae0453d 100644 --- a/src/network/protocols/server_lobby_room_protocol.cpp +++ b/src/network/protocols/server_lobby_room_protocol.cpp @@ -26,7 +26,7 @@ #include "network/network_player_profile.hpp" #include "network/protocols/get_public_address.hpp" #include "network/protocols/connect_to_peer.hpp" -#include "network/protocols/start_game_protocol.hpp" +#include "network/protocols/synchronization_protocol.hpp" #include "network/protocol_manager.hpp" #include "network/race_event_manager.hpp" #include "network/stk_host.hpp" @@ -41,7 +41,37 @@ #include "utils/time.hpp" -/** This is the central game setup protocol running in the server. +/** This is the central game setup protocol running in the server. It is + * mostly a finite state machine. Note that all nodes in capital leters + * are actual states, while nodes starting with a lower case letter are + * just functions being called. + \dot + digraph interaction { + "Server Constructor" -> "INIT_WAN" [label="If WAN game"] + "Server Constructor" -> "ACCEPTING_CLIENTS" [label="If LAN game"] + "INIT_WAN" -> "GETTING_PUBLIC_ADDRESS" [label="GetPublicAddress protocol callback"] + "GETTING_PUBLIC_ADDRESS" -> "ACCEPTING_CLIENTS" [label="Register server"] + "ACCEPTING_CLIENTS" -> "connectionRequested" [label="Client connection request"] + "connectionRequested" -> "ACCEPTING_CLIENTS" + "ACCEPTING_CLIENTS" -> "SELECTING" [label="Start race from authorised client"] + "SELECTING" -> "SELECTING" [label="Client selects kart, #laps, ..."] + "SELECTING" -> "playerVoteTrack" [label="Client selected track"] + "playerVoteTrack" -> "SELECTING" [label="Not all clients have selected"] + "playerVoteTrack" -> "LOAD_WORLD" [label="All clients have selected"] + "LOAD"WORLD -> "WAIT_FOR_WORLD_LOADED" + "WAIT_FOR_WORLD_LOADED" -> "WAIT_FOR_WORLD_LOADED" [label="Client or server loaded world"] + "WAIT_FOR_WORLD_LOADED" -> "startRace" [label="All clients and server ready"] + "startRace" -> "DELAY_SERVER" + "DELAY_SERVER" -> "DELAY_SERVER" [label="Not done waiting"] + "DELAY_SERVER -> "Start Countdown" [label="Server starts race now"] + "Start Countdown" -> "Wait For Clients" + "Wait For Clients" -> "Wait For Clients" [label="Client started 'ready set go'"] + "Wait For Clients" -> "Additional Server Delay" + "Additional Server Delay" -> "Start Race" [label="Additional delay done"] + } + \enddot + + * It starts with detecting the public ip address and port of this * host (GetPublicAddress). */ @@ -61,24 +91,38 @@ ServerLobbyRoomProtocol::~ServerLobbyRoomProtocol() void ServerLobbyRoomProtocol::setup() { - m_setup = STKHost::get()->setupNewGame(); - m_setup->setNumLocalPlayers(0); // no local players on a server + m_game_setup = STKHost::get()->setupNewGame(); + m_game_setup->setNumLocalPlayers(0); // no local players on a server m_next_player_id.setAtomic(0); // In case of LAN we don't need our public address or register with the // STK server, so we can directly go to the accepting clients state. m_state = NetworkConfig::get()->isLAN() ? ACCEPTING_CLIENTS - : NONE; + : INIT_WAN; m_selection_enabled = false; m_current_protocol = NULL; Log::info("ServerLobbyRoomProtocol", "Starting the protocol."); + + // Initialise the data structures to detect if all clients and + // the server are ready: + m_player_states.clear(); + m_client_ready_count.setAtomic(0); + m_server_delay = 0.02f; + m_server_has_loaded_world = false; + const std::vector &players = + m_game_setup->getPlayers(); + for (unsigned int i = 0; i < players.size(); i++) + { + m_player_states[players[i]->getGlobalPlayerId()] = false; + } + } // setup //----------------------------------------------------------------------------- bool ServerLobbyRoomProtocol::notifyEventAsynchronous(Event* event) { - assert(m_setup); // assert that the setup exists + assert(m_game_setup); // assert that the setup exists if (event->getType() == EVENT_TYPE_MESSAGE) { NetworkString &data = event->data(); @@ -92,6 +136,7 @@ bool ServerLobbyRoomProtocol::notifyEventAsynchronous(Event* event) case LE_CONNECTION_REQUESTED: connectionRequested(event); break; case LE_REQUEST_BEGIN: startSelection(event); break; case LE_KART_SELECTION: kartSelectionRequested(event); break; + case LE_CLIENT_LOADED_WORLD: finishedLoadingWorldClient(event); break; case LE_VOTE_MAJOR: playerMajorVote(event); break; case LE_VOTE_RACE_COUNT: playerRaceCountVote(event); break; case LE_VOTE_MINOR: playerMinorVote(event); break; @@ -118,7 +163,7 @@ void ServerLobbyRoomProtocol::update(float dt) { switch (m_state) { - case NONE: + case INIT_WAN: // Start the protocol to find the public ip address. m_current_protocol = new GetPublicAddress(this); m_current_protocol->requestStart(); @@ -148,7 +193,34 @@ void ServerLobbyRoomProtocol::update(float dt) break; } case SELECTING: - break; // Nothing to do, this is event based + // The function playerVoteTrack will trigger the next state + // one all track votes have been received. + break; + case LOAD_WORLD: + Log::info("ServerLobbyRoom", "Starting the race loading."); + // This will create the world instance, i.e. load track and karts + loadWorld(); + m_state = WAIT_FOR_WORLD_LOADED; + break; + case WAIT_FOR_WORLD_LOADED: + // Note that m_server_has_loaded_world is called by the main thread + // (same a the thread updating this protocol) + m_client_ready_count.lock(); + if (m_server_has_loaded_world && + m_client_ready_count.getData() == m_game_setup->getPlayerCount()) + { + signalRaceStartToClients(); + } + m_client_ready_count.unlock(); + break; + case DELAY_SERVER: + m_server_delay -= dt; + if (m_server_delay < 0) + { + m_state = RACING; + + } + break; case RACING: if (World::getWorld() && RaceEventManager::getInstance()->isRunning()) @@ -236,23 +308,18 @@ void ServerLobbyRoomProtocol::registerServer() } // registerServer //----------------------------------------------------------------------------- -/** This function is called when all track votes from the clients have - * been received. It broadcasts a message to all client to start the - * race - -informs each client to start the race, and then starts the - * StartGameProtocol. +/** This function is called when all clients have loaded the world and + * are therefore ready to start the race. It signals to all clients + * to start the race and then switches state to DELAY_SERVER. */ -void ServerLobbyRoomProtocol::startGame() +void ServerLobbyRoomProtocol::signalRaceStartToClients() { const std::vector &peers = STKHost::get()->getPeers(); NetworkString *ns = getNetworkString(1); ns->addUInt8(LE_START_RACE); sendMessageToPeersChangingToken(ns, /*reliable*/true); delete ns; - Protocol *p = new StartGameProtocol(m_setup); - p->requestStart(); - m_state = RACING; + m_state = DELAY_SERVER; } // startGame //----------------------------------------------------------------------------- @@ -398,7 +465,7 @@ void ServerLobbyRoomProtocol::clientDisconnected(Event* event) msg->addUInt8(players_on_host[i]->getGlobalPlayerId()); Log::info("ServerLobbyRoomProtocol", "Player disconnected : id %d", players_on_host[i]->getGlobalPlayerId()); - m_setup->removePlayer(players_on_host[i]); + m_game_setup->removePlayer(players_on_host[i]); } sendMessageToPeersChangingToken(msg, /*reliable*/true); @@ -426,7 +493,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event) const NetworkString &data = event->data(); // can we add the player ? - if (m_setup->getPlayerCount() >= NetworkConfig::get()->getMaxPlayers() || + if (m_game_setup->getPlayerCount() >= NetworkConfig::get()->getMaxPlayers() || m_state!=ACCEPTING_CLIENTS ) { NetworkString *message = getNetworkString(2); @@ -455,8 +522,8 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event) m_next_player_id.getData()++; int new_player_id = m_next_player_id.getData(); m_next_player_id.unlock(); - if(m_setup->getLocalMasterID()==0) - m_setup->setLocalMaster(new_player_id); + if(m_game_setup->getLocalMasterID()==0) + m_game_setup->setLocalMaster(new_player_id); // The host id has already been incremented when the peer // was added, so it is the right id now. @@ -484,7 +551,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event) peer->setAuthorised(is_authorised); peer->setHostId(new_host_id); - const std::vector &players = m_setup->getPlayers(); + const std::vector &players = m_game_setup->getPlayers(); // send a message to the one that asked to connect // Estimate 10 as average name length NetworkString *message_ack = getNetworkString(4 + players.size() * (2+10)); @@ -504,7 +571,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event) NetworkPlayerProfile* profile = new NetworkPlayerProfile(name, new_player_id, new_host_id); - m_setup->addPlayer(profile); + m_game_setup->addPlayer(profile); NetworkingLobby::getInstance()->addPlayer(profile); Log::verbose("ServerLobbyRoomProtocol", "New player."); @@ -551,7 +618,7 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event) return; } // check if somebody picked that kart - if (!m_setup->isKartAvailable(kart_name)) + if (!m_game_setup->isKartAvailable(kart_name)) { NetworkString *answer = getNetworkString(2); // kart is already taken @@ -561,7 +628,7 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event) return; } // check if this kart is authorized - if (!m_setup->isKartAllowed(kart_name)) + if (!m_game_setup->isKartAllowed(kart_name)) { NetworkString *answer = getNetworkString(2); // kart is not authorized @@ -580,7 +647,7 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event) .encodeString(kart_name); sendMessageToPeersChangingToken(answer); delete answer; - m_setup->setPlayerKart(player_id, kart_name); + m_game_setup->setPlayerKart(player_id, kart_name); } // kartSelectionRequested //----------------------------------------------------------------------------- @@ -602,7 +669,7 @@ void ServerLobbyRoomProtocol::playerMajorVote(Event* event) NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint32_t major = data.getUInt32(); - m_setup->getRaceConfig()->setPlayerMajorVote(player_id, major); + m_game_setup->getRaceConfig()->setPlayerMajorVote(player_id, major); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(6); other->addUInt8(LE_VOTE_MAJOR).addUInt8(player_id).addUInt32(major); @@ -627,7 +694,7 @@ void ServerLobbyRoomProtocol::playerRaceCountVote(Event* event) NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint8_t race_count = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerRaceCountVote(player_id, race_count); + m_game_setup->getRaceConfig()->setPlayerRaceCountVote(player_id, race_count); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(3); other->addUInt8(LE_VOTE_RACE_COUNT).addUInt8(player_id) @@ -654,7 +721,7 @@ void ServerLobbyRoomProtocol::playerMinorVote(Event* event) NetworkString &data = event->data(); uint8_t player_id = data.getUInt8(); uint32_t minor = data.getUInt32(); - m_setup->getRaceConfig()->setPlayerMinorVote(player_id, minor); + m_game_setup->getRaceConfig()->setPlayerMinorVote(player_id, minor); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(3); @@ -685,7 +752,7 @@ void ServerLobbyRoomProtocol::playerTrackVote(Event* event) uint8_t track_number = data.getUInt8(); std::string track_name; int N = data.decodeString(&track_name); - m_setup->getRaceConfig()->setPlayerTrackVote(player_id, track_name, + m_game_setup->getRaceConfig()->setPlayerTrackVote(player_id, track_name, track_number); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(3+1+data.size()); @@ -693,8 +760,19 @@ void ServerLobbyRoomProtocol::playerTrackVote(Event* event) .encodeString(track_name); sendMessageToPeersChangingToken(other); delete other; - if(m_setup->getRaceConfig()->getNumTrackVotes()==m_setup->getPlayerCount()) - startGame(); + + // Check if we received all information + if (m_game_setup->getRaceConfig()->getNumTrackVotes() == + m_game_setup->getPlayerCount()) + { + // Inform clients to start loading the world + NetworkString *ns = getNetworkString(1); + ns->setSynchronous(true); + ns->addUInt8(LE_LOAD_WORLD); + sendMessageToPeersChangingToken(ns, /*reliable*/true); + delete ns; + m_state = LOAD_WORLD; // Server can now load world + } } // playerTrackVote //----------------------------------------------------------------------------- @@ -716,8 +794,8 @@ void ServerLobbyRoomProtocol::playerReversedVote(Event* event) uint8_t player_id = data.getUInt8(); uint8_t reverse = data.getUInt8(); uint8_t nb_track = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerReversedVote(player_id, - reverse!=0, nb_track); + m_game_setup->getRaceConfig()->setPlayerReversedVote(player_id, + reverse!=0, nb_track); // Send the vote to everybody (including the sender) NetworkString *other = getNetworkString(4); other->addUInt8(LE_VOTE_REVERSE).addUInt8(player_id).addUInt8(reverse) @@ -744,8 +822,8 @@ void ServerLobbyRoomProtocol::playerLapsVote(Event* event) uint8_t player_id = data.getUInt8(); uint8_t lap_count = data.getUInt8(); uint8_t track_nb = data.getUInt8(); - m_setup->getRaceConfig()->setPlayerLapsVote(player_id, lap_count, - track_nb); + m_game_setup->getRaceConfig()->setPlayerLapsVote(player_id, lap_count, + track_nb); NetworkString *other = getNetworkString(4); other->addUInt8(LE_VOTE_LAPS).addUInt8(player_id).addUInt8(lap_count) .addUInt8(track_nb); @@ -753,6 +831,58 @@ void ServerLobbyRoomProtocol::playerLapsVote(Event* event) delete other; } // playerLapsVote +// ---------------------------------------------------------------------------- +/** Called from the RaceManager of the server when the world is loaded. Marks + * the server to be ready to start the race. + */ +void ServerLobbyRoomProtocol::finishedLoadingWorld() +{ + m_server_has_loaded_world = true; +} // finishedLoadingWorld; + +//----------------------------------------------------------------------------- +/** Called when a client notifies the server that it has loaded the world. + * When all clients and the server are ready, the race can be started. + */ +void ServerLobbyRoomProtocol::finishedLoadingWorldClient(Event *event) +{ + if (!checkDataSize(event, 1)) return; + + const NetworkString &data = event->data(); + uint8_t player_count = data.getUInt8(); + m_client_ready_count.lock(); + for (unsigned int i = 0; i < player_count; i++) + { + uint8_t player_id = data.getUInt8(); + if (m_player_states[player_id]) + { + Log::error("ServerLobbyProtocol", + "Player %d send more than one ready message.", + player_id); + return; + } + Log::info("ServerLobbyeProtocol", "One of the players is ready."); + m_player_states[player_id] = true; + m_client_ready_count.getData()++; + } + m_client_ready_count.unlock(); + + if (m_client_ready_count.getAtomic() == m_game_setup->getPlayerCount()) + { + Protocol *p = ProtocolManager::getInstance() + ->getProtocol(PROTOCOL_SYNCHRONIZATION); + SynchronizationProtocol* protocol = + dynamic_cast(p); + if (protocol) + { + protocol->startCountdown(5.0f); // 5 seconds countdown + Log::info("ServerLobbyProtocol", + "All players ready, starting countdown."); + } + } // if m_ready_count == number of players + +} // finishedLoadingWorld + //----------------------------------------------------------------------------- /** Called when a client clicks on 'ok' on the race result screen. * If all players have clicked on 'ok', go back to the lobby. diff --git a/src/network/protocols/server_lobby_room_protocol.hpp b/src/network/protocols/server_lobby_room_protocol.hpp index 4a4cb697f..3c03cc470 100644 --- a/src/network/protocols/server_lobby_room_protocol.hpp +++ b/src/network/protocols/server_lobby_room_protocol.hpp @@ -12,10 +12,14 @@ private: /* The state for a small finite state machine. */ enum { - NONE, + INIT_WAN, // Start state for WAN game GETTING_PUBLIC_ADDRESS, // Waiting to receive its public ip address ACCEPTING_CLIENTS, // In lobby, accepting clients SELECTING, // kart, track, ... selection started + LOAD_WORLD, // Server starts loading world + WAIT_FOR_WORLD_LOADED, // Wait for clients and server to load world + START_RACE, // Inform clients to start race + DELAY_SERVER, // Additional server delay RACING, // racing RESULT_DISPLAY, // Show result screen DONE, // shutting down server @@ -25,6 +29,22 @@ private: /** Next id to assign to a peer. */ Synchronised m_next_player_id; + /** Keeps track of the server state. */ + bool m_server_has_loaded_world; + + /** Counts how many clients have finished loading the world. */ + Synchronised m_client_ready_count; + + /** For debugging: keep track of the state (ready or not) of each player, + * to make sure no client/player reports more than once. Needs to be a + * map since the client IDs can be non-consecutive. */ + std::map m_player_states; + + /** Keeps track of an artificial server delay (which makes sure that the + * data from all clients has arrived when the server computes a certain + * timestep. */ + float m_server_delay; + Protocol *m_current_protocol; bool m_selection_enabled; @@ -48,7 +68,7 @@ private: void playerLapsVote(Event* event); void playerFinishedResult(Event *event); void registerServer(); - + void finishedLoadingWorldClient(Event *event); public: ServerLobbyRoomProtocol(); virtual ~ServerLobbyRoomProtocol(); @@ -58,10 +78,11 @@ public: virtual void update(float dt) OVERRIDE; virtual void asynchronousUpdate() OVERRIDE {}; - void startGame(); + void signalRaceStartToClients(); void startSelection(const Event *event=NULL); void checkIncomingConnectionRequests(); void checkRaceFinished(); + void finishedLoadingWorld(); virtual void callback(Protocol *protocol) OVERRIDE; diff --git a/src/network/protocols/start_game_protocol.cpp b/src/network/protocols/start_game_protocol.cpp deleted file mode 100644 index 38ee66f35..000000000 --- a/src/network/protocols/start_game_protocol.cpp +++ /dev/null @@ -1,250 +0,0 @@ -#include "network/protocols/start_game_protocol.hpp" - -#include "config/player_manager.hpp" -#include "input/device_manager.hpp" -#include "input/input_device.hpp" -#include "input/input_manager.hpp" -#include "challenges/unlock_manager.hpp" -#include "modes/world.hpp" -#include "network/event.hpp" -#include "network/game_setup.hpp" -#include "network/network_config.hpp" -#include "network/network_player_profile.hpp" -#include "network/race_event_manager.hpp" -#include "network/protocol_manager.hpp" -#include "network/protocols/synchronization_protocol.hpp" -#include "network/stk_host.hpp" -#include "online/online_profile.hpp" -#include "race/race_manager.hpp" -#include "states_screens/kart_selection.hpp" -#include "states_screens/network_kart_selection.hpp" -#include "utils/log.hpp" -#include "utils/time.hpp" - -StartGameProtocol::StartGameProtocol(GameSetup* game_setup) - : Protocol(PROTOCOL_START_GAME) -{ - m_game_setup = game_setup; - const std::vector &players = - m_game_setup->getPlayers(); - for (unsigned int i = 0; i < players.size(); i++) - { - m_player_states[ players[i]->getGlobalPlayerId() ] = LOADING; - } - m_ready_count = 0; -} // StartGameProtocol - -// ---------------------------------------------------------------------------- -StartGameProtocol::~StartGameProtocol() -{ -} // ~StartGameProtocol - -// ---------------------------------------------------------------------------- -/** Setup the actual game. It first starts the SynchronisationProtocol, - * and then - */ -void StartGameProtocol::setup() -{ - m_state = NONE; - m_ready_count = 0; - m_ready = false; - Log::info("SynchronizationProtocol", "Ready !"); - - Protocol *p = new SynchronizationProtocol(); - p->requestStart(); - Log::info("StartGameProtocol", "SynchronizationProtocol started."); - - // Race startup sequence - // --------------------- - // This creates the network world. - RaceEventManager::getInstance()->start(); - - // The number of karts includes the AI karts, which are not supported atm - race_manager->setNumKarts(m_game_setup->getPlayerCount()); - - // Set number of global and local players. - race_manager->setNumPlayers(m_game_setup->getPlayerCount(), - m_game_setup->getNumLocalPlayers()); - - // Create the kart information for the race manager: - // ------------------------------------------------- - std::vector players = m_game_setup->getPlayers(); - int local_player_id = 0; - for (unsigned int i = 0; i < players.size(); i++) - { - NetworkPlayerProfile* profile = players[i]; - bool is_local = profile->isLocalPlayer(); - - // All non-local players are created here. This means all players - // on the server, and all non-local players on a client (the local - // karts are created in the NetworkingLobby). - if(!is_local) - { - // On the server no device or player profile is needed. - StateManager::get()->createActivePlayer(NULL, NULL); - } - - // Adjust the local player id so that local players have the numbers - // 0 to num-1; and all other karts start with num. This way the local - // players get the first ActivePlayers assigned (which have the - // corresponding device associated with it). - RemoteKartInfo rki(is_local ? local_player_id - : i-local_player_id - +STKHost::get()->getGameSetup()->getNumLocalPlayers(), - profile->getKartName(), - profile->getName(), - profile->getHostId(), - !is_local); - rki.setGlobalPlayerId(profile->getGlobalPlayerId()); - rki.setPerPlayerDifficulty(profile->getPerPlayerDifficulty()); - if(is_local) - { - rki.setLocalPlayerId(local_player_id); - local_player_id++; - } - - // Inform the race manager about the data for this kart. - race_manager->setPlayerKart(i, rki); - } // for i in players - - // Make sure that if there is only a single local player this player can - // use all input devices. - StateManager::ActivePlayer *ap = race_manager->getNumLocalPlayers()>1 - ? NULL - : StateManager::get()->getActivePlayer(0); - - input_manager->getDeviceManager()->setSinglePlayer(ap); - - Log::info("StartGameProtocol", "Player configuration ready."); - m_state = SYNCHRONIZATION_WAIT; - -} // setup - -// ---------------------------------------------------------------------------- -/** Handles incoming messages on the server. Should never be called on a - * client. It counts how many clients are ready, and once all clients - * are ready, will call startRace(). - * \param event Details about the received mnessage. - */ -bool StartGameProtocol::notifyEventAsynchronous(Event* event) -{ - if(!checkDataSize(event, 1)) return true; - - const NetworkString &data = event->data(); - uint8_t player_id = data.getUInt8(); - uint8_t ready = data.getUInt8(); - if (NetworkConfig::get()->isServer() && ready) // on server, player is ready - { - Log::info("StartGameProtocol", "One of the players is ready."); - if (m_player_states[player_id] != LOADING) - { - Log::error("StartGameProtocol", - "Player %d send more than one ready message.", - player_id); - } - m_player_states[player_id] = READY; - m_ready_count++; - if (m_ready_count == m_game_setup->getPlayerCount()) - { - startRace(); - } // if m_ready_count == number of players - } - else // on the client, we shouldn't even receive messages. - { - Log::error("StartGameProtocol", "Received a message with bad format."); - } - return true; -} // notifyEventAsynchronous - -// ---------------------------------------------------------------------------- -/** Starts the race by starting the SynchronizationProtocol. - */ -void StartGameProtocol::startRace() -{ - // everybody ready, synchronize - Protocol *p = ProtocolManager::getInstance() - ->getProtocol(PROTOCOL_SYNCHRONIZATION); - SynchronizationProtocol* protocol = - dynamic_cast(p); - if (protocol) - { - protocol->startCountdown(5.0f); // 5 seconds countdown - Log::info("StartGameProtocol", - "All players ready, starting countdown."); - m_ready = true; - } - else - { - Log::error("StartGameProtocol", - "The Synchronization protocol hasn't been started."); - } -} // startRace - -// ---------------------------------------------------------------------------- -void StartGameProtocol::update(float dt) -{ - switch(m_state) - { - case SYNCHRONIZATION_WAIT: - { - // Wait till the synchronisation protocol is running - Protocol *p = ProtocolManager::getInstance() - ->getProtocol(PROTOCOL_SYNCHRONIZATION); - SynchronizationProtocol* protocol = - dynamic_cast(p); - if (protocol) - { - // Now the synchronization protocol exists. - Log::info("StartGameProtocol", "Starting the race loading."); - // This will create the world instance, - // i.e. load track and karts - m_game_setup->getRaceConfig()->setRaceData(); - World::getWorld()->setNetworkWorld(true); - m_state = LOADING; - } - break; - } - case LOADING: - { - if (m_ready) m_state = READY; - break; - } - case READY: - { - // set karts into the network game setup - STKHost::get()->getGameSetup()->bindKartsToProfiles(); - m_state = EXITING; - requestTerminate(); - break; - } - } // switch -} // update - -// ---------------------------------------------------------------------------- -/** Callback from the race manager when the world was setup. - */ -void StartGameProtocol::ready() -{ - // On clients this means the loading is finished. - // Inform the server that this client is ready. - if (NetworkConfig::get()->isClient()) - { - assert(STKHost::get()->getPeerCount() == 1); - std::vector players = - STKHost::get()->getMyPlayerProfiles(); - for(unsigned int i=0; iaddUInt8(players[i]->getGlobalPlayerId()).addUInt8(1); - Log::info("StartGameProtocol", "Player %d ready, notifying server.", - players[i]->getGlobalPlayerId()); - sendToServer(ns, /*reliable*/true); - delete ns; - } - m_state = READY; - m_ready = true; - return; - } -} // ready - diff --git a/src/network/protocols/start_game_protocol.hpp b/src/network/protocols/start_game_protocol.hpp deleted file mode 100644 index c300a5bbf..000000000 --- a/src/network/protocols/start_game_protocol.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef START_GAME_PROTOCOL_HPP -#define START_GAME_PROTOCOL_HPP - -#include "network/protocol.hpp" -#include "utils/cpp2011.hpp" - -#include - -class GameSetup; -class NetworkPlayerProfile; - -/** This protocol runs on both server and clients. - */ -class StartGameProtocol : public Protocol -{ -private: - /** State for the finite state machine, and also for - * remote clients. */ - enum STATE { NONE, SYNCHRONIZATION_WAIT, - LOADING, READY, EXITING }; - - /** State of the finite state machine. */ - STATE m_state; - - /** Keeps the state for all clients. */ - std::map m_player_states; - - /** Stores a handy pointer to the game setup structure. */ - GameSetup* m_game_setup; - - /** Counts how many clients have reported to be ready (which is then - * used to trigger the next state one all clients are ready). */ - int m_ready_count; - - bool m_ready; - - void startRace(); - -public: - StartGameProtocol(GameSetup* game_setup); - virtual ~StartGameProtocol(); - - virtual bool notifyEventAsynchronous(Event* event); - virtual void setup() OVERRIDE; - virtual void update(float dt) OVERRIDE; - void ready(); - virtual void asynchronousUpdate() OVERRIDE {} - -}; // class StartGameProtocol - -#endif // START_GAME_PROTOCOL_HPP diff --git a/src/network/protocols/synchronization_protocol.cpp b/src/network/protocols/synchronization_protocol.cpp index a1d202276..807240bcf 100644 --- a/src/network/protocols/synchronization_protocol.cpp +++ b/src/network/protocols/synchronization_protocol.cpp @@ -126,10 +126,10 @@ bool SynchronizationProtocol::notifyEventAsynchronous(Event* event) //----------------------------------------------------------------------------- /** Waits for the countdown to be started. On the server the start of the - * countdown is triggered by the StartGameProtocol::startRace(), which is - * called once all clients have confirmed that they are ready to start. - * The server will send a ping request to each client once a second, and - * include the information if the countdown has started (and its current + * countdown is triggered by ServerLobbyRoomProtocol::finishedLoadingWorld(), + * which is called once all clients have confirmed that they are ready to + * start. The server will send a ping request to each client once a second, + * and include the information if the countdown has started (and its current * value). On the client the countdown is started in notifyEvenAsynchronous() * when a server ping is received that indicates that the countdown has * started. The measured times can be used later to estimate the latency @@ -188,10 +188,10 @@ void SynchronizationProtocol::asynchronousUpdate() //----------------------------------------------------------------------------- /** Starts the countdown on this machine. On the server side this function - * is called from the StartGameProtocol (when all players have confirmed that - * they are ready to play). On the client side this function is called from - * this protocol when a message from the server is received indicating that - * the countdown has to be started. + * is called from ServerLobbyRoomProtocol::finishedLoadingWorld() (when all + * players have confirmed that they are ready to play). On the client side + * this function is called from this protocol when a message from the server + * is received indicating that the countdown has to be started. * \param ms_countdown Countdown to use in ms. */ void SynchronizationProtocol::startCountdown(float ms_countdown) diff --git a/src/network/race_config.cpp b/src/network/race_config.cpp index c300403cc..26f57e218 100644 --- a/src/network/race_config.cpp +++ b/src/network/race_config.cpp @@ -421,15 +421,15 @@ void RaceConfig::computeNextTrack() //----------------------------------------------------------------------------- /** Computes the selected setting (based on the users' vote) and sets them - * in the race manager. + * in the race manager. Then it loads the world. */ -void RaceConfig::setRaceData() +void RaceConfig::loadWorld() { computeRaceMode(); computeNextTrack(); race_manager->startSingleRace(m_tracks[0].track, m_tracks[0].laps, m_tracks[0].reversed); -} // setRaceData +} // loadWorld //----------------------------------------------------------------------------- const TrackInfo* RaceConfig::getNextTrackInfo() const diff --git a/src/network/race_config.hpp b/src/network/race_config.hpp index 5d96234b3..e88979862 100644 --- a/src/network/race_config.hpp +++ b/src/network/race_config.hpp @@ -110,7 +110,7 @@ public: void setPlayerLapsVote(uint8_t player_id, uint8_t lap_count, uint8_t track_nb = 0); - void setRaceData(); + void loadWorld(); const TrackInfo* getNextTrackInfo() const; bool getReverse() const; diff --git a/src/network/race_event_manager.cpp b/src/network/race_event_manager.cpp index ac2c73997..fae5856fd 100644 --- a/src/network/race_event_manager.cpp +++ b/src/network/race_event_manager.cpp @@ -115,26 +115,7 @@ void RaceEventManager::startReadySetGo() ProtocolManager::getInstance()->getProtocol(PROTOCOL_GAME_EVENTS)); protocol->startReadySetGo(); } // startReadySetGo -// ---------------------------------------------------------------------------- -/** Called on a client if it has started the 'ready' phase. The clients will - * send this information to the server, and the server will wait for all - * those messages before it starts its own 'ready set go'. De-facto that - * means that the server will wait for the client with the highest latency - * before it starts. Assuming no latency peaks that means that the server will - * always have received all events for time T before it executes time T -The server waits - * for all clients to report that they -*/ -void RaceEventManager::clientHasStarted() -{ - // this is only called in the client - assert(NetworkConfig::get()->isClient()); - - GameEventsProtocol* protocol = static_cast( - ProtocolManager::getInstance()->getProtocol(PROTOCOL_GAME_EVENTS)); - protocol->clientHasStarted(); -} // clientHasStarted // ---------------------------------------------------------------------------- void RaceEventManager::controllerAction(Controller* controller, PlayerAction action, int value) diff --git a/src/network/race_event_manager.hpp b/src/network/race_event_manager.hpp index 6730e3f9b..f224c2cff 100755 --- a/src/network/race_event_manager.hpp +++ b/src/network/race_event_manager.hpp @@ -57,7 +57,6 @@ public: int value); void kartFinishedRace(AbstractKart *kart, float time); void startReadySetGo(); - void clientHasStarted(); // ------------------------------------------------------------------------ /** Returns if this instance is in running state or not. */ bool isRunning() { return m_running; } diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index 3862be37a..1b32fea27 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -206,23 +206,22 @@ void STKHost::create() * stored in RaceConfig of GameSetup. * * The server will detect when the track votes from each client have been - * received and will trigger the start of the race (SLR::startGame, called - * from playerTrackVote). In SLR::startGame the server will start the - * StartGameProtocol and the clients will be informed to start the game. - * In a client the StartGame protocol will be started in CLR::startGame. + * received and will inform all clients to load the world (playerTrackVote). + * Then (state LOAD_GAME) the server will load the world and wait for all + * clients to finish loading (WAIT_FOR_WORLD_LOADED). * - * The StartGame protocol will create the ActivePlayers for all non-local - * players: on a server, all karts are non-local. On a client, the - * ActivePlayer objects for each local players have been created (to store - * the device used by each player when joining), so they are used to create - * the LocalPlayerController for each kart. Each remote player gets a + * In LR::loadWorld all ActivePlayers for all non-local players are created. + * (on a server all karts are non-local). On a client, the ActivePlayer + * objects for each local players have been created (to store the device + * used by each player when joining), so they are used to create the + * LocalPlayerController for each kart. Each remote player gets a * NULL ActivePlayer (the ActivePlayer is only used for assigning the input * device to each kart, achievements and highscores, so it's not needed for - * remote players). It will also start the SynchronizationProtocol. - * The StartGameProtocol has a callback ready() which is called from world - * when the world is loaded (i.e. track and all karts are ready). When - * this callback is invoked, each client will send a 'ready' message to - * the server's StartGameProtocol. Once the server has received all + * remote players). It will also start the SynchronizationProtocol, + * RaceEventManager and then load the world. + + * TODO: + * Once the server has received all * messages in notifyEventAsynchronous(), it will call startCountdown() * in the SynchronizationProtocol. The SynchronizationProtocol is * sending regular (once per second) pings to the clients and measure diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index 011208291..d976144b3 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -45,7 +45,7 @@ #include "modes/soccer_world.hpp" #include "network/protocol_manager.hpp" #include "network/network_config.hpp" -#include "network/protocols/start_game_protocol.hpp" +#include "network/protocols/lobby_room_protocol.hpp" #include "network/race_event_manager.hpp" #include "replay/replay_play.hpp" #include "scriptengine/property_animator.hpp" @@ -560,10 +560,9 @@ void RaceManager::startNextRace() // the world has been setup if(NetworkConfig::get()->isNetworking()) { - StartGameProtocol* protocol = static_cast( - ProtocolManager::getInstance()->getProtocol(PROTOCOL_START_GAME)); - if (protocol) - protocol->ready(); + LobbyRoomProtocol *lobby = LobbyRoomProtocol::get(); + assert(lobby); + lobby->finishedLoadingWorld(); } } // startNextRace diff --git a/src/states_screens/network_kart_selection.cpp b/src/states_screens/network_kart_selection.cpp index b3c339a70..cee840b9b 100644 --- a/src/states_screens/network_kart_selection.cpp +++ b/src/states_screens/network_kart_selection.cpp @@ -135,7 +135,8 @@ void NetworkKartSelectionScreen::playerConfirm(const int playerID) { LobbyRoomProtocol* protocol = LobbyRoomProtocol::get(); - + ClientLobbyRoomProtocol *clrp = dynamic_cast(protocol); + assert(clrp); // FIXME SPLITSCREEN: we need to supply the global player id of the // player selecting the kart here. For now ... just vote the same kart // for each local player. @@ -143,7 +144,7 @@ void NetworkKartSelectionScreen::playerConfirm(const int playerID) STKHost::get()->getMyPlayerProfiles(); for(unsigned int i=0; irequestKartSelection(players[i]->getGlobalPlayerId(), + clrp->requestKartSelection(players[i]->getGlobalPlayerId(), selection); } } diff --git a/src/states_screens/networking_lobby.cpp b/src/states_screens/networking_lobby.cpp index baaf983ec..cdc3044f1 100644 --- a/src/states_screens/networking_lobby.cpp +++ b/src/states_screens/networking_lobby.cpp @@ -56,7 +56,7 @@ DEFINE_SCREEN_SINGLETON( NetworkingLobby ); * for all local players (the ActivePlayer maps device to player, i.e. * controls which device is used by which player). Note that a server * does not create an instance of this class and will create the ActivePlayer - * data structure in the StartGameProtocol. + * data structure in LobbyProtocol::loadWorld(). */ // ---------------------------------------------------------------------------- NetworkingLobby::NetworkingLobby() : Screen("online/networking_lobby.stkgui")