Added end of race handling, so that clients and server shut
down properly and go back to the lobby.
This commit is contained in:
@@ -107,6 +107,21 @@ void Protocol::requestTerminate()
|
||||
ProtocolManager::getInstance()->requestTerminate(this);
|
||||
} // requestTerminate
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Finds a protocol with the given type and requests it to be terminated.
|
||||
* If no such protocol exist, log an error message.
|
||||
* \param type The protocol type to delete.
|
||||
*/
|
||||
void Protocol::findAndTerminateProtocol(ProtocolType type)
|
||||
{
|
||||
Protocol* protocol = ProtocolManager::getInstance()->getProtocol(type);
|
||||
if (protocol)
|
||||
protocol->requestTerminate();
|
||||
else
|
||||
Log::error("ClientLobbyRoomProtocol",
|
||||
"No protocol %d registered.", type);
|
||||
} // findAndTerminateProtocol
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sends a message to all peers, inserting the peer's token into the message.
|
||||
* The message is composed of a 1-byte message (usually the message type)
|
||||
|
||||
@@ -138,6 +138,7 @@ public:
|
||||
void requestPause();
|
||||
void requestUnpause();
|
||||
void requestTerminate();
|
||||
void findAndTerminateProtocol(ProtocolType type);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** \brief Called when the protocol is paused (by an other entity or by
|
||||
|
||||
@@ -315,10 +315,10 @@ bool ProtocolManager::sendEvent(Event* event)
|
||||
/** \brief Updates the manager.
|
||||
*
|
||||
* This function processes the events queue, notifies the concerned
|
||||
* protocols that they have events to process. Then ask all protocols
|
||||
* to update themselves. Finally processes stored requests about
|
||||
* protocols that they have events to process. Then asks all protocols
|
||||
* to update themselves. Finally it processes stored requests about
|
||||
* starting, stoping, pausing etc... protocols.
|
||||
* This function is called by the main loop.
|
||||
* This function is called by the main thread (i.e. from main_loop).
|
||||
* This function IS FPS-dependant.
|
||||
*/
|
||||
void ProtocolManager::update()
|
||||
@@ -357,7 +357,7 @@ void ProtocolManager::update()
|
||||
* protocols that they have events to process. Then ask all protocols
|
||||
* to update themselves. Finally processes stored requests about
|
||||
* starting, stoping, pausing etc... protocols.
|
||||
* This function is called in a thread.
|
||||
* This function is called in a separate thread running in this instance.
|
||||
* This function IS NOT FPS-dependant.
|
||||
*/
|
||||
void ProtocolManager::asynchronousUpdate()
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "online/online_profile.hpp"
|
||||
#include "states_screens/networking_lobby.hpp"
|
||||
#include "states_screens/network_kart_selection.hpp"
|
||||
#include "states_screens/race_result_gui.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
@@ -174,7 +175,8 @@ void ClientLobbyRoomProtocol::voteLaps(uint8_t player_id, uint8_t laps,
|
||||
} // voteLaps
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** Called when a client selects to exit a server.
|
||||
*/
|
||||
void ClientLobbyRoomProtocol::leave()
|
||||
{
|
||||
m_server->disconnect();
|
||||
@@ -183,30 +185,40 @@ void ClientLobbyRoomProtocol::leave()
|
||||
ServersManager::get()->unsetJoinedServer();
|
||||
} // leave
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called from the gui when a client clicked on 'continue' on the race result
|
||||
* screen. It notifies the server that this client has exited the screen and
|
||||
* is back at the lobby.
|
||||
*/
|
||||
void ClientLobbyRoomProtocol::doneWithResults()
|
||||
{
|
||||
NetworkString *done = getNetworkString(1);
|
||||
done->addUInt8(LE_RACE_FINISHED_ACK);
|
||||
sendToServer(done, /*reliable*/true);
|
||||
delete done;
|
||||
} // doneWithResults
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool ClientLobbyRoomProtocol::notifyEvent(Event* event)
|
||||
{
|
||||
assert(m_setup); // assert that the setup exists
|
||||
if (event->getType() == EVENT_TYPE_MESSAGE)
|
||||
|
||||
NetworkString &data = event->data();
|
||||
assert(data.size()); // assert that data isn't empty
|
||||
uint8_t message_type = data.getUInt8();
|
||||
Log::info("ClientLobbyRoomProtocol", "Synchronous message of type %d",
|
||||
message_type);
|
||||
switch(message_type)
|
||||
{
|
||||
NetworkString &data = event->data();
|
||||
assert(data.size()); // assert that data isn't empty
|
||||
uint8_t message_type = data.getUInt8();
|
||||
if (message_type != LE_KART_SELECTION_UPDATE &&
|
||||
message_type != LE_RACE_FINISHED )
|
||||
return false; // don't treat the event
|
||||
|
||||
Log::info("ClientLobbyRoomProtocol", "Synchronous message of type %d",
|
||||
message_type);
|
||||
if (message_type == LE_KART_SELECTION_UPDATE) // kart selection update
|
||||
kartSelectionUpdate(event);
|
||||
else if (message_type == LE_RACE_FINISHED) // end of race
|
||||
raceFinished(event);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case LE_KART_SELECTION_UPDATE: kartSelectionUpdate(event); break;
|
||||
case LE_RACE_FINISHED: raceFinished(event); break;
|
||||
case LE_EXIT_RESULT: exitResultScreen(event); break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
} // switch
|
||||
return true;
|
||||
} // notifyEvent
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -302,15 +314,7 @@ void ClientLobbyRoomProtocol::update()
|
||||
case SELECTING_KARTS:
|
||||
break;
|
||||
case PLAYING:
|
||||
{
|
||||
// race is now over, kill race protocols and return to connected state
|
||||
if (RaceEventManager::getInstance<RaceEventManager>()->isRaceOver())
|
||||
{
|
||||
Log::info("ClientLobbyRoomProtocol", "Game finished.");
|
||||
m_state = RACE_FINISHED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case RACE_FINISHED:
|
||||
break;
|
||||
case DONE:
|
||||
@@ -663,7 +667,15 @@ void ClientLobbyRoomProtocol::raceFinished(Event* event)
|
||||
} // raceFinished
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called when the server informs the clients to exit the race result screen.
|
||||
* It exits the race, and goes back to the lobby.
|
||||
*/
|
||||
void ClientLobbyRoomProtocol::exitResultScreen(Event *event)
|
||||
{
|
||||
RaceResultGUI::getInstance()->backToLobby();
|
||||
} // exitResultScreen
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/*! \brief Called when a player votes for a major race mode.
|
||||
* \param event : Event providing the information.
|
||||
*
|
||||
|
||||
@@ -18,6 +18,7 @@ private:
|
||||
void startGame(Event* event);
|
||||
void startSelection(Event* event);
|
||||
void raceFinished(Event* event);
|
||||
void exitResultScreen(Event *event);
|
||||
// race votes
|
||||
void playerMajorVote(Event* event);
|
||||
void playerRaceCountVote(Event* event);
|
||||
@@ -60,6 +61,7 @@ public:
|
||||
uint8_t track_nb = 0);
|
||||
void voteReversed(uint8_t player_id, bool reversed, uint8_t track_nb = 0);
|
||||
void voteLaps(uint8_t player_id, uint8_t laps, uint8_t track_nb = 0);
|
||||
void doneWithResults();
|
||||
void leave();
|
||||
|
||||
virtual bool notifyEvent(Event* event);
|
||||
|
||||
@@ -36,24 +36,26 @@ public:
|
||||
/** Lists all lobby events (LE). */
|
||||
enum
|
||||
{
|
||||
LE_CONNECTION_REQUESTED = 1,
|
||||
LE_REQUEST_BEGIN,
|
||||
LE_NEW_PLAYER_CONNECTED,
|
||||
LE_KART_SELECTION,
|
||||
LE_PLAYER_DISCONNECTED,
|
||||
LE_KART_SELECTION_UPDATE,
|
||||
LE_START_RACE,
|
||||
LE_START_SELECTION,
|
||||
LE_RACE_FINISHED,
|
||||
LE_CONNECTION_REFUSED,
|
||||
LE_CONNECTION_ACCEPTED,
|
||||
LE_KART_SELECTION_REFUSED,
|
||||
LE_VOTE_MAJOR,
|
||||
LE_VOTE_RACE_COUNT,
|
||||
LE_VOTE_MINOR,
|
||||
LE_VOTE_TRACK,
|
||||
LE_VOTE_REVERSE,
|
||||
LE_VOTE_LAPS,
|
||||
LE_CONNECTION_REQUESTED = 1, // a connection to the server
|
||||
LE_CONNECTION_REFUSED, // Connection to server refused
|
||||
LE_CONNECTION_ACCEPTED, // Connection to server accepted
|
||||
LE_KART_SELECTION_UPDATE, // inform client about kart selected
|
||||
LE_REQUEST_BEGIN, // begin of kart selection
|
||||
LE_KART_SELECTION_REFUSED, // Client not auth. to start selection
|
||||
LE_NEW_PLAYER_CONNECTED, // inform client about new player
|
||||
LE_KART_SELECTION, // Player selected kart
|
||||
LE_PLAYER_DISCONNECTED, // Client disconnected
|
||||
LE_START_RACE, // start race
|
||||
LE_START_SELECTION, // inform client to start selection
|
||||
LE_RACE_FINISHED, // race has finished, display result
|
||||
LE_RACE_FINISHED_ACK, // client went back to lobby
|
||||
LE_EXIT_RESULT, // Force clients to exit race result screen
|
||||
LE_VOTE_MAJOR, // vote of major race mode
|
||||
LE_VOTE_MINOR, // vote for minor race mode
|
||||
LE_VOTE_RACE_COUNT, // vote for number of tracks
|
||||
LE_VOTE_TRACK, // vote for a track
|
||||
LE_VOTE_REVERSE, // vote if race in reverse
|
||||
LE_VOTE_LAPS, // vote number of laps
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "network/stk_peer.hpp"
|
||||
#include "online/online_profile.hpp"
|
||||
#include "online/request_manager.hpp"
|
||||
#include "states_screens/race_result_gui.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/random_generator.hpp"
|
||||
#include "utils/time.hpp"
|
||||
@@ -67,7 +68,6 @@ void ServerLobbyRoomProtocol::setup()
|
||||
m_state = NetworkConfig::get()->isLAN() ? ACCEPTING_CLIENTS
|
||||
: NONE;
|
||||
m_selection_enabled = false;
|
||||
m_in_race = false;
|
||||
m_current_protocol = NULL;
|
||||
Log::info("ServerLobbyRoomProtocol", "Starting the protocol.");
|
||||
} // setup
|
||||
@@ -96,6 +96,7 @@ bool ServerLobbyRoomProtocol::notifyEventAsynchronous(Event* event)
|
||||
case LE_VOTE_TRACK: playerTrackVote(event); break;
|
||||
case LE_VOTE_REVERSE: playerReversedVote(event); break;
|
||||
case LE_VOTE_LAPS: playerLapsVote(event); break;
|
||||
case LE_RACE_FINISHED_ACK: playerFinishedResult(event); break;
|
||||
} // switch
|
||||
|
||||
} // if (event->getType() == EVENT_TYPE_MESSAGE)
|
||||
@@ -142,16 +143,38 @@ void ServerLobbyRoomProtocol::update()
|
||||
// Only poll the STK server if this is a WAN server.
|
||||
if(NetworkConfig::get()->isWAN())
|
||||
checkIncomingConnectionRequests();
|
||||
if (m_in_race && World::getWorld() &&
|
||||
break;
|
||||
}
|
||||
case SELECTING:
|
||||
break; // Nothing to do, this is event based
|
||||
case RACING:
|
||||
if (World::getWorld() &&
|
||||
RaceEventManager::getInstance<RaceEventManager>()->isRunning())
|
||||
{
|
||||
checkRaceFinished();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SELECTING_KARTS:
|
||||
break; // Nothing to do, this is event based
|
||||
case RESULT_DISPLAY:
|
||||
if(StkTime::getRealTime() > m_timeout)
|
||||
{
|
||||
// Send a notification to all clients to exit
|
||||
// the race result screen
|
||||
NetworkString *exit_result_screen = getNetworkString(1);
|
||||
exit_result_screen->setSynchronous(true);
|
||||
exit_result_screen->addUInt8(LE_EXIT_RESULT);
|
||||
sendMessageToPeersChangingToken(exit_result_screen,
|
||||
/*reliable*/true);
|
||||
delete exit_result_screen;
|
||||
m_state = ACCEPTING_CLIENTS;
|
||||
RaceResultGUI::getInstance()->backToLobby();
|
||||
// notify the network world that it is stopped
|
||||
RaceEventManager::getInstance()->stop();
|
||||
// stop race protocols
|
||||
findAndTerminateProtocol(PROTOCOL_CONTROLLER_EVENTS);
|
||||
findAndTerminateProtocol(PROTOCOL_KART_UPDATE);
|
||||
findAndTerminateProtocol(PROTOCOL_GAME_EVENTS);
|
||||
}
|
||||
break;
|
||||
case DONE:
|
||||
m_state = EXITING;
|
||||
requestTerminate();
|
||||
@@ -227,7 +250,7 @@ void ServerLobbyRoomProtocol::startGame()
|
||||
delete ns;
|
||||
Protocol *p = new StartGameProtocol(m_setup);
|
||||
p->requestStart();
|
||||
m_in_race = true;
|
||||
m_state = RACING;
|
||||
} // startGame
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -252,7 +275,7 @@ void ServerLobbyRoomProtocol::startSelection(const Event *event)
|
||||
|
||||
m_selection_enabled = true;
|
||||
|
||||
m_state = SELECTING_KARTS;
|
||||
m_state = SELECTING;
|
||||
} // startSelection
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -304,79 +327,55 @@ void ServerLobbyRoomProtocol::checkIncomingConnectionRequests()
|
||||
} // checkIncomingConnectionRequests
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void ServerLobbyRoomProtocol::checkRaceFinished()
|
||||
/** Checks if the race is finished, and if so informs the clients and switches
|
||||
* to state RESULT_DISPLAY, during which the race result gui is shown and all
|
||||
* clients can click on 'continue'.
|
||||
*/
|
||||
void ServerLobbyRoomProtocol::checkRaceFinished()
|
||||
{
|
||||
assert(RaceEventManager::getInstance()->isRunning());
|
||||
assert(World::getWorld());
|
||||
// if race is over, give the final score to everybody
|
||||
if (RaceEventManager::getInstance()->isRaceOver())
|
||||
if(!RaceEventManager::getInstance()->isRaceOver()) return;
|
||||
|
||||
m_player_ready_counter = 0;
|
||||
// Set the delay before the server forces all clients to exit the race
|
||||
// result screen and go back to the lobby
|
||||
m_timeout = (float)(StkTime::getRealTime()+15.0f);
|
||||
m_state = RESULT_DISPLAY;
|
||||
|
||||
// calculate karts ranks :
|
||||
int num_karts = race_manager->getNumberOfKarts();
|
||||
std::vector<int> karts_results;
|
||||
std::vector<float> karts_times;
|
||||
for (int j = 0; j < num_karts; j++)
|
||||
{
|
||||
// calculate karts ranks :
|
||||
int num_players = race_manager->getNumberOfKarts();
|
||||
std::vector<int> karts_results;
|
||||
std::vector<float> karts_times;
|
||||
for (int j = 0; j < num_players; j++)
|
||||
float kart_time = race_manager->getKartRaceTime(j);
|
||||
for (unsigned int i = 0; i < karts_times.size(); i++)
|
||||
{
|
||||
float kart_time = race_manager->getKartRaceTime(j);
|
||||
for (unsigned int i = 0; i < karts_times.size(); i++)
|
||||
if (kart_time < karts_times[i])
|
||||
{
|
||||
if (kart_time < karts_times[i])
|
||||
{
|
||||
karts_times.insert(karts_times.begin()+i, kart_time);
|
||||
karts_results.insert(karts_results.begin()+i, j);
|
||||
break;
|
||||
}
|
||||
karts_times.insert(karts_times.begin() + i, kart_time);
|
||||
karts_results.insert(karts_results.begin() + i, j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<STKPeer*> &peers = STKHost::get()->getPeers();
|
||||
|
||||
NetworkString *total = getNetworkString(1+karts_results.size());
|
||||
total->setSynchronous(true);
|
||||
total->addUInt8(LE_RACE_FINISHED);
|
||||
for (unsigned int i = 0; i < karts_results.size(); i++)
|
||||
{
|
||||
total->addUInt8(karts_results[i]); // kart pos = i+1
|
||||
Log::info("ServerLobbyRoomProtocol", "Kart %d finished #%d",
|
||||
karts_results[i], i + 1);
|
||||
}
|
||||
sendMessageToPeersChangingToken(total, /*reliable*/ true);
|
||||
delete total;
|
||||
Log::info("ServerLobbyRoomProtocol", "End of game message sent");
|
||||
m_in_race = false;
|
||||
|
||||
// stop race protocols
|
||||
Protocol* protocol = ProtocolManager::getInstance()
|
||||
->getProtocol(PROTOCOL_CONTROLLER_EVENTS);
|
||||
if (protocol)
|
||||
protocol->requestTerminate();
|
||||
else
|
||||
Log::error("ClientLobbyRoomProtocol",
|
||||
"No controller events protocol registered.");
|
||||
|
||||
protocol = ProtocolManager::getInstance()
|
||||
->getProtocol(PROTOCOL_KART_UPDATE);
|
||||
if (protocol)
|
||||
protocol->requestTerminate();
|
||||
else
|
||||
Log::error("ClientLobbyRoomProtocol",
|
||||
"No kart update protocol registered.");
|
||||
|
||||
protocol = ProtocolManager::getInstance()
|
||||
->getProtocol(PROTOCOL_GAME_EVENTS);
|
||||
if (protocol)
|
||||
protocol->requestTerminate();
|
||||
else
|
||||
Log::error("ClientLobbyRoomProtocol",
|
||||
"No game events protocol registered.");
|
||||
|
||||
// notify the network world that it is stopped
|
||||
RaceEventManager::getInstance()->stop();
|
||||
// exit the race now
|
||||
race_manager->exitRace();
|
||||
race_manager->setAIKartOverride("");
|
||||
}
|
||||
|
||||
const std::vector<STKPeer*> &peers = STKHost::get()->getPeers();
|
||||
|
||||
NetworkString *total = getNetworkString(1 + karts_results.size());
|
||||
total->setSynchronous(true);
|
||||
total->addUInt8(LE_RACE_FINISHED);
|
||||
for (unsigned int i = 0; i < karts_results.size(); i++)
|
||||
{
|
||||
total->addUInt8(karts_results[i]); // kart pos = i+1
|
||||
Log::info("ServerLobbyRoomProtocol", "Kart %d finished #%d",
|
||||
karts_results[i], i + 1);
|
||||
}
|
||||
sendMessageToPeersChangingToken(total, /*reliable*/ true);
|
||||
delete total;
|
||||
Log::info("ServerLobbyRoomProtocol", "End of game message sent");
|
||||
|
||||
} // checkRaceFinished
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -522,7 +521,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event)
|
||||
*/
|
||||
void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event)
|
||||
{
|
||||
if(m_state!=SELECTING_KARTS)
|
||||
if(m_state!=SELECTING)
|
||||
{
|
||||
Log::warn("Server", "Received kart selection while in state %d.",
|
||||
m_state);
|
||||
@@ -751,3 +750,19 @@ void ServerLobbyRoomProtocol::playerLapsVote(Event* event)
|
||||
} // playerLapsVote
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called when a client clicks on 'ok' on the race result screen.
|
||||
* If all players have clicked on 'ok', go back to the lobby.
|
||||
*/
|
||||
void ServerLobbyRoomProtocol::playerFinishedResult(Event *event)
|
||||
{
|
||||
m_player_ready_counter++;
|
||||
if(m_player_ready_counter == STKHost::get()->getPeerCount())
|
||||
{
|
||||
// We can't trigger the world/race exit here, since this is called
|
||||
// from the protocol manager thread. So instead we force the timeout
|
||||
// to get triggered (which is done from the main thread):
|
||||
m_timeout = 0;
|
||||
}
|
||||
} // playerFinishedResult
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -13,10 +13,12 @@ private:
|
||||
enum
|
||||
{
|
||||
NONE,
|
||||
GETTING_PUBLIC_ADDRESS,
|
||||
ACCEPTING_CLIENTS,
|
||||
SELECTING_KARTS,
|
||||
DONE,
|
||||
GETTING_PUBLIC_ADDRESS, // Waiting to receive its public ip address
|
||||
ACCEPTING_CLIENTS, // In lobby, accepting clients
|
||||
SELECTING, // kart, track, ... selection started
|
||||
RACING, // racing
|
||||
RESULT_DISPLAY, // Show result screen
|
||||
DONE, // shutting down server
|
||||
EXITING
|
||||
} m_state;
|
||||
|
||||
@@ -25,7 +27,12 @@ private:
|
||||
|
||||
Protocol *m_current_protocol;
|
||||
bool m_selection_enabled;
|
||||
bool m_in_race;
|
||||
|
||||
/** Counts how many players are ready to go on. */
|
||||
int m_player_ready_counter;
|
||||
|
||||
/** Timeout counter for showing the result screen. */
|
||||
float m_timeout;
|
||||
|
||||
// connection management
|
||||
void clientDisconnected(Event* event);
|
||||
@@ -39,6 +46,7 @@ private:
|
||||
void playerTrackVote(Event* event);
|
||||
void playerReversedVote(Event* event);
|
||||
void playerLapsVote(Event* event);
|
||||
void playerFinishedResult(Event *event);
|
||||
void registerServer();
|
||||
|
||||
public:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -213,6 +213,7 @@ public:
|
||||
Input::InputType type, int playerId) OVERRIDE;
|
||||
void eventCallback(GUIEngine::Widget* widget, const std::string& name,
|
||||
const int playerID) OVERRIDE;
|
||||
void backToLobby();
|
||||
|
||||
|
||||
friend class GUIEngine::ScreenSingleton<RaceResultGUI>;
|
||||
|
||||
Reference in New Issue
Block a user