Removed StartGameProtocol, and added the necessary states to the
Lobby rooms. Added documentation of the FSM for the ServerLobby.
This commit is contained in:
parent
6b1563321f
commit
09eae7e25f
@ -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
|
||||
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)
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -80,7 +80,7 @@ void* NetworkConsole::mainLoop(void* data)
|
||||
{
|
||||
ServerLobbyRoomProtocol* protocol =
|
||||
dynamic_cast<ServerLobbyRoomProtocol*>(LobbyRoomProtocol::get());
|
||||
protocol->startGame();
|
||||
protocol->signalRaceStartToClients();
|
||||
}
|
||||
else if (str == "selection" && NetworkConfig::get()->isServer())
|
||||
{
|
||||
|
@ -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<NetworkPlayerProfile*> 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
|
||||
|
@ -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 {}
|
||||
|
@ -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<RaceEventManager>()->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<NetworkPlayerProfile*> 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
|
||||
|
||||
|
@ -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() {}
|
||||
// ------------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
|
@ -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<NetworkPlayerProfile*> &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<RaceEventManager>()->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<STKPeer*> &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<NetworkPlayerProfile*> &players = m_setup->getPlayers();
|
||||
const std::vector<NetworkPlayerProfile*> &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,7 +794,7 @@ 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,
|
||||
m_game_setup->getRaceConfig()->setPlayerReversedVote(player_id,
|
||||
reverse!=0, nb_track);
|
||||
// Send the vote to everybody (including the sender)
|
||||
NetworkString *other = getNetworkString(4);
|
||||
@ -744,7 +822,7 @@ 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,
|
||||
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)
|
||||
@ -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<SynchronizationProtocol*>(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.
|
||||
|
@ -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<int> 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<int> 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<uint8_t, bool> 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;
|
||||
|
||||
|
@ -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<NetworkPlayerProfile*> &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<RaceEventManager>()->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<NetworkPlayerProfile*> 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<SynchronizationProtocol*>(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<SynchronizationProtocol*>(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<NetworkPlayerProfile*> players =
|
||||
STKHost::get()->getMyPlayerProfiles();
|
||||
for(unsigned int i=0; i<players.size(); i++)
|
||||
{
|
||||
NetworkString *ns = getNetworkString(2);
|
||||
// 1 indicates: client is ready
|
||||
ns->addUInt8(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
|
||||
|
@ -1,51 +0,0 @@
|
||||
#ifndef START_GAME_PROTOCOL_HPP
|
||||
#define START_GAME_PROTOCOL_HPP
|
||||
|
||||
#include "network/protocol.hpp"
|
||||
#include "utils/cpp2011.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
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<uint8_t, STATE> 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
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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<GameEventsProtocol*>(
|
||||
ProtocolManager::getInstance()->getProtocol(PROTOCOL_GAME_EVENTS));
|
||||
protocol->clientHasStarted();
|
||||
} // clientHasStarted
|
||||
// ----------------------------------------------------------------------------
|
||||
void RaceEventManager::controllerAction(Controller* controller,
|
||||
PlayerAction action, int value)
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
@ -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<StartGameProtocol*>(
|
||||
ProtocolManager::getInstance()->getProtocol(PROTOCOL_START_GAME));
|
||||
if (protocol)
|
||||
protocol->ready();
|
||||
LobbyRoomProtocol *lobby = LobbyRoomProtocol::get();
|
||||
assert(lobby);
|
||||
lobby->finishedLoadingWorld();
|
||||
}
|
||||
} // startNextRace
|
||||
|
||||
|
@ -135,7 +135,8 @@ void NetworkKartSelectionScreen::playerConfirm(const int playerID)
|
||||
{
|
||||
|
||||
LobbyRoomProtocol* protocol = LobbyRoomProtocol::get();
|
||||
|
||||
ClientLobbyRoomProtocol *clrp = dynamic_cast<ClientLobbyRoomProtocol*>(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; i<players.size(); i++)
|
||||
{
|
||||
protocol->requestKartSelection(players[i]->getGlobalPlayerId(),
|
||||
clrp->requestKartSelection(players[i]->getGlobalPlayerId(),
|
||||
selection);
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
Loading…
Reference in New Issue
Block a user