implementing the race vote network communications

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/hilnius@14135 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hilnius 2013-09-22 20:40:14 +00:00
parent a637ce6e36
commit 26321be49d
11 changed files with 863 additions and 71 deletions

Binary file not shown.

View File

@ -44,14 +44,6 @@ void* waitInput(void* data)
{
stop = true;
}
else if (str == "disconnect")
{
NetworkManager::getInstance()->getPeers()[0]->disconnect();
}
else if (str == "connect")
{
ProtocolManager::getInstance()->requestStart(new ConnectToServer());
}
else if (str == "select")
{
std::string str2;
@ -60,9 +52,48 @@ void* waitInput(void* data)
ClientLobbyRoomProtocol* clrp = static_cast<ClientLobbyRoomProtocol*>(protocol);
clrp->requestKartSelection(str2);
}
else if (str == "synchronize")
else if (str == "vote")
{
ProtocolManager::getInstance()->requestStart(new SynchronizationProtocol());
std::cout << "Vote for ? (track/laps/reversed/major/minor/race#) :";
std::string str2;
getline(std::cin, str2);
Protocol* protocol = ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM);
ClientLobbyRoomProtocol* clrp = static_cast<ClientLobbyRoomProtocol*>(protocol);
if (str2 == "track")
{
std::cin >> str2;
clrp->voteTrack(str2);
}
else if (str2 == "laps")
{
int cnt;
std::cin >> cnt;
clrp->voteLaps(cnt);
}
else if (str2 == "reversed")
{
bool cnt;
std::cin >> cnt;
clrp->voteReversed(cnt);
}
else if (str2 == "major")
{
int cnt;
std::cin >> cnt;
clrp->voteMajor(cnt);
}
else if (str2 == "minor")
{
int cnt;
std::cin >> cnt;
clrp->voteMinor(cnt);
}
else if (str2 == "race#")
{
int cnt;
std::cin >> cnt;
clrp->voteRaceCount(cnt);
}
}
else if (NetworkManager::getInstance()->getPeers().size() > 0)
{

View File

@ -19,6 +19,7 @@
#include "network/protocol.hpp"
#include "network/protocol_manager.hpp"
#include "network/network_manager.hpp"
Protocol::Protocol(CallbackObject* callback_object, PROTOCOL_TYPE type)
{
@ -52,3 +53,47 @@ PROTOCOL_TYPE Protocol::getProtocolType()
{
return m_type;
}
bool Protocol::checkDataSizeAndToken(Event* event, int minimum_size)
{
NetworkString data = event->data();
if (data.size() < minimum_size || data[0] != 4)
{
Log::warn("Protocol", "Receiving a badly "
"formated message. Size is %d and first byte %d",
data.size(), data[0]);
return false;
}
STKPeer* peer = *(event->peer);
uint32_t token = data.gui32(1);
if (token != peer->getClientServerToken())
{
Log::warn("Protocol", "Peer sending bad token. Request "
"aborted.");
return false;
}
return true;
}
bool Protocol::isByteCorrect(Event* event, int byte_nb, int value)
{
NetworkString data = event->data();
if (data[byte_nb] != value)
{
Log::info("Protocol", "Bad byte at pos %d. %d "
"should be %d", byte_nb, data[byte_nb], value);
return false;
}
return true;
}
void Protocol::sendMessageToPeersChangingToken(NetworkString prefix, NetworkString message)
{
std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers();
for (unsigned int i = 0; i < peers.size(); i++)
{
prefix.ai8(4).ai32(peers[i]->getClientServerToken());
prefix += message;
m_listener->sendMessage(this, peers[i], prefix);
}
}

View File

@ -112,6 +112,13 @@ class Protocol
* \return The protocol type.
*/
PROTOCOL_TYPE getProtocolType();
/// functions to check incoming data easily
bool checkDataSizeAndToken(Event* event, int minimum_size);
bool isByteCorrect(Event* event, int byte_nb, int value);
void sendMessageToPeersChangingToken(NetworkString prefix, NetworkString message);
protected:
ProtocolManager* m_listener; //!< The protocol listener
PROTOCOL_TYPE m_type; //!< The type of the protocol

View File

@ -46,6 +46,7 @@ ClientLobbyRoomProtocol::~ClientLobbyRoomProtocol()
void ClientLobbyRoomProtocol::setup()
{
m_setup = NetworkManager::getInstance()->setupNewGame(); // create a new setup
m_setup->getRaceConfig()->setPlayerCount(16); //FIXME : this has to be changed when logging into the server
m_state = NONE;
}
@ -56,7 +57,67 @@ void ClientLobbyRoomProtocol::requestKartSelection(std::string kart_name)
NetworkString request;
// 0x02 : kart selection request, size_token (4), token, size kart name, kart name
request.ai8(0x02).ai8(4).ai32(m_server->getClientServerToken()).ai8(kart_name.size()).as(kart_name);
m_listener->sendMessage(this, request);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::voteMajor(uint8_t major)
{
NetworkString request;
// 0xc0 : major vote, size_token (4), token, size major(1),major
request.ai8(0xc0).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(major);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::voteRaceCount(uint8_t count)
{
NetworkString request;
// 0xc0 : race count vote, size_token (4), token, size race count(1), count
request.ai8(0xc1).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(count);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::voteMinor(uint8_t minor)
{
NetworkString request;
// 0xc0 : minor vote, size_token (4), token, size minor(1),minor
request.ai8(0xc2).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(minor);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::voteTrack(std::string track, uint8_t track_nb)
{
NetworkString request;
// 0xc0 : major vote, size_token (4), token, size track, track, size #track, #track
request.ai8(0xc3).ai8(4).ai32(m_server->getClientServerToken()).ai8(track.size()).as(track).ai8(1).ai8(track_nb);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::voteReversed(bool reversed, uint8_t track_nb)
{
NetworkString request;
// 0xc0 : major vote, size_token (4), token, size reversed(1),reversed, size #track, #track
request.ai8(0xc4).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(reversed).ai8(1).ai8(track_nb);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
void ClientLobbyRoomProtocol::voteLaps(uint8_t laps, uint8_t track_nb)
{
NetworkString request;
// 0xc0 : major vote, size_token (4), token, size laps(1),laps, size #track, #track
request.ai8(0xc5).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(laps).ai8(1).ai8(track_nb);
m_listener->sendMessage(this, request, true);
}
//-----------------------------------------------------------------------------
@ -124,6 +185,18 @@ bool ClientLobbyRoomProtocol::notifyEventAsynchronous(Event* event)
connectionAccepted(event);
else if (message_type == 0x82) // kart selection refused
kartSelectionRefused(event);
else if (message_type == 0xc0) // vote for major mode
playerMajorVote(event);
else if (message_type == 0xc1) // vote for race count
playerRaceCountVote(event);
else if (message_type == 0xc2) // vote for minor mode
playerMinorVote(event);
else if (message_type == 0xc3) // vote for track
playerTrackVote(event);
else if (message_type == 0xc4) // vote for reversed mode
playerReversedVote(event);
else if (message_type == 0xc5) // vote for laps
playerLapsVote(event);
return true;
} // message
@ -589,3 +662,145 @@ void ClientLobbyRoomProtocol::raceFinished(Event* event)
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for a major race mode.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9
* --------------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 |
* Data | 4 | priv token | 1 | player id | 1 | major mode vote |
* --------------------------------------------------------
*/
void ClientLobbyRoomProtocol::playerMajorVote(Event* event)
{
NetworkString data = event->data();
if (!checkDataSizeAndToken(event, 9))
return;
if (!isByteCorrect(event, 5, 1))
return;
if (!isByteCorrect(event, 7, 1))
return;
m_setup->getRaceConfig()->setPlayerMajorVote(data[6], data[8]);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for the number of races in a GP.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9
* ----------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 |
* Data | 4 | priv token | 1 | player id | 1 | races count |
* ----------------------------------------------------
*/
void ClientLobbyRoomProtocol::playerRaceCountVote(Event* event)
{
NetworkString data = event->data();
if (!checkDataSizeAndToken(event, 9))
return;
if (!isByteCorrect(event, 5, 1))
return;
if (!isByteCorrect(event, 7, 1))
return;
m_setup->getRaceConfig()->setPlayerRaceCountVote(data[6], data[8]);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for a minor race mode.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9
* --------------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 |
* Data | 4 | priv token | 1 | player id | 1 | minor mode vote |
* --------------------------------------------------------
*/
void ClientLobbyRoomProtocol::playerMinorVote(Event* event)
{
NetworkString data = event->data();
if (!checkDataSizeAndToken(event, 9))
return;
if (!isByteCorrect(event, 5, 1))
return;
if (!isByteCorrect(event, 7, 1))
return;
m_setup->getRaceConfig()->setPlayerMinorVote(data[6], data[8]);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for a track.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 N+8 N+9 N+10
* ---------------------------------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | N | 1 | 1 |
* Data | 4 | priv token | 1 | player id | N | track name | 1 | track number (gp) |
* ---------------------------------------------------------------------------
*/
void ClientLobbyRoomProtocol::playerTrackVote(Event* event)
{
NetworkString data = event->data();
if (!checkDataSizeAndToken(event, 10))
return;
if (!isByteCorrect(event, 5, 1))
return;
int N = data[7];
std::string track_name = data.gs(8, N);
if (!isByteCorrect(event, N+8, 1))
return;
m_setup->getRaceConfig()->setPlayerTrackVote(data[6], track_name, data[N+9]);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for the reverse mode of a race
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9 10 11
* -------------------------------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 | 1 | 1 |
* Data | 4 | priv token | 1 | player id | 1 | reversed | 1 | track number (gp) |
* -------------------------------------------------------------------------
*/
void ClientLobbyRoomProtocol::playerReversedVote(Event* event)
{
NetworkString data = event->data();
if (!checkDataSizeAndToken(event, 11))
return;
if (!isByteCorrect(event, 5, 1))
return;
if (!isByteCorrect(event, 7, 1))
return;
if (!isByteCorrect(event, 9, 1))
return;
m_setup->getRaceConfig()->setPlayerReversedVote(data[6], data[8], data[10]);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for a major race mode.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9 10 11
* ---------------------------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 | 1 | 1 |
* Data | 4 | priv token | 1 | player id | 1 | laps | 1 | track number (gp) |
* ---------------------------------------------------------------------
*/
void ClientLobbyRoomProtocol::playerLapsVote(Event* event)
{
NetworkString data = event->data();
if (!checkDataSizeAndToken(event, 9))
return;
if (!isByteCorrect(event, 5, 1))
return;
if (!isByteCorrect(event, 7, 1))
return;
m_setup->getRaceConfig()->setPlayerLapsVote(data[6], data[8], data[10]);
}
//-----------------------------------------------------------------------------

View File

@ -10,6 +10,12 @@ class ClientLobbyRoomProtocol : public LobbyRoomProtocol
virtual ~ClientLobbyRoomProtocol();
void requestKartSelection(std::string kart_name);
void voteMajor(uint8_t major);
void voteRaceCount(uint8_t count);
void voteMinor(uint8_t minor);
void voteTrack(std::string track, uint8_t track_nb = 0);
void voteReversed(bool reversed, uint8_t track_nb = 0);
void voteLaps(uint8_t laps, uint8_t track_nb = 0);
void sendMessage(std::string message);
void leave();
@ -29,6 +35,13 @@ class ClientLobbyRoomProtocol : public LobbyRoomProtocol
void startGame(Event* event);
void startSelection(Event* event);
void raceFinished(Event* event);
// race votes
void playerMajorVote(Event* event);
void playerRaceCountVote(Event* event);
void playerMinorVote(Event* event);
void playerTrackVote(Event* event);
void playerReversedVote(Event* event);
void playerLapsVote(Event* event);
TransportAddress m_server_address;
STKPeer* m_server;

View File

@ -34,6 +34,7 @@
#include "utils/time.hpp"
#include "utils/random_generator.hpp"
ServerLobbyRoomProtocol::ServerLobbyRoomProtocol() : LobbyRoomProtocol(NULL)
{
}
@ -49,6 +50,7 @@ ServerLobbyRoomProtocol::~ServerLobbyRoomProtocol()
void ServerLobbyRoomProtocol::setup()
{
m_setup = NetworkManager::getInstance()->setupNewGame(); // create a new setup
m_setup->getRaceConfig()->setPlayerCount(16); //FIXME : this has to be moved to when logging into the server
m_next_id = 0;
m_state = NONE;
m_public_address.ip = 0;
@ -73,8 +75,20 @@ bool ServerLobbyRoomProtocol::notifyEventAsynchronous(Event* event)
Log::info("ServerLobbyRoomProtocol", "Message received with type %d.", message_type);
if (message_type == 0x01) // player requesting connection
connectionRequested(event);
if (message_type == 0x02) // player requesting kart selection
else if (message_type == 0x02) // player requesting kart selection
kartSelectionRequested(event);
else if (message_type == 0xc0) // vote for major mode
playerMajorVote(event);
else if (message_type == 0xc1) // vote for race count
playerRaceCountVote(event);
else if (message_type == 0xc2) // vote for minor mode
playerMinorVote(event);
else if (message_type == 0xc3) // vote for track
playerTrackVote(event);
else if (message_type == 0xc4) // vote for reversed mode
playerReversedVote(event);
else if (message_type == 0xc5) // vote for laps
playerLapsVote(event);
} // if (event->type == EVENT_TYPE_MESSAGE)
else if (event->type == EVENT_TYPE_CONNECTED)
{
@ -404,21 +418,10 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event)
void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event)
{
NetworkString data = event->data();
if (data.size() < 6 || data[0] != 4)
{
Log::warn("ServerLobbyRoomProtocol", "Receiving a badly "
"formated message. Size is %d and first byte %d",
data.size(), data[0]);
return;
}
STKPeer* peer = *(event->peer);
uint32_t token = data.gui32(1);
if (token != peer->getClientServerToken())
{
Log::warn("ServerLobbyRoomProtocol", "Peer sending bad token. Request "
"aborted.");
if (!checkDataSizeAndToken(event, 6))
return;
}
uint8_t kart_name_size = data.gui8(5);
std::string kart_name = data.gs(6, kart_name_size);
if (kart_name.size() != kart_name_size)
@ -462,3 +465,195 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event)
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for a major race mode.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7
* ----------------------------------------
* Size | 1 | 4 | 1 | 1 |
* Data | 4 | priv token | 1 | major mode vote |
* ----------------------------------------
*/
void ServerLobbyRoomProtocol::playerMajorVote(Event* event)
{
NetworkString data = event->data();
STKPeer* peer = *(event->peer);
if (!checkDataSizeAndToken(event, 7))
return;
if (!isByteCorrect(event, 5, 1))
return;
uint8_t player_id = peer->getPlayerProfile()->race_id;
m_setup->getRaceConfig()->setPlayerMajorVote(player_id, data[6]);
// Send the vote to everybody (including the sender)
NetworkString other;
other.ai8(1).ai8(player_id); // add the player id
data.removeFront(5); // remove the token
other += data; // add the data
NetworkString prefix;
prefix.ai8(0xc0); // prefix the token with the ype
sendMessageToPeersChangingToken(prefix, other);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for the number of races in a GP.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7
* ------------------------------------
* Size | 1 | 4 | 1 | 1 |
* Data | 4 | priv token | 1 | races count |
* ------------------------------------
*/
void ServerLobbyRoomProtocol::playerRaceCountVote(Event* event)
{
NetworkString data = event->data();
STKPeer* peer = *(event->peer);
if (!checkDataSizeAndToken(event, 7))
return;
if (!isByteCorrect(event, 5, 1))
return;
uint8_t player_id = peer->getPlayerProfile()->race_id;
m_setup->getRaceConfig()->setPlayerRaceCountVote(player_id, data[6]);
// Send the vote to everybody (including the sender)
NetworkString other;
other.ai8(1).ai8(player_id); // add the player id
data.removeFront(5); // remove the token
other += data; // add the data
NetworkString prefix;
prefix.ai8(0xc1); // prefix the token with the ype
sendMessageToPeersChangingToken(prefix, other);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for a minor race mode.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7
* ----------------------------------------
* Size | 1 | 4 | 1 | 1 |
* Data | 4 | priv token | 1 | minor mode vote |
* ----------------------------------------
*/
void ServerLobbyRoomProtocol::playerMinorVote(Event* event)
{
NetworkString data = event->data();
STKPeer* peer = *(event->peer);
if (!checkDataSizeAndToken(event, 7))
return;
if (!isByteCorrect(event, 5, 1))
return;
uint8_t player_id = peer->getPlayerProfile()->race_id;
m_setup->getRaceConfig()->setPlayerMinorVote(player_id, data[6]);
// Send the vote to everybody (including the sender)
NetworkString other;
other.ai8(1).ai8(player_id); // add the player id
data.removeFront(5); // remove the token
other += data; // add the data
NetworkString prefix;
prefix.ai8(0xc2); // prefix the token with the ype
sendMessageToPeersChangingToken(prefix, other);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for a track.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 N+6 N+7 N+8
* -----------------------------------------------------------
* Size | 1 | 4 | 1 | N | 1 | 1 |
* Data | 4 | priv token | N | track name | 1 | track number (gp) |
* -----------------------------------------------------------
*/
void ServerLobbyRoomProtocol::playerTrackVote(Event* event)
{
NetworkString data = event->data();
STKPeer* peer = *(event->peer);
if (!checkDataSizeAndToken(event, 8))
return;
int N = data[5];
std::string track_name = data.gs(5, N);
if (!isByteCorrect(event, N+6, 1))
return;
uint8_t player_id = peer->getPlayerProfile()->race_id;
m_setup->getRaceConfig()->setPlayerTrackVote(player_id, track_name, data[N+7]);
// Send the vote to everybody (including the sender)
NetworkString other;
other.ai8(1).ai8(player_id); // add the player id
data.removeFront(5); // remove the token
other += data; // add the data
NetworkString prefix;
prefix.ai8(0xc3); // prefix the token with the ype
sendMessageToPeersChangingToken(prefix, other);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for the reverse mode of a race
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9
* ---------------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 |
* Data | 4 | priv token | 1 | reversed | 1 | track number (gp) |
* ---------------------------------------------------------
*/
void ServerLobbyRoomProtocol::playerReversedVote(Event* event)
{
NetworkString data = event->data();
STKPeer* peer = *(event->peer);
if (!checkDataSizeAndToken(event, 9))
return;
if (!isByteCorrect(event, 5, 1))
return;
if (!isByteCorrect(event, 7, 1))
return;
uint8_t player_id = peer->getPlayerProfile()->race_id;
m_setup->getRaceConfig()->setPlayerReversedVote(player_id, data[6], data[8]);
// Send the vote to everybody (including the sender)
NetworkString other;
other.ai8(1).ai8(player_id); // add the player id
data.removeFront(5); // remove the token
other += data; // add the data
NetworkString prefix;
prefix.ai8(0xc4); // prefix the token with the ype
sendMessageToPeersChangingToken(prefix, other);
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player votes for a major race mode.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 7 8 9
* -----------------------------------------------------
* Size | 1 | 4 | 1 | 1 | 1 | 1 |
* Data | 4 | priv token | 1 | laps | 1 | track number (gp) |
* -----------------------------------------------------
*/
void ServerLobbyRoomProtocol::playerLapsVote(Event* event)
{
NetworkString data = event->data();
STKPeer* peer = *(event->peer);
if (!checkDataSizeAndToken(event, 9))
return;
if (!isByteCorrect(event, 5, 1))
return;
if (!isByteCorrect(event, 7, 1))
return;
uint8_t player_id = peer->getPlayerProfile()->race_id;
m_setup->getRaceConfig()->setPlayerLapsVote(player_id, data[6], data[8]);
// Send the vote to everybody (including the sender)
NetworkString other;
other.ai8(1).ai8(player_id); // add the player id
data.removeFront(5); // remove the token
other += data; // add the data
NetworkString prefix;
prefix.ai8(0xc5); // prefix the token with the ype
sendMessageToPeersChangingToken(prefix, other);
}
//-----------------------------------------------------------------------------

View File

@ -20,9 +20,18 @@ class ServerLobbyRoomProtocol : public LobbyRoomProtocol
void checkRaceFinished();
protected:
// connection management
void kartDisconnected(Event* event);
void connectionRequested(Event* event);
// kart selection
void kartSelectionRequested(Event* event);
// race votes
void playerMajorVote(Event* event);
void playerRaceCountVote(Event* event);
void playerMinorVote(Event* event);
void playerTrackVote(Event* event);
void playerReversedVote(Event* event);
void playerLapsVote(Event* event);
uint8_t m_next_id; //!< Next id to assign to a peer.
std::vector<TransportAddress> m_peers;

View File

@ -1,12 +1,17 @@
#include "network/race_config.hpp"
#include "race/race_manager.hpp"
#include "utils/log.hpp"
/** \brief Gets the element with the highest count in a std::map<S,int>.
* \param histogram : A pointer to the histogram.
* \return The key of type S that has the highest second value.
*/
template<typename S>
S getHighestInHistogram(std::map<S,int>* histogram)
{
S best_item;
int highest_count;
uint8_t highest_count;
for (typename std::map<S, int>::iterator it = histogram->begin();
it != histogram->end(); it++)
{
@ -20,6 +25,9 @@ S getHighestInHistogram(std::map<S,int>* histogram)
}
//-----------------------------------------------------------------------------
//--------------------------------- TrackVote --------------------------------
//-----------------------------------------------------------------------------
TrackVote::TrackVote()
{
has_voted_laps = false;
@ -39,12 +47,136 @@ void TrackVote::voteReversed(bool reversed)
has_voted_reversed = true;
}
//-----------------------------------------------------------------------------
void TrackVote::voteLaps(int laps)
void TrackVote::voteLaps(uint8_t laps)
{
track_info.laps = laps;
has_voted_laps = true;
}
//-----------------------------------------------------------------------------
//--------------------------------- RaceVote ---------------------------------
//-----------------------------------------------------------------------------
RaceVote::RaceVote()
{
m_has_voted_major = false;
m_has_voted_minor = false;
m_has_voted_races_count = false;
m_major_mode = 0;
m_minor_mode = 0;
m_races_count = 0;
}
//-----------------------------------------------------------------------------
void RaceVote::voteMajor(uint8_t major)
{
m_has_voted_major = true;
m_major_mode = major;
}
//-----------------------------------------------------------------------------
void RaceVote::voteRaceCount(uint8_t count)
{
m_has_voted_races_count = true;
m_races_count = count;
}
//-----------------------------------------------------------------------------
void RaceVote::voteMinor(uint8_t minor)
{
m_has_voted_minor = true;
m_minor_mode = minor;
}
//-----------------------------------------------------------------------------
void RaceVote::voteTrack(std::string track, uint8_t track_number)
{
m_tracks_vote[track_number].voteTrack(track);
}
//-----------------------------------------------------------------------------
void RaceVote::voteReversed(bool reversed, uint8_t track_number)
{
m_tracks_vote[track_number].voteReversed(reversed);
}
//-----------------------------------------------------------------------------
void RaceVote::voteLaps(uint8_t laps, uint8_t track_number)
{
m_tracks_vote[track_number].voteLaps(laps);
}
//-----------------------------------------------------------------------------
bool RaceVote::hasVotedMajor() const
{
return m_has_voted_major;
}
//-----------------------------------------------------------------------------
bool RaceVote::hasVotedRacesCount() const
{
return m_has_voted_races_count;
}
//-----------------------------------------------------------------------------
bool RaceVote::hasVotedMinor() const
{
return m_has_voted_minor;
}
//-----------------------------------------------------------------------------
bool RaceVote::hasVotedTrack(uint8_t track_number) const
{
return m_tracks_vote[track_number].has_voted_track;
}
//-----------------------------------------------------------------------------
bool RaceVote::hasVotedReversed(uint8_t track_number) const
{
return m_tracks_vote[track_number].has_voted_reversed;
}
//-----------------------------------------------------------------------------
bool RaceVote::hasVotedLaps(uint8_t track_number) const
{
return m_tracks_vote[track_number].has_voted_laps;
}
//-----------------------------------------------------------------------------
uint8_t RaceVote::getMajorVote() const
{
return m_major_mode;
}
//-----------------------------------------------------------------------------
uint8_t RaceVote::getRacesCountVote() const
{
return m_races_count;
}
//-----------------------------------------------------------------------------
uint8_t RaceVote::getMinorVote() const
{
return m_minor_mode;
}
//-----------------------------------------------------------------------------
std::string RaceVote::getTrackVote(uint8_t track_number) const
{
return m_tracks_vote[track_number].track_info.track;
}
//-----------------------------------------------------------------------------
bool RaceVote::getReversedVote(uint8_t track_number) const
{
return m_tracks_vote[track_number].track_info.reversed;
}
//-----------------------------------------------------------------------------
uint8_t RaceVote::getLapsVote(uint8_t track_number) const
{
return m_tracks_vote[track_number].track_info.laps;
}
//-----------------------------------------------------------------------------
//--------------------------------- RaceConfig -------------------------------
//-----------------------------------------------------------------------------
RaceConfig::RaceConfig()
@ -54,7 +186,7 @@ RaceConfig::RaceConfig()
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerCount(int count)
void RaceConfig::setPlayerCount(uint8_t count)
{
m_max_players = count;
m_votes.resize(m_max_players);
@ -62,28 +194,118 @@ void RaceConfig::setPlayerCount(int count)
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerTrackVote(int player_id, std::string track_name)
void RaceConfig::setPlayerMajorVote(uint8_t player_id, uint8_t major)
{
m_votes[player_id].voteTrack(track_name);
Log::info("RaceConfig", "Player %d voted for major %d", player_id, major);
m_votes[player_id].voteMajor(major);
}
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerReverseVote(int player_id, bool reversed)
void RaceConfig::setPlayerRaceCountVote(uint8_t player_id, uint8_t count)
{
m_votes[player_id].voteReversed(reversed);
Log::info("RaceConfig", "Player %d voted for %d races in GP", player_id, count);
m_votes[player_id].voteRaceCount(count);
}
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerLapVote(int player_id, int lap_count)
void RaceConfig::setPlayerMinorVote(uint8_t player_id, uint8_t minor)
{
m_votes[player_id].voteLaps(lap_count);
Log::info("RaceConfig", "Player %d voted for minor %d", player_id, minor);
m_votes[player_id].voteMinor(minor);
}
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerTrackVote(uint8_t player_id, std::string track, uint8_t track_nb)
{
Log::info("RaceConfig", "Player %d voted for track %s", player_id, track.c_str());
m_votes[player_id].voteTrack(track, track_nb);
}
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerReversedVote(uint8_t player_id, bool reversed, uint8_t track_nb)
{
if (reversed)
Log::info("RaceConfig", "Player %d voted map %d to be reversed", player_id, track_nb);
else
Log::info("RaceConfig", "Player %d voted map %d NOT to be reversed", player_id, track_nb);
m_votes[player_id].voteReversed(reversed, track_nb);
}
//-----------------------------------------------------------------------------
void RaceConfig::setPlayerLapsVote(uint8_t player_id, uint8_t lap_count, uint8_t track_nb)
{
Log::info("RaceConfig", "Player %d voted map %d to have %d laps", player_id, track_nb, lap_count);
m_votes[player_id].voteLaps(lap_count, track_nb);
}
//-----------------------------------------------------------------------------
void RaceConfig::computeRaceMode()
{
// calculate the race type and number of tracks (in GP mode).
std::map<int,int> major_histogram;
std::map<int,int> races_count_histogram;
std::map<int,int> minor_histogram;
for (unsigned int i = 0; i < m_max_players; i++)
{
// increase the count of votes
if (m_votes[i].hasVotedMajor())
{
try
{
major_histogram.at(m_votes[i].getMajorVote()) ++;
}
catch (const std::out_of_range& oor) // doesn't exist in the map
{
major_histogram[m_votes[i].getMajorVote()] = 1;
}
}
else if (m_votes[i].hasVotedRacesCount())
{
try
{
races_count_histogram.at(m_votes[i].getRacesCountVote()) ++;
}
catch (const std::out_of_range& oor) // doesn't exist in the map
{
races_count_histogram[m_votes[i].getRacesCountVote()] = 1;
}
}
else if (m_votes[i].hasVotedMinor())
{
try
{
minor_histogram.at(m_votes[i].getMinorVote()) ++;
}
catch (const std::out_of_range& oor) // doesn't exist in the map
{
minor_histogram[m_votes[i].getMinorVote()] = 1;
}
}
}
// now we know :
m_major_mode = ((major_histogram.size() > 0) ? getHighestInHistogram<int>(&major_histogram) : 1);
m_races_count = ((minor_histogram.size() > 0) ? getHighestInHistogram<int>(&races_count_histogram) : 1);
m_minor_mode = ((minor_histogram.size() > 0) ? getHighestInHistogram<int>(&minor_histogram) : 0);
if (m_major_mode == RaceManager::MAJOR_MODE_GRAND_PRIX)
m_tracks.resize(m_races_count);
else
{
m_tracks.resize(1);
m_races_count = 1;
}
Log::info("RaceConfig", "Major mode will be %d with %d races. Minor is %d", m_major_mode, m_races_count, m_minor_mode);
}
void RaceConfig::computeNextTrack()
{
for (unsigned int j = 0; j < m_races_count; j++)
{
// first create histograms of the votes
std::map<std::string,int> tracks_histogram;
@ -92,51 +314,56 @@ void RaceConfig::computeNextTrack()
for (unsigned int i = 0; i < m_max_players; i++)
{
// increase the count of votes
if (m_votes[i].has_voted_track)
if (m_votes[i].hasVotedTrack())
{
try // maps
{
tracks_histogram.at(m_votes[i].track_info.track) ++;
tracks_histogram.at(m_votes[i].getTrackVote()) ++;
}
catch (const std::out_of_range& oor) // doesn't exist in the map : add it
catch (const std::out_of_range& oor) // doesn't exist in the map
{
tracks_histogram[m_votes[i].track_info.track] = 1;
tracks_histogram[m_votes[i].getTrackVote()] = 1;
}
}
else if (m_votes[i].has_voted_reversed)
else if (m_votes[i].hasVotedReversed())
{
try // reversed
{
reversed_histogram.at(m_votes[i].track_info.reversed) ++;
reversed_histogram.at(m_votes[i].getReversedVote()) ++;
}
catch (const std::out_of_range& oor) // doesn't exist in the map : add it
catch (const std::out_of_range& oor) // doesn't exist in the map
{
reversed_histogram[m_votes[i].track_info.reversed] = 1;
reversed_histogram[m_votes[i].getReversedVote()] = 1;
}
}
else if (m_votes[i].has_voted_laps)
else if (m_votes[i].hasVotedLaps())
{
try // laps
{
laps_histogram.at(m_votes[i].track_info.laps) ++;
laps_histogram.at(m_votes[i].getLapsVote()) ++;
}
catch (const std::out_of_range& oor) // doesn't exist in the map : add it
catch (const std::out_of_range& oor) // doesn't exist in the mapt
{
laps_histogram[m_votes[i].track_info.laps] = 1;
laps_histogram[m_votes[i].getLapsVote()] = 1;
}
}
}
// now find the highest votes
m_track.track = getHighestInHistogram<std::string>(&tracks_histogram);
m_track.reversed = getHighestInHistogram<bool>(&reversed_histogram);
m_track.laps = getHighestInHistogram<int>(&laps_histogram);
m_tracks[j].track = getHighestInHistogram<std::string>(&tracks_histogram);
m_tracks[j].reversed = getHighestInHistogram<bool>(&reversed_histogram);
m_tracks[j].laps = getHighestInHistogram<int>(&laps_histogram);
if (m_tracks[j].reversed)
Log::info("RaceConfig", "Race %d will be on %s with %d laps and reversed", j, m_tracks[j].track.c_str(), m_tracks[j].laps);
else
Log::info("RaceConfig", "Race %d will be on %s with %d laps", j, m_tracks[j].track.c_str(), m_tracks[j].laps);
}
}
//-----------------------------------------------------------------------------
const TrackInfo* RaceConfig::getNextTrackInfo() const
{
return &m_track;
return &m_tracks[0];
}
//-----------------------------------------------------------------------------

View File

@ -3,13 +3,15 @@
#include <string>
#include <vector>
#include "utils/types.hpp"
class TrackInfo
{
public:
TrackInfo() { laps = 0; reversed = false; }
std::string track;
bool reversed;
int laps;
uint8_t laps;
};
class TrackVote
{
@ -18,15 +20,48 @@ class TrackVote
void voteTrack(std::string track);
void voteReversed(bool reversed);
void voteLaps(int laps);
void voteLaps(uint8_t laps);
TrackInfo track_info;
bool has_voted_track;
bool has_voted_reversed;
bool has_voted_laps;
};
class RaceVote
{
public:
RaceVote();
int minor_race_type; // corresponds to the enum in race_manager.hpp
void voteMajor(uint8_t major);
void voteRaceCount(uint8_t count);
void voteMinor(uint8_t minor);
void voteTrack(std::string track, uint8_t track_number = 0);
void voteReversed(bool reversed, uint8_t track_number = 0);
void voteLaps(uint8_t laps, uint8_t track_number = 0);
bool hasVotedMajor() const;
bool hasVotedRacesCount() const;
bool hasVotedMinor() const;
bool hasVotedTrack(uint8_t track_number = 0) const;
bool hasVotedReversed(uint8_t track_number = 0) const;
bool hasVotedLaps(uint8_t track_number = 0) const;
uint8_t getMajorVote() const;
uint8_t getRacesCountVote() const;
uint8_t getMinorVote() const;
std::string getTrackVote(uint8_t track_number = 0) const;
bool getReversedVote(uint8_t track_number = 0) const;
uint8_t getLapsVote(uint8_t track_number = 0) const;
private:
uint8_t m_major_mode;
uint8_t m_minor_mode;
uint8_t m_races_count; //!< Stores the number of races that will be in a GP
bool m_has_voted_major;
bool m_has_voted_minor;
bool m_has_voted_races_count;
std::vector<TrackVote> m_tracks_vote;
};
class RaceConfig
@ -34,11 +69,15 @@ class RaceConfig
public:
RaceConfig();
void setPlayerCount(int count);
void setPlayerTrackVote(int player_id, std::string track_name);
void setPlayerReverseVote(int player_id, bool reversed);
void setPlayerLapVote(int player_id, int lap_count);
void setPlayerCount(uint8_t count);
void setPlayerMajorVote(uint8_t player_id, uint8_t major);
void setPlayerRaceCountVote(uint8_t player_id, uint8_t count);
void setPlayerMinorVote(uint8_t player_id, uint8_t minor);
void setPlayerTrackVote(uint8_t player_id, std::string track, uint8_t track_nb = 0);
void setPlayerReversedVote(uint8_t player_id, bool reversed, uint8_t track_nb = 0);
void setPlayerLapsVote(uint8_t player_id, uint8_t lap_count, uint8_t track_nb = 0);
void computeRaceMode();
void computeNextTrack();
const TrackInfo* getNextTrackInfo() const;
@ -46,12 +85,13 @@ class RaceConfig
bool getLapCount() const;
protected:
TrackInfo m_track;
bool m_reverse;
int m_laps;
std::vector<TrackInfo> m_tracks;
int m_minor_mode;
int m_major_mode;
int m_races_count;
std::vector<TrackVote> m_votes;
int m_max_players;
std::vector<RaceVote> m_votes;
uint8_t m_max_players;
};

View File

@ -62,6 +62,16 @@ void* waitInput2(void* data)
assert(protocol);
protocol->startSelection();
}
else if (str == "compute_race")
{
GameSetup* setup = NetworkManager::getInstance()->getGameSetup();
setup->getRaceConfig()->computeRaceMode();
}
else if (str == "compute_track")
{
GameSetup* setup = NetworkManager::getInstance()->getGameSetup();
setup->getRaceConfig()->computeNextTrack();
}
}
uint32_t id = ProtocolManager::getInstance()->requestStart(new StopServer());