diff --git a/doc/protocols.xls b/doc/protocols.xls index 1d191bfd5..740c64631 100644 Binary files a/doc/protocols.xls and b/doc/protocols.xls differ diff --git a/src/network/client_network_manager.cpp b/src/network/client_network_manager.cpp index 2d978eb4e..dbd8e34b5 100644 --- a/src/network/client_network_manager.cpp +++ b/src/network/client_network_manager.cpp @@ -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(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(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) { diff --git a/src/network/protocol.cpp b/src/network/protocol.cpp index e4a34f310..d71d8c265 100644 --- a/src/network/protocol.cpp +++ b/src/network/protocol.cpp @@ -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 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); + } +} diff --git a/src/network/protocol.hpp b/src/network/protocol.hpp index b19892ce7..4fab04112 100644 --- a/src/network/protocol.hpp +++ b/src/network/protocol.hpp @@ -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 diff --git a/src/network/protocols/client_lobby_room_protocol.cpp b/src/network/protocols/client_lobby_room_protocol.cpp index d8fac469b..f5b8fe5d3 100644 --- a/src/network/protocols/client_lobby_room_protocol.cpp +++ b/src/network/protocols/client_lobby_room_protocol.cpp @@ -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]); +} +//----------------------------------------------------------------------------- diff --git a/src/network/protocols/client_lobby_room_protocol.hpp b/src/network/protocols/client_lobby_room_protocol.hpp index 569bbebb6..d57fd067e 100644 --- a/src/network/protocols/client_lobby_room_protocol.hpp +++ b/src/network/protocols/client_lobby_room_protocol.hpp @@ -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; diff --git a/src/network/protocols/server_lobby_room_protocol.cpp b/src/network/protocols/server_lobby_room_protocol.cpp index 19d1ccf9b..f56633af2 100644 --- a/src/network/protocols/server_lobby_room_protocol.cpp +++ b/src/network/protocols/server_lobby_room_protocol.cpp @@ -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); +} +//----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby_room_protocol.hpp b/src/network/protocols/server_lobby_room_protocol.hpp index 906e818d9..82d2691f0 100644 --- a/src/network/protocols/server_lobby_room_protocol.hpp +++ b/src/network/protocols/server_lobby_room_protocol.hpp @@ -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 m_peers; diff --git a/src/network/race_config.cpp b/src/network/race_config.cpp index d53321730..fb4d7e6ce 100644 --- a/src/network/race_config.cpp +++ b/src/network/race_config.cpp @@ -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. + * \param histogram : A pointer to the histogram. + * \return The key of type S that has the highest second value. + */ template S getHighestInHistogram(std::map* histogram) { S best_item; - int highest_count; + uint8_t highest_count; for (typename std::map::iterator it = histogram->begin(); it != histogram->end(); it++) { @@ -20,6 +25,9 @@ S getHighestInHistogram(std::map* 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,81 +194,176 @@ 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::computeNextTrack() +void RaceConfig::setPlayerTrackVote(uint8_t player_id, std::string track, uint8_t track_nb) { - // first create histograms of the votes - std::map tracks_histogram; - std::map reversed_histogram; - std::map laps_histogram; + 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 major_histogram; + std::map races_count_histogram; + std::map minor_histogram; 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].hasVotedMajor()) { - try // maps + try { - tracks_histogram.at(m_votes[i].track_info.track) ++; + major_histogram.at(m_votes[i].getMajorVote()) ++; } - 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; + major_histogram[m_votes[i].getMajorVote()] = 1; } } - else if (m_votes[i].has_voted_reversed) + else if (m_votes[i].hasVotedRacesCount()) { - try // reversed + try { - reversed_histogram.at(m_votes[i].track_info.reversed) ++; + races_count_histogram.at(m_votes[i].getRacesCountVote()) ++; } - 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; + races_count_histogram[m_votes[i].getRacesCountVote()] = 1; } } - else if (m_votes[i].has_voted_laps) + else if (m_votes[i].hasVotedMinor()) { - try // laps + try { - laps_histogram.at(m_votes[i].track_info.laps) ++; + minor_histogram.at(m_votes[i].getMinorVote()) ++; } - 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 { - laps_histogram[m_votes[i].track_info.laps] = 1; + minor_histogram[m_votes[i].getMinorVote()] = 1; } } } - // now find the highest votes - m_track.track = getHighestInHistogram(&tracks_histogram); - m_track.reversed = getHighestInHistogram(&reversed_histogram); - m_track.laps = getHighestInHistogram(&laps_histogram); + // now we know : + m_major_mode = ((major_histogram.size() > 0) ? getHighestInHistogram(&major_histogram) : 1); + m_races_count = ((minor_histogram.size() > 0) ? getHighestInHistogram(&races_count_histogram) : 1); + m_minor_mode = ((minor_histogram.size() > 0) ? getHighestInHistogram(&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 tracks_histogram; + std::map reversed_histogram; + std::map laps_histogram; + for (unsigned int i = 0; i < m_max_players; i++) + { + // increase the count of votes + if (m_votes[i].hasVotedTrack()) + { + try // maps + { + tracks_histogram.at(m_votes[i].getTrackVote()) ++; + } + catch (const std::out_of_range& oor) // doesn't exist in the map + { + tracks_histogram[m_votes[i].getTrackVote()] = 1; + } + } + else if (m_votes[i].hasVotedReversed()) + { + try // reversed + { + reversed_histogram.at(m_votes[i].getReversedVote()) ++; + } + catch (const std::out_of_range& oor) // doesn't exist in the map + { + reversed_histogram[m_votes[i].getReversedVote()] = 1; + } + } + else if (m_votes[i].hasVotedLaps()) + { + try // laps + { + laps_histogram.at(m_votes[i].getLapsVote()) ++; + } + catch (const std::out_of_range& oor) // doesn't exist in the mapt + { + laps_histogram[m_votes[i].getLapsVote()] = 1; + } + } + } + // now find the highest votes + m_tracks[j].track = getHighestInHistogram(&tracks_histogram); + m_tracks[j].reversed = getHighestInHistogram(&reversed_histogram); + m_tracks[j].laps = getHighestInHistogram(&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]; } //----------------------------------------------------------------------------- diff --git a/src/network/race_config.hpp b/src/network/race_config.hpp index ac7a2aeb7..635017f33 100644 --- a/src/network/race_config.hpp +++ b/src/network/race_config.hpp @@ -3,13 +3,15 @@ #include #include +#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 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 m_tracks; + int m_minor_mode; + int m_major_mode; + int m_races_count; - std::vector m_votes; - int m_max_players; + std::vector m_votes; + uint8_t m_max_players; }; diff --git a/src/network/server_network_manager.cpp b/src/network/server_network_manager.cpp index 7e917d9a5..c6d33aaf0 100644 --- a/src/network/server_network_manager.cpp +++ b/src/network/server_network_manager.cpp @@ -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());