Use a central timeout controller (in LobbyProtocol) to be used by

both client and server. Voting time now starts from the moment the
kart screen is shown (not on first player having finished voting).
Improved coding style.
This commit is contained in:
hiker 2018-11-16 16:57:23 +11:00
parent cf52ff16b7
commit 0da03e14ca
7 changed files with 95 additions and 70 deletions

View File

@ -440,8 +440,7 @@ void ClientLobby::displayPlayerVote(Event* event)
if (!checkDataSize(event, 4)) return;
// Get the player name who voted
NetworkString& data = event->data();
float timeout = data.getFloat();
TracksScreen::getInstance()->setVoteTimeout(timeout);
std::string player_name;
data.decodeString(&player_name);
uint32_t host_id = data.getUInt32();
@ -840,6 +839,7 @@ void ClientLobby::startSelection(Event* event)
{
SFXManager::get()->quickSound("wee");
const NetworkString& data = event->data();
startVotingPeriod(data.getFloat());
bool skip_kart_screen = data.getUInt8() == 1;
m_server_auto_lap = data.getUInt8() == 1;
const unsigned kart_num = data.getUInt16();

View File

@ -30,6 +30,7 @@
#include "network/race_event_manager.hpp"
#include "race/race_manager.hpp"
#include "states_screens/state_manager.hpp"
#include "utils/time.hpp"
std::weak_ptr<LobbyProtocol> LobbyProtocol::m_lobby;
@ -37,6 +38,7 @@ LobbyProtocol::LobbyProtocol(CallbackObject* callback_object)
: Protocol(PROTOCOL_LOBBY_ROOM, callback_object)
{
m_game_setup = new GameSetup();
m_end_voting_period.store(0);
} // LobbyProtocol
// ----------------------------------------------------------------------------
@ -140,3 +142,29 @@ void LobbyProtocol::setup()
{
m_game_setup->reset();
} // setupNewGame
//-----------------------------------------------------------------------------
/** Starts the voting period time with the specified maximum time.
* \param max_time Maximum voting time in seconds
*/
void LobbyProtocol::startVotingPeriod(float max_time)
{
m_max_voting_time = uint64_t(max_time*1000);
m_end_voting_period.store(StkTime::getRealTimeMs() + m_max_voting_time);
} // startVotingPeriod
//-----------------------------------------------------------------------------
/** Returns the remaining voting time in seconds. */
int LobbyProtocol::getRemainingVotingTime()
{
uint64_t t = m_end_voting_period.load()- StkTime::getRealTimeMs();
return int(t/1000);
} // getRemainingVotingTime
//-----------------------------------------------------------------------------
/** Returns if the voting period is over. */
bool LobbyProtocol::isVotingOver()
{
return m_end_voting_period.load() < StkTime::getRealTimeMs();
} // isVotingOver

View File

@ -24,6 +24,7 @@
class GameSetup;
class NetworkPlayerProfile;
#include <atomic>
#include <cassert>
#include <memory>
#include <thread>
@ -75,6 +76,12 @@ public:
RR_INVALID_PLAYER = 5
};
/** Timer user for voting periods in both lobbies. */
std::atomic_uint64_t m_end_voting_period;
/** The maximum voting time. */
uint64_t m_max_voting_time;
protected:
std::thread m_start_game_thread;
@ -127,6 +134,12 @@ public:
virtual void loadWorld();
virtual bool allPlayersReady() const = 0;
virtual bool isRacing() const = 0;
void startVotingPeriod(float max_time);
int getRemainingVotingTime();
bool isVotingOver();
// ------------------------------------------------------------------------
float getMaxVotingTime() { return m_max_voting_time * 1000.0f; }
// ------------------------------------------------------------------------
GameSetup* getGameSetup() const { return m_game_setup; }
}; // class LobbyProtocol

View File

