Added end of race handling, so that clients and server shut

down properly and go back to the lobby.
This commit is contained in:
hiker
2016-03-17 17:19:21 +11:00
parent 094a87eb94
commit b6bcf33ae0
10 changed files with 1167 additions and 1094 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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