Removed StartGameProtocol, and added the necessary states to the

Lobby rooms. Added documentation of the FSM for the ServerLobby.
This commit is contained in:
hiker 2016-11-22 17:57:15 +11:00
parent 6b1563321f
commit 09eae7e25f
21 changed files with 399 additions and 447 deletions

View File

@ -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)
{

View File

@ -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

View File

@ -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())
{

View File

@ -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

View File

@ -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 {}

View File

@ -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

View File

@ -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)
{

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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; }

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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")