@ -489,15 +489,17 @@ void ServerLobby::asynchronousUpdate()
}
case SELECTING:
{
auto result = handleVote();
if (m_timeout.load() < (int64_t)StkTime::getRealTimeMs() ||
(std::get<3>(result) &&
std::string track_name;
int num_laps;
bool reverse;
auto result = handleVote(&track_name, &num_laps, &reverse);
if (isVotingOver() ||
(std::get<0>(result) &&
m_timeout.load() -
(int64_t)(ServerConfig::m_voting_timeout / 2.0f * 1000.0f) <
(int64_t)StkTime::getRealTimeMs()))
{
m_game_setup->setRace(std::get<0>(result), std::get<1>(result),
std::get<2>(result));
m_game_setup->setRace(track_name, num_laps, reverse);
// Remove disconnected player (if any) one last time
m_game_setup->update(true);
m_game_setup->sortPlayersForGrandPrix();
@ -507,8 +509,8 @@ void ServerLobby::asynchronousUpdate()
player->getPeer()->clearAvailableKartIDs();
NetworkString* load_world = getNetworkString();
load_world->setSynchronous(true);
load_world->addUInt8(LE_LOAD_WORLD).encodeString(std::get<0>(result))
.addUInt8(std::get<1>(result)).addUInt8(std::get<2>(result))
load_world->addUInt8(LE_LOAD_WORLD).encodeString(track_name)
.addUInt8(num_laps).addUInt8(reverse)
.addUInt8((uint8_t)players.size());
for (unsigned i = 0; i < players.size(); i++)
{
@ -835,6 +837,7 @@ void ServerLobby::startSelection(const Event *event)
}
}
if (ServerConfig::m_team_choosing && race_manager->teamEnabled())
{
auto red_blue = m_game_setup->getPlayerTeamInfo();
@ -863,13 +866,15 @@ void ServerLobby::startSelection(const Event *event)
}
}
startVotingPeriod(ServerConfig::m_voting_timeout);
NetworkString *ns = getNetworkString(1);
// Start selection - must be synchronous since the receiver pushes
// a new screen, which must be done from the main thread.
ns->setSynchronous(true);
ns->addUInt8(LE_START_SELECTION).addUInt8(
m_game_setup->isGrandPrixStarted() ? 1 : 0)
.addUInt8(ServerConfig::m_auto_lap_ratio > 0.0f ? 1 : 0);
ns->addUInt8(LE_START_SELECTION)
.addFloat(ServerConfig::m_voting_timeout)
.addUInt8(m_game_setup->isGrandPrixStarted() ? 1 : 0)
.addUInt8(ServerConfig::m_auto_lap_ratio > 0.0f ? 1 : 0);
// Remove karts / tracks from server that are not supported on all clients
std::set<std::string> karts_erase, tracks_erase;
@ -1845,18 +1850,7 @@ void ServerLobby::playerVote(Event* event)
event->getPeer()->isWaitingForGame())
return;
// Check if first vote, if so start counter
if (m_timeout.load() == std::numeric_limits<int64_t>::max())
{
m_timeout.store((int64_t)StkTime::getRealTimeMs() +
(int64_t)(ServerConfig::m_voting_timeout * 1000.0f));
}
int64_t remaining_time =
m_timeout.load() - (int64_t)StkTime::getRealTimeMs();
if (remaining_time < 0)
{
return;
}
if (isVotingOver()) return;
NetworkString& data = event->data();
std::string track_name;
@ -1890,7 +1884,7 @@ void ServerLobby::playerVote(Event* event)
std::string name = StringUtils::wideToUtf8(event->getPeer()
->getPlayerProfiles()[0]->getName());
other.setSynchronous(true);
other.addUInt8(LE_VOTE).addFloat(ServerConfig::m_voting_timeout)
other.addUInt8(LE_VOTE)
.encodeString(name).addUInt32(event->getPeer()->getHostId())
.encodeString(track_name).addUInt8(lap).addUInt8(reverse);
@ -1901,19 +1895,22 @@ void ServerLobby::playerVote(Event* event)
} // playerVote
// ----------------------------------------------------------------------------
std::tuple<std::string, uint8_t, bool, bool> ServerLobby::handleVote()
/** Returns the information about a current vote.
* \param track_name Name of the track voted for.
* \param num_laps Number of laps.
* \param reverse If reverse track is to be used.
*/
std::tuple<bool> ServerLobby::handleVote(std::string *track_name,
int *num_laps, bool *reverse)
{
// Default settings if no votes at all
RandomGenerator rg;
std::set<std::string>::iterator it = m_available_kts.second.begin();
std::advance(it, rg.get((int)m_available_kts.second.size()));
std::string final_track = *it;
unsigned final_laps = UserConfigParams::m_num_laps;
bool final_reverse = final_track.size() % 2 == 0;
*track_name = *it;
*num_laps = UserConfigParams::m_num_laps;
*reverse = track_name->size() % 2 == 0;
std::map<std::string, unsigned> tracks;
std::map<unsigned, unsigned> laps;
std::map<bool, unsigned> reverses;
float cur_players = 0.0f;
auto peers = STKHost::get()->getPeers();
@ -1923,10 +1920,14 @@ std::tuple<std::string, uint8_t, bool, bool> ServerLobby::handleVote()
cur_players += 1.0f;
}
if (cur_players == 0.0f)
return std::make_tuple(final_track, final_laps, final_reverse, false);
float tracks_rate = 0.0f;
float laps_rate = 0.0f;
return std::make_tuple(false);
float tracks_rate = 0.0f;
float laps_rate = 0.0f;
float reverses_rate = 0.0f;
std::map<std::string, unsigned> tracks;
std::map<unsigned, unsigned> laps;
std::map<bool, unsigned> reverses;
for (auto p : m_peers_votes)
{
@ -1947,7 +1948,7 @@ std::tuple<std::string, uint8_t, bool, bool> ServerLobby::handleVote()
reverses[std::get<2>(p.second)] = 1;
else
reverse_vote->second++;
}
} // for p in m_peers_votes
unsigned vote = 0;
auto track_vote = tracks.begin();
@ -1961,7 +1962,7 @@ std::tuple<std::string, uint8_t, bool, bool> ServerLobby::handleVote()
}
if (track_vote != tracks.end())
{
final_track = track_vote->first;
*track_name = track_vote->first;
tracks_rate = float(track_vote->second) / cur_players;
}
@ -1977,7 +1978,7 @@ std::tuple<std::string, uint8_t, bool, bool> ServerLobby::handleVote()
}
if (lap_vote != laps.end())
{
final_laps = lap_vote->first;
*num_laps = lap_vote->first;
laps_rate = float(lap_vote->second) / cur_players;
}
@ -1993,13 +1994,12 @@ std::tuple<std::string, uint8_t, bool, bool> ServerLobby::handleVote()
}
if (reverse_vote != reverses.end())
{
final_reverse = reverse_vote->first;
*reverse = reverse_vote->first;
reverses_rate = float(reverse_vote->second) / cur_players;
}
return std::make_tuple(final_track, final_laps, final_reverse,
tracks_rate > 0.5f && laps_rate > 0.5f && reverses_rate > 0.5f ?
true : false);
return std::make_tuple(tracks_rate > 0.5f &&
laps_rate > 0.5f && reverses_rate > 0.5f );
} // handleVote
// ----------------------------------------------------------------------------

View File

@ -238,7 +238,8 @@ private:
const std::string& iv,
uint32_t online_id,
const irr::core::stringw& online_name);
std::tuple<std::string, uint8_t, bool, bool> handleVote();
std::tuple<bool> handleVote(std::string *track_name,
int *num_laps, bool *reverse);
void getRankingForPlayer(std::shared_ptr<NetworkPlayerProfile> p);
void submitRankingsToAddons();
void computeNewRankings();

View File

@ -248,8 +248,6 @@ void TracksScreen::init()
IconButtonWidget* back_button = getWidget<IconButtonWidget>("back");
back_button->setImage("gui/icons/back.png");
}
if (!m_network_tracks)
m_vote_timeout = std::numeric_limits<uint64_t>::max();
DynamicRibbonWidget* tracks_widget = getWidget<DynamicRibbonWidget>("tracks");
assert(tracks_widget != NULL);
@ -446,14 +444,6 @@ void TracksScreen::setFocusOnTrack(const std::string& trackName)
tracks_widget->setSelection(trackName, PLAYER_ID_GAME_MASTER, true);
} // setFocusOnTrack
// -----------------------------------------------------------------------------
void TracksScreen::setVoteTimeout(float timeout)
{
if (m_vote_timeout != std::numeric_limits<uint64_t>::max())
return;
m_vote_timeout = StkTime::getRealTimeMs() + (uint64_t)(timeout * 1000.0f);
} // setVoteTimeout
// -----------------------------------------------------------------------------
void TracksScreen::voteForPlayer()
{
@ -497,17 +487,13 @@ void TracksScreen::voteForPlayer()
void TracksScreen::onUpdate(float dt)
{
assert(m_votes);
if (m_vote_timeout == std::numeric_limits<uint64_t>::max())
{
m_votes->setText(L"", false);
return;
}
m_votes->setVisible(true);
int remaining_time = (int)
((int64_t)m_vote_timeout - (int64_t)StkTime::getRealTimeMs()) / 1000;
if (remaining_time < 0)
remaining_time = 0;
auto cl = LobbyProtocol::get<LobbyProtocol>();
int remaining_time = cl->getRemainingVotingTime();
if (remaining_time < 0) remaining_time = 0;
//I18N: In tracks screen, about voting of tracks in network
core::stringw message = _("Remaining time: %d", remaining_time);
message += L"\n";

View File

@ -97,21 +97,18 @@ public:
/** \brief implement callback from parent class GUIEngine::Screen */
virtual void onUpdate(float dt) OVERRIDE;
// ------------------------------------------------------------------------
void setFocusOnTrack(const std::string& trackName);
// ------------------------------------------------------------------------
void setNetworkTracks() { m_network_tracks = true; }
// ------------------------------------------------------------------------
void setQuitServer() { m_quit_server = true; }
// ------------------------------------------------------------------------
void resetVote()
{
m_vote_messages.clear();
m_vote_timeout = std::numeric_limits<uint64_t>::max();
}
void setVoteTimeout(float timeout);
// ------------------------------------------------------------------------
void addVoteMessage(const std::string& user,
const irr::core::stringw& message)
{