More work on server side vote kick. Most error handling complete now. Client side still lacking.

This commit is contained in:
lotodore
2008-12-07 11:04:42 +00:00
parent e0c1662fa5
commit 89450a9a32
5 changed files with 51 additions and 29 deletions
+1 -1
View File
@@ -829,7 +829,7 @@ Deny Reason:
0x0000: Invalid state. Vote kick is only possible when the game is running. 0x0000: Invalid state. Vote kick is only possible when the game is running.
0x0001: Kick not possible due to number of players. 0x0001: Kick not possible due to number of players.
0x0002: Another kick cannot be requested at this time. 0x0002: Another kick cannot be requested at this time.
0x0003: Kick request is already in progress for this player. 0x0003: Kick request is already in progress.
0xFFFF: Other reason. 0xFFFF: Other reason.
+1 -1
View File
@@ -98,7 +98,7 @@ struct VoteKickData
int numVotesToKick; int numVotesToKick;
int numVotesInFavourOfKicking; int numVotesInFavourOfKicking;
int numVotesAgainstKicking; int numVotesAgainstKicking;
unsigned timeLimitSec; int timeLimitSec;
boost::timers::portable::microsec_timer voteTimer; boost::timers::portable::microsec_timer voteTimer;
PlayerIdList votedPlayerIds; PlayerIdList votedPlayerIds;
}; };
+1 -1
View File
@@ -213,7 +213,7 @@ AbstractServerGameStateReceiving::Process(ServerGameThread &server)
NetPacketVoteKickPlayer::Data voteData; NetPacketVoteKickPlayer::Data voteData;
packet->ToNetPacketVoteKickPlayer()->GetData(voteData); packet->ToNetPacketVoteKickPlayer()->GetData(voteData);
server.InternalVoteKick(voteData.petitionId, voteData.vote); server.InternalVoteKick(session, voteData.petitionId, voteData.vote);
} }
} }
// Chat text is always allowed. // Chat text is always allowed.
+46 -25
View File
@@ -176,7 +176,6 @@ ServerGameThread::VoteKickLoop()
{ {
// Do not call the vote kick action all the time. // Do not call the vote kick action all the time.
// Check the timer. // Check the timer.
// The action will also be initiated after a player left.
if (m_voteKickActionTimer.elapsed().total_milliseconds() >= SERVER_CHECK_VOTE_KICK_INTERVAL_MSEC) if (m_voteKickActionTimer.elapsed().total_milliseconds() >= SERVER_CHECK_VOTE_KICK_INTERVAL_MSEC)
VoteKickAction(); VoteKickAction();
} }
@@ -189,8 +188,8 @@ ServerGameThread::VoteKickAction()
boost::mutex::scoped_lock lock(m_voteKickDataMutex); boost::mutex::scoped_lock lock(m_voteKickDataMutex);
if (m_voteKickData) if (m_voteKickData)
{ {
// Prepare some values.
const PlayerIdList playerIds(GetPlayerIdList()); const PlayerIdList playerIds(GetPlayerIdList());
// 1. Several players left the game, so a kick is no longer possible.
int votesRequiredToKick = m_voteKickData->numVotesToKick - m_voteKickData->numVotesInFavourOfKicking; int votesRequiredToKick = m_voteKickData->numVotesToKick - m_voteKickData->numVotesInFavourOfKicking;
int playersAllowedToVote = 0; int playersAllowedToVote = 0;
// We need to count the number of players which are still allowed to vote. // We need to count the number of players which are still allowed to vote.
@@ -203,20 +202,29 @@ ServerGameThread::VoteKickAction()
++player_i; ++player_i;
} }
bool abortPetition = false; bool abortPetition = false;
EndPetitionReason reason = PETITION_END_ENOUGH_VOTES; bool doKick = false;
EndPetitionReason reason;
if (votesRequiredToKick > playersAllowedToVote) // 1. Enough votes to kick the player.
if (m_voteKickData->numVotesInFavourOfKicking >= m_voteKickData->numVotesToKick)
{
reason = PETITION_END_ENOUGH_VOTES;
abortPetition = true;
doKick = true;
}
// 2. Several players left the game, so a kick is no longer possible.
else if (votesRequiredToKick > playersAllowedToVote)
{ {
reason = PETITION_END_NOT_ENOUGH_PLAYERS; reason = PETITION_END_NOT_ENOUGH_PLAYERS;
abortPetition = true; abortPetition = true;
} }
// 2. The kick has become invalid because the player to be kicked left. // 3. The kick has become invalid because the player to be kicked left.
else if (find(playerIds.begin(), playerIds.end(), m_voteKickData->kickPlayerId) == playerIds.end()) else if (find(playerIds.begin(), playerIds.end(), m_voteKickData->kickPlayerId) == playerIds.end())
{ {
reason = PETITION_END_PLAYER_LEFT; reason = PETITION_END_PLAYER_LEFT;
abortPetition = true; abortPetition = true;
} }
// 3. A kick request timed out (because not everyone voted). // 4. A kick request timed out (because not everyone voted).
else if (m_voteKickData->voteTimer.elapsed().total_seconds() >= m_voteKickData->timeLimitSec) else if (m_voteKickData->voteTimer.elapsed().total_seconds() >= m_voteKickData->timeLimitSec)
{ {
reason = PETITION_END_TIMEOUT; reason = PETITION_END_TIMEOUT;
@@ -229,13 +237,16 @@ ServerGameThread::VoteKickAction()
endPetitionData.petitionId = m_voteKickData->petitionId; endPetitionData.petitionId = m_voteKickData->petitionId;
endPetitionData.numVotesAgainstKicking = m_voteKickData->numVotesAgainstKicking; endPetitionData.numVotesAgainstKicking = m_voteKickData->numVotesAgainstKicking;
endPetitionData.numVotesInFavourOfKicking = m_voteKickData->numVotesInFavourOfKicking; endPetitionData.numVotesInFavourOfKicking = m_voteKickData->numVotesInFavourOfKicking;
endPetitionData.playerKicked = false; endPetitionData.playerKicked = doKick;
endPetitionData.endReason = reason; endPetitionData.endReason = reason;
m_voteKickData.reset(); m_voteKickData.reset();
lock.unlock(); // Do not block the data longer than necessary.
static_cast<NetPacketEndKickPlayerPetition *>(endPetition.get())->SetData(endPetitionData); static_cast<NetPacketEndKickPlayerPetition *>(endPetition.get())->SetData(endPetitionData);
SendToAllPlayers(endPetition, SessionData::Game); SendToAllPlayers(endPetition, SessionData::Game);
// Perform kick.
if (doKick)
InternalKickPlayer(m_voteKickData->kickPlayerId);
} }
} }
} }
@@ -329,16 +340,12 @@ ServerGameThread::InternalAskVoteKick(SessionWrapper byWhom, unsigned playerIdWh
startPetitionData.kickPlayerId = m_voteKickData->kickPlayerId; startPetitionData.kickPlayerId = m_voteKickData->kickPlayerId;
startPetitionData.kickTimeoutSec = m_voteKickData->timeLimitSec; startPetitionData.kickTimeoutSec = m_voteKickData->timeLimitSec;
startPetitionData.numVotesNeededToKick = m_voteKickData->numVotesToKick; startPetitionData.numVotesNeededToKick = m_voteKickData->numVotesToKick;
lock.unlock(); // Do not block the data longer than necessary.
static_cast<NetPacketStartKickPlayerPetition *>(startPetition.get())->SetData(startPetitionData); static_cast<NetPacketStartKickPlayerPetition *>(startPetition.get())->SetData(startPetitionData);
SendToAllPlayers(startPetition, SessionData::Game); SendToAllPlayers(startPetition, SessionData::Game);
} }
else else
{
lock.unlock(); // Do not block the data longer than necessary.
InternalDenyAskVoteKick(byWhom, playerIdWho, KICK_DENIED_OTHER_IN_PROGRESS); InternalDenyAskVoteKick(byWhom, playerIdWho, KICK_DENIED_OTHER_IN_PROGRESS);
}
} }
else else
InternalDenyAskVoteKick(byWhom, playerIdWho, KICK_DENIED_TOO_FEW_PLAYERS); InternalDenyAskVoteKick(byWhom, playerIdWho, KICK_DENIED_TOO_FEW_PLAYERS);
@@ -359,29 +366,43 @@ ServerGameThread::InternalDenyAskVoteKick(SessionWrapper byWhom, unsigned player
} }
void void
ServerGameThread::InternalVoteKick(unsigned petitionId, KickVote vote) ServerGameThread::InternalVoteKick(SessionWrapper byWhom, unsigned petitionId, KickVote vote)
{ {
if (IsRunning()) if (IsRunning() && byWhom.playerData)
{ {
boost::mutex::scoped_lock lock(m_voteKickDataMutex); boost::mutex::scoped_lock lock(m_voteKickDataMutex);
// Check whether this is the valid petition id.
if (m_voteKickData->petitionId == petitionId) if (m_voteKickData->petitionId == petitionId)
{ {
if (vote == KICK_VOTE_IN_FAVOUR) // Check whether the player already voted.
unsigned playerId = byWhom.playerData->GetUniqueId();
if (find(m_voteKickData->votedPlayerIds.begin(), m_voteKickData->votedPlayerIds.end(), playerId) == m_voteKickData->votedPlayerIds.end())
{ {
m_voteKickData->numVotesInFavourOfKicking++; m_voteKickData->votedPlayerIds.push_back(playerId);
if (m_voteKickData->numVotesInFavourOfKicking >= m_voteKickData->numVotesToKick) if (vote == KICK_VOTE_IN_FAVOUR)
{ m_voteKickData->numVotesInFavourOfKicking++;
// Perform kick. else
InternalKickPlayer(m_voteKickData->kickPlayerId); m_voteKickData->numVotesAgainstKicking++;
}
} }
else else
m_voteKickData->numVotesAgainstKicking++; InternalDenyVoteKick(byWhom, petitionId, VOTE_DENIED_ALREADY_VOTED);
// TODO abort if no longer possible.
// TODO remove deprecated list entries.
// TODO error handling.
} }
else
InternalDenyVoteKick(byWhom, petitionId, VOTE_DENIED_INVALID_PETITION);
} }
else
InternalDenyVoteKick(byWhom, petitionId, VOTE_DENIED_IMPOSSIBLE);
}
void
ServerGameThread::InternalDenyVoteKick(SessionWrapper byWhom, unsigned petitionId, DenyVoteReason reason)
{
boost::shared_ptr<NetPacket> denyVote(new NetPacketVoteKickPlayerDenied);
NetPacketVoteKickPlayerDenied::Data denyVoteData;
denyVoteData.petitionId = petitionId;
denyVoteData.denyReason = reason;
static_cast<NetPacketVoteKickPlayerDenied *>(denyVote.get())->SetData(denyVoteData);
GetSender().Send(byWhom.sessionData, denyVote);
} }
PlayerDataList PlayerDataList
+2 -1
View File
@@ -90,7 +90,8 @@ protected:
void InternalKickPlayer(unsigned playerId); void InternalKickPlayer(unsigned playerId);
void InternalAskVoteKick(SessionWrapper byWhom, unsigned playerIdWho, unsigned timeoutSec); void InternalAskVoteKick(SessionWrapper byWhom, unsigned playerIdWho, unsigned timeoutSec);
void InternalDenyAskVoteKick(SessionWrapper byWhom, unsigned playerIdWho, DenyKickPlayerReason reason); void InternalDenyAskVoteKick(SessionWrapper byWhom, unsigned playerIdWho, DenyKickPlayerReason reason);
void InternalVoteKick(unsigned petitionId, KickVote vote); void InternalVoteKick(SessionWrapper byWhom, unsigned petitionId, KickVote vote);
void InternalDenyVoteKick(SessionWrapper byWhom, unsigned petitionId, DenyVoteReason reason);
PlayerDataList GetFullPlayerDataList() const; PlayerDataList GetFullPlayerDataList() const;