diff --git a/src/network/game_setup.cpp b/src/network/game_setup.cpp index 1e8dde438..6633347e3 100644 --- a/src/network/game_setup.cpp +++ b/src/network/game_setup.cpp @@ -24,6 +24,7 @@ #include "modes/capture_the_flag.hpp" #include "network/network_config.hpp" #include "network/network_player_profile.hpp" +#include "network/peer_vote.hpp" #include "network/protocols/game_events_protocol.hpp" #include "network/protocols/server_lobby.hpp" #include "network/server_config.hpp" @@ -300,3 +301,11 @@ std::pair GameSetup::getPlayerTeamInfo() const } return std::make_pair(red_count, blue_count); } // getPlayerTeamInfo + +// ---------------------------------------------------------------------------- +void GameSetup::setRace(const PeerVote &vote) +{ + m_tracks.push_back(vote.m_track_name); + m_laps = vote.m_num_laps; + m_reverse = vote.m_reverse; +} // setRace diff --git a/src/network/game_setup.hpp b/src/network/game_setup.hpp index 8cf5b7d4a..32c646f9a 100644 --- a/src/network/game_setup.hpp +++ b/src/network/game_setup.hpp @@ -24,8 +24,6 @@ #include "network/remote_kart_info.hpp" -#include "network/peer_vote.hpp" - #include #include #include @@ -36,6 +34,7 @@ class NetworkPlayerProfile; class NetworkString; +class PeerVote; // ============================================================================ /*! \class GameSetup @@ -110,12 +109,7 @@ public: /** Returns the number of connected players. */ unsigned getPlayerCount() { return m_connected_players_count.load(); } // ------------------------------------------------------------------------ - void setRace(const PeerVote &vote) - { - m_tracks.push_back(vote.m_track_name); - m_laps = vote.m_num_laps; - m_reverse = vote.m_reverse; - } // setRace + void setRace(const PeerVote &vote); // ------------------------------------------------------------------------ void reset() { diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index 413b248e4..bac651dd2 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -35,6 +35,7 @@ #include "network/network_config.hpp" #include "network/network_player_profile.hpp" #include "network/network_timer_synchronizer.hpp" +#include "network/peer_vote.hpp" #include "network/protocols/connect_to_server.hpp" #include "network/protocols/game_protocol.hpp" #include "network/protocols/game_events_protocol.hpp" @@ -437,26 +438,20 @@ void ClientLobby::receivePlayerVote(Event* event) if (!checkDataSize(event, 4)) return; // Get the player name who voted NetworkString& data = event->data(); - - uint32_t host_id2 = data.getUInt32(); - std::shared_ptr peer = STKHost::get()->findPeerByHostId(host_id2); - - std::string player_name; - data.decodeString(&player_name); - uint32_t host_id = data.getUInt32(); - player_name += ": "; PeerVote vote(data); - Log::verbose("CL", "vote from server: host %d track %s reverse %d", - host_id, vote.m_track_name.c_str(), vote.m_reverse); - addVote(host_id, vote); + Log::debug("ClientLobby", + "Vote from server: host %d, track %s, laps %d, reverse %d.", + host_id, vote.m_track_name.c_str(), vote.m_num_laps, vote.m_reverse); + Track* track = track_manager->getTrack(vote.m_track_name); if (!track) - Log::fatal("ClientLobby", "Missing track %s", vote.m_track_name.c_str()); - - TracksScreen *ts = TracksScreen::getInstance(); - ts->addVote(host_id2); - + { + Log::fatal("ClientLobby", "Missing track %s", + vote.m_track_name.c_str()); + } + addVote(host_id, vote); + TracksScreen::getInstance()->updatePlayerVotes(); } // receivePlayerVote //----------------------------------------------------------------------------- @@ -477,18 +472,18 @@ void ClientLobby::disconnectedPlayer(Event* event) NetworkString &data = event->data(); SFXManager::get()->quickSound("appear"); unsigned disconnected_player_count = data.getUInt8(); + uint32_t host_id = data.getUInt32(); + m_peers_votes.erase(host_id); for (unsigned i = 0; i < disconnected_player_count; i++) { std::string name; data.decodeString(&name); core::stringw player_name = StringUtils::utf8ToWide(name); core::stringw msg = _("%s disconnected.", player_name); - uint32_t host_id = data.getUInt32(); // Use the friend icon to avoid an error-like message MessageQueue::add(MessageQueue::MT_FRIEND, msg); - TracksScreen::getInstance()->removeVote(host_id); } - + TracksScreen::getInstance()->updatePlayerVotes(); } // disconnectedPlayer //----------------------------------------------------------------------------- diff --git a/src/network/protocols/lobby_protocol.cpp b/src/network/protocols/lobby_protocol.cpp index 01dcf1eb8..ae1618eb0 100644 --- a/src/network/protocols/lobby_protocol.cpp +++ b/src/network/protocols/lobby_protocol.cpp @@ -25,6 +25,7 @@ #include "network/game_setup.hpp" #include "network/network_config.hpp" #include "network/network_player_profile.hpp" +#include "network/peer_vote.hpp" #include "network/protocols/game_protocol.hpp" #include "network/protocols/game_events_protocol.hpp" #include "network/race_event_manager.hpp" @@ -141,6 +142,8 @@ void LobbyProtocol::configRemoteKart( */ void LobbyProtocol::setup() { + resetVotingTime(); + m_peers_votes.clear(); m_game_setup->reset(); } // setupNewGame @@ -158,6 +161,8 @@ void LobbyProtocol::startVotingPeriod(float max_time) /** Returns the remaining voting time in seconds. */ float LobbyProtocol::getRemainingVotingTime() { + if (m_end_voting_period.load() == 0) + return 0.0f; uint64_t t = m_end_voting_period.load()- StkTime::getRealTimeMs(); return t/1000.0f; } // getRemainingVotingTime @@ -166,6 +171,26 @@ float LobbyProtocol::getRemainingVotingTime() /** Returns if the voting period is over. */ bool LobbyProtocol::isVotingOver() { - return m_end_voting_period.load() < StkTime::getRealTimeMs(); + return m_end_voting_period.load() != 0 && + m_end_voting_period.load() < StkTime::getRealTimeMs(); } // isVotingOver +//----------------------------------------------------------------------------- +/** Adds a vote. + * \param host_id Host id of this vote. + * \param vote The vote to add. */ +void LobbyProtocol::addVote(uint32_t host_id, const PeerVote &vote) +{ + m_peers_votes[host_id] = vote; +} // addVote + +//----------------------------------------------------------------------------- +/** Returns the voting data for one host. Returns NULL if the vote from + * the given host id has not yet arrived (or if it is an invalid host id). + */ +const PeerVote* LobbyProtocol::getVote(uint32_t host_id) const +{ + auto it = m_peers_votes.find(host_id); + if (it == m_peers_votes.end()) return NULL; + return &(it->second); +} // getVote diff --git a/src/network/protocols/lobby_protocol.hpp b/src/network/protocols/lobby_protocol.hpp index 4f97d5caf..bbba8d403 100644 --- a/src/network/protocols/lobby_protocol.hpp +++ b/src/network/protocols/lobby_protocol.hpp @@ -21,11 +21,9 @@ #include "network/protocol.hpp" -#include "network/network_string.hpp" -#include "network/peer_vote.hpp" - class GameSetup; class NetworkPlayerProfile; +class PeerVote; #include #include @@ -82,18 +80,17 @@ public: RR_INVALID_PLAYER = 5 }; +protected: + /** Vote from each peer. The host id is used as a key. Note that + * host ids can be non-consecutive, so we cannot use std::vector. */ + std::map m_peers_votes; + /** Timer user for voting periods in both lobbies. */ std::atomic m_end_voting_period; /** The maximum voting time. */ uint64_t m_max_voting_time; -protected: - /** Vote from each peer. The host id is used as a key. Note that - * host ids can be non-consecutive, so we cannot use std::vector. */ - std::map m_peers_votes; - - std::thread m_start_game_thread; static std::weak_ptr m_lobby; @@ -166,23 +163,15 @@ public: /** Returns the number of votes received so far. */ int getNumberOfVotes() const { return (int)m_peers_votes.size(); } // ----------------------------------------------------------------------- - /** Adds a vote. - * \param host_id Host id of this vote. - * \param vote The vote to add. */ - void addVote(int host_id, const PeerVote &vote) - { - m_peers_votes[host_id] = vote; - } // addVote + void addVote(uint32_t host_id, const PeerVote &vote); // ----------------------------------------------------------------------- - /** Returns the voting data for one host. Returns NULL if the vote from - * the given host id has not yet arrived (or if it is an invalid host id). - */ - const PeerVote* getVote(int host_id) - { - auto it = m_peers_votes.find(host_id); - if (it == m_peers_votes.end()) return NULL; - return &(it->second); - } + const PeerVote* getVote(uint32_t host_id) const; + // ----------------------------------------------------------------------- + void resetVotingTime() { m_end_voting_period.store(0); } + // ----------------------------------------------------------------------- + /** Returns all voting data.*/ + const std::map& getAllVotes() const + { return m_peers_votes; } // ----------------------------------------------------------------------- std::pair getGameStartedProgress() const { diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c08df66ef..edd553ac7 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -31,6 +31,7 @@ #include "network/game_setup.hpp" #include "network/network_config.hpp" #include "network/network_player_profile.hpp" +#include "network/peer_vote.hpp" #include "network/protocol_manager.hpp" #include "network/protocols/connect_to_peer.hpp" #include "network/protocols/game_protocol.hpp" @@ -265,7 +266,6 @@ void ServerLobby::setup() // Initialise the data structures to detect if all clients and // the server are ready: resetPeersReady(); - m_peers_votes.clear(); m_timeout.store(std::numeric_limits::max()); m_waiting_for_reset = false; m_server_started_at = m_server_delay = 0; @@ -1416,11 +1416,12 @@ void ServerLobby::clientDisconnected(Event* event) event->getPeer()->isWaitingForGame(); msg->setSynchronous(true); msg->addUInt8(LE_PLAYER_DISCONNECTED); - msg->addUInt8((uint8_t)players_on_peer.size()); + msg->addUInt8((uint8_t)players_on_peer.size()) + .addUInt32(event->getPeer()->getHostId()); for (auto p : players_on_peer) { std::string name = StringUtils::wideToUtf8(p->getName()); - msg->encodeString(name).addUInt32(event->getPeer()->getHostId()); + msg->encodeString(name); Log::info("ServerLobby", "%s disconnected", name.c_str()); } @@ -1928,7 +1929,8 @@ void ServerLobby::kartSelectionRequested(Event* event) } // kartSelectionRequested //----------------------------------------------------------------------------- -/*! \brief Called when a player votes for track(s). +/*! \brief Called when a player votes for track(s), it will auto correct client + * data if it sends some invalid data. * \param event : Event providing the information. */ void ServerLobby::handlePlayerVote(Event* event) @@ -1949,62 +1951,64 @@ void ServerLobby::handlePlayerVote(Event* event) NetworkString& data = event->data(); PeerVote vote(data); - Log::verbose("SL", "vote from server: host %d track %s reverse %d", - event->getPeer()->getHostId(), vote.m_track_name.c_str(), vote.m_reverse); + Log::debug("ServerLobby", + "Vote from client: host %d, track %s, laps %d, reverse %d.", + event->getPeer()->getHostId(), vote.m_track_name.c_str(), + vote.m_num_laps, vote.m_reverse); + + Track* t = track_manager->getTrack(vote.m_track_name); + if (!t) + { + vote.m_track_name = *m_available_kts.second.begin(); + t = track_manager->getTrack(vote.m_track_name); + assert(t); + } if (race_manager->modeHasLaps()) { if (ServerConfig::m_auto_game_time_ratio > 0.0f) { - Track* t = track_manager->getTrack(vote.m_track_name); - if (t) - { - vote.m_num_laps = - (uint8_t)(fmaxf(1.0f, - (float)t->getDefaultNumberOfLaps() - *ServerConfig::m_auto_game_time_ratio ) ); - } - else - { - // Prevent someone send invalid vote - vote.m_track_name = *m_available_kts.second.begin(); - vote.m_num_laps = (uint8_t)3; - } + vote.m_num_laps = + (uint8_t)(fmaxf(1.0f, (float)t->getDefaultNumberOfLaps() * + ServerConfig::m_auto_game_time_ratio)); } - else if (vote.m_num_laps == 0) + else if (vote.m_num_laps == 0 || vote.m_num_laps > 20) vote.m_num_laps = (uint8_t)3; } - else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER && - ServerConfig::m_auto_game_time_ratio > 0.0f ) + else if (race_manager->isSoccerMode()) { if (m_game_setup->isSoccerGoalTarget()) { - vote.m_num_laps = (uint8_t)(ServerConfig::m_auto_game_time_ratio * - UserConfigParams::m_num_goals); + if (ServerConfig::m_auto_game_time_ratio > 0.0f) + { + vote.m_num_laps = (uint8_t)(ServerConfig::m_auto_game_time_ratio * + UserConfigParams::m_num_goals); + } + else if (vote.m_num_laps > 10) + vote.m_num_laps = (uint8_t)5; } else { - vote.m_num_laps = (uint8_t)(ServerConfig::m_auto_game_time_ratio * - UserConfigParams::m_soccer_time_limit); + if (ServerConfig::m_auto_game_time_ratio > 0.0f) + { + vote.m_num_laps = (uint8_t)(ServerConfig::m_auto_game_time_ratio * + UserConfigParams::m_soccer_time_limit); + } + else if (vote.m_num_laps > 15) + vote.m_num_laps = (uint8_t)7; } } // Store vote: + vote.m_player_name = event->getPeer()->getPlayerProfiles()[0]->getName(); addVote(event->getPeer()->getHostId(), vote); // Now inform all clients about the vote NetworkString other = NetworkString(PROTOCOL_LOBBY_ROOM); - - std::string name = - StringUtils::wideToUtf8(event->getPeer() - ->getPlayerProfiles()[0]->getName()); other.setSynchronous(true); other.addUInt8(LE_VOTE); - - other.addUInt32(event->getPeer()->getHostId()) .encodeString(name) - .addUInt32(event->getPeer()->getHostId()); + other.addUInt32(event->getPeer()->getHostId()); vote.encode(&other); - sendMessageToPeers(&other); } // handlePlayerVote @@ -2034,7 +2038,7 @@ bool ServerLobby::handleAllVotes(PeerVote *winner_vote) for (auto peer : peers) { if (peer->hasPlayerProfiles() && !peer->isWaitingForGame()) - cur_players ++; + cur_players++; } if (cur_players == 0 || m_peers_votes.size() < cur_players) { diff --git a/src/states_screens/online/tracks_screen.cpp b/src/states_screens/online/tracks_screen.cpp index 96be4d44f..d4fa7b72b 100644 --- a/src/states_screens/online/tracks_screen.cpp +++ b/src/states_screens/online/tracks_screen.cpp @@ -32,6 +32,7 @@ #include "guiengine/widgets/spinner_widget.hpp" #include "io/file_manager.hpp" #include "network/game_setup.hpp" +#include "network/peer_vote.hpp" #include "network/protocols/client_lobby.hpp" #include "network/network_config.hpp" #include "network/stk_host.hpp" @@ -158,6 +159,7 @@ void TracksScreen::beforeAddingWidget() { Screen::init(); + m_selected_track = NULL; m_timer = getWidget("timer"); m_timer->showLabel(false); @@ -260,6 +262,14 @@ void TracksScreen::init() // goals / time limit and random item location auto cl = LobbyProtocol::get(); assert(cl); + const PeerVote* vote = cl->getVote(STKHost::get()->getMyHostId()); + if (vote) + { + DynamicRibbonWidget* w2 = getWidget("tracks"); + m_selected_track = track_manager->getTrack(vote->m_track_name); + w2->setBadge(vote->m_track_name, OK_BADGE); + } + if (UserConfigParams::m_num_laps == 0 || UserConfigParams::m_num_laps > 20) UserConfigParams::m_num_laps = 1; @@ -272,6 +282,8 @@ void TracksScreen::init() getWidget("reverse-text")->setText(_("Random item location"), false); m_reversed->setVisible(true); m_reversed->setState(UserConfigParams::m_random_arena_item); + if (vote) + m_reversed->setState(vote->m_reverse); } else if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) { @@ -292,8 +304,6 @@ void TracksScreen::init() { m_laps->setVisible(true); getWidget("lap-text")->setVisible(true); - auto cl = LobbyProtocol::get(); - assert(cl); if (cl->getGameSetup()->isSoccerGoalTarget()) { //I18N: In track screen @@ -310,12 +320,16 @@ void TracksScreen::init() m_laps->setMin(1); m_laps->setMax(15); } + if (vote) + m_laps->setValue(vote->m_num_laps); } getWidget("reverse-text")->setVisible(true); //I18N: In track screen getWidget("reverse-text")->setText(_("Random item location"), false); m_reversed->setVisible(true); m_reversed->setState(UserConfigParams::m_random_arena_item); + if (vote) + m_reversed->setState(vote->m_reverse); } else { @@ -335,26 +349,16 @@ void TracksScreen::init() m_laps->setMin(1); m_laps->setMax(20); m_laps->setValue(UserConfigParams::m_num_laps); + if (vote) + m_laps->setValue(vote->m_num_laps); } getWidget("reverse-text")->setVisible(true); //I18N: In track screen getWidget("reverse-text") ->setText(_("Drive in reverse"), false); m_reversed->setVisible(true); - - auto lp = LobbyProtocol::get(); - const PeerVote *vote = lp ->getVote(STKHost::get()->getMyHostId()); - DynamicRibbonWidget* w2 = getWidget("tracks"); - if(vote) - { - m_reverse_checked = vote->m_reverse; - m_selected_track = track_manager->getTrack(vote->m_track_name); - w2->setBadge(vote->m_track_name, OK_BADGE); - } - else - { - m_reversed->setState(m_reverse_checked); - } + if (vote) + m_reversed->setState(vote->m_reverse); } } if (NetworkConfig::get()->isAutoConnect() && m_network_tracks) @@ -365,6 +369,7 @@ void TracksScreen::init() vote.encodeString(m_random_track_list[0]).addUInt8(1).addUInt8(0); STKHost::get()->sendToServer(&vote, true); } + updatePlayerVotes(); } // init // ----------------------------------------------------------------------------- @@ -458,30 +463,22 @@ void TracksScreen::voteForPlayer() { assert(STKHost::existHost()); - // If submit is clicked without a vote, select a random track. - if(!m_selected_track) - { - std::string track_name = m_random_track_list.front(); - m_selected_track = track_manager->getTrack(track_name); - m_random_track_list.pop_front(); - m_random_track_list.push_back(track_name); - } assert(m_laps); assert(m_reversed); // Remember reverse globally for each stk instance if not arena - const core::stringw &player_name = - PlayerManager::getCurrentPlayer()->getName(); if (!race_manager->isBattleMode() && race_manager->getMinorMode() != RaceManager::MINOR_MODE_SOCCER) { UserConfigParams::m_num_laps = m_laps->getValue(); - m_reverse_checked = m_reversed->getState(); } else UserConfigParams::m_random_arena_item = m_reversed->getState(); NetworkString vote(PROTOCOL_LOBBY_ROOM); vote.addUInt8(LobbyProtocol::LE_VOTE); + const core::stringw &player_name = + PlayerManager::getCurrentPlayer()->getName(); + vote.encodeString(player_name); if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) { vote.encodeString(m_selected_track->getIdent()) @@ -495,12 +492,15 @@ void TracksScreen::voteForPlayer() } else { - PeerVote pvote(player_name, m_selected_track->getIdent(), - m_laps->getValue(), m_reversed->getState() ); - pvote.encode(&vote); - auto lp = LobbyProtocol::get(); - - // The vote will be sent to + vote.encodeString(m_selected_track->getIdent()) + .addUInt8(m_laps->getValue()) + .addUInt8(m_reversed->getState() ? 1 : 0); + } + if (auto lp = LobbyProtocol::get()) + { + vote.reset(); + vote.skip(2); + PeerVote pvote(vote); lp->addVote(STKHost::get()->getMyHostId(), pvote); } STKHost::get()->sendToServer(&vote, true); @@ -687,3 +687,11 @@ void TracksScreen::setResult(const PeerVote &winner_vote) } // wim_winning_index == -1 } // setResult + +// ----------------------------------------------------------------------------- +/* Update player votes whenever vote is recieved from any players or + * player disconnected, or when this screen is pushed. + */ +void TracksScreen::updatePlayerVotes() +{ +} // updatePlayerVotes diff --git a/src/states_screens/online/tracks_screen.hpp b/src/states_screens/online/tracks_screen.hpp index c09c1b039..6912ebd10 100644 --- a/src/states_screens/online/tracks_screen.hpp +++ b/src/states_screens/online/tracks_screen.hpp @@ -59,7 +59,7 @@ private: /** Maximum number of votes, as sent by the server. */ unsigned int m_max_num_votes; - bool m_network_tracks, m_reverse_checked, m_quit_server; + bool m_network_tracks, m_quit_server; int m_bottom_box_height; @@ -80,7 +80,6 @@ private: TracksScreen() : Screen("tracks.stkgui") { m_network_tracks = false; - m_reverse_checked = false; m_quit_server = false; m_bottom_box_height = -1; } @@ -129,8 +128,10 @@ public: { m_index_to_hostid.clear(); } - + // ------------------------------------------------------------------------ void setVoteTimeout(float timeout); + // ------------------------------------------------------------------------ + void updatePlayerVotes(); }; #endif