aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/server/vote_controller.cpp
diff options
context:
space:
mode:
authorMichael Sartain <[email protected]>2014-10-02 08:25:55 -0700
committerMichael Sartain <[email protected]>2014-10-02 08:25:55 -0700
commit55ed12f8d1eb6887d348be03aee5573d44177ffb (patch)
tree3686f7ca78c780cd9a3d367b79a9d9250c1be7c0 /mp/src/game/server/vote_controller.cpp
parent* Added support for Visual C++ 2013 Express to VPC (diff)
downloadsource-sdk-2013-55ed12f8d1eb6887d348be03aee5573d44177ffb.tar.xz
source-sdk-2013-55ed12f8d1eb6887d348be03aee5573d44177ffb.zip
Updated the SDK with the latest code from the TF and HL2 branches.
Diffstat (limited to 'mp/src/game/server/vote_controller.cpp')
-rw-r--r--mp/src/game/server/vote_controller.cpp235
1 files changed, 161 insertions, 74 deletions
diff --git a/mp/src/game/server/vote_controller.cpp b/mp/src/game/server/vote_controller.cpp
index 316974ad..7dab54bb 100644
--- a/mp/src/game/server/vote_controller.cpp
+++ b/mp/src/game/server/vote_controller.cpp
@@ -10,6 +10,7 @@
#include "eiface.h"
#include "team.h"
#include "gameinterface.h"
+#include "fmtstr.h"
#ifdef TF_DLL
#include "tf/tf_gamerules.h"
@@ -39,15 +40,105 @@ CVoteController *g_voteController = NULL;
ConVar sv_vote_timer_duration("sv_vote_timer_duration", "15", FCVAR_DEVELOPMENTONLY, "How long to allow voting on an issue");
ConVar sv_vote_command_delay("sv_vote_command_delay", "2", FCVAR_DEVELOPMENTONLY, "How long after a vote passes until the action happens", false, 0, true, 4.5);
-ConVar sv_allow_votes("sv_allow_votes", "1", 0, "Allow voting?");
-ConVar sv_vote_failure_timer("sv_vote_failure_timer", "300", 0, "A vote that fails cannot be re-submitted for this long");
+ConVar sv_allow_votes("sv_allow_votes", "1", FCVAR_NONE, "Allow voting?");
+ConVar sv_vote_failure_timer( "sv_vote_failure_timer", "300", FCVAR_NONE, "A vote that fails cannot be re-submitted for this long" );
#ifdef TF_DLL
-ConVar sv_vote_failure_timer_mvm( "sv_vote_failure_timer_mvm", "120", 0, "A vote that fails in MvM cannot be re-submitted for this long" );
+ConVar sv_vote_failure_timer_mvm( "sv_vote_failure_timer_mvm", "120", FCVAR_NONE, "A vote that fails in MvM cannot be re-submitted for this long" );
#endif // TF_DLL
ConVar sv_vote_creation_timer("sv_vote_creation_timer", "120", FCVAR_DEVELOPMENTONLY, "How often someone can individually call a vote.");
-ConVar sv_vote_quorum_ratio( "sv_vote_quorum_ratio", "0.6", 1, "The minimum ratio of players needed to vote on an issue to resolve it.", true, 0.1, true, 1.0 );
-ConVar sv_vote_allow_spectators( "sv_vote_allow_spectators", "0", 0, "Allow spectators to vote?" );
-ConVar sv_vote_ui_hide_disabled_issues( "sv_vote_ui_hide_disabled_issues", "1", 0, "Suppress listing of disabled issues in the vote setup screen." );
+ConVar sv_vote_quorum_ratio( "sv_vote_quorum_ratio", "0.6", FCVAR_HIDDEN, "The minimum ratio of players needed to vote on an issue to resolve it.", true, 0.1, true, 1.0 );
+ConVar sv_vote_allow_spectators( "sv_vote_allow_spectators", "0", FCVAR_NONE, "Allow spectators to vote?" );
+ConVar sv_vote_ui_hide_disabled_issues( "sv_vote_ui_hide_disabled_issues", "1", FCVAR_NONE, "Suppress listing of disabled issues in the vote setup screen." );
+
+static const int k_nKickWatchListMaxDuration = 300;
+
+//-----------------------------------------------------------------------------
+// Purpose: Game system to detect maps without cameras in them, and move on
+//-----------------------------------------------------------------------------
+class CVoteControllerSystem : public CAutoGameSystemPerFrame
+{
+public:
+ CVoteControllerSystem( char const *name ) : CAutoGameSystemPerFrame( name )
+ {
+ SetDefLessFunc( m_mapKickWatchList );
+ m_flNextKickCheckTime = 0.f;
+ }
+
+ virtual void LevelInitPreEntity()
+ {
+ }
+
+ virtual void FrameUpdatePostEntityThink( void )
+ {
+ // Executing the vote controller command needs to happen in the PostEntityThink as it can restart levels and
+ // blast entities, etc. If you're doing this during a regular think, this can cause entities thinking after
+ // you in Physics_RunThinkFunctions() to get grumpy and crash.
+ if ( g_voteController )
+ {
+ // Vote passed - execute the command
+ if ( g_voteController->m_executeCommandTimer.HasStarted() && g_voteController->m_executeCommandTimer.IsElapsed() )
+ {
+ g_voteController->m_executeCommandTimer.Invalidate();
+ g_voteController->m_potentialIssues[g_voteController->m_iActiveIssueIndex]->ExecuteCommand();
+ }
+
+ // Kick watch
+ if ( m_flNextKickCheckTime < gpGlobals->curtime )
+ {
+ FOR_EACH_MAP( m_mapKickWatchList, i )
+ {
+ if ( gpGlobals->curtime > m_mapKickWatchList[i] )
+ {
+ m_mapKickWatchList.RemoveAt( i );
+ break; // Constantly called code - resume on next pass
+ }
+
+ CBasePlayer *pTarget = NULL;
+ CSteamID steamIDPlayer;
+ for ( int j = 1; j <= gpGlobals->maxClients; j++ )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( j );
+ if ( !pPlayer )
+ continue;
+
+ if ( pPlayer->GetSteamID( &steamIDPlayer ) == false )
+ continue;
+
+ if ( steamIDPlayer == m_mapKickWatchList.Key( i ) )
+ {
+ pTarget = pPlayer;
+ break;
+ }
+ }
+
+ if ( pTarget )
+ {
+ // Welcome back
+ engine->ServerCommand( CFmtStr( "kickid %d %s;", pTarget->GetUserID(), "Kicked by server." ) );
+ }
+ }
+
+ m_flNextKickCheckTime = gpGlobals->curtime + 0.2f;
+ }
+ }
+ }
+
+ void AddPlayerToKickWatchList( CSteamID steamID, float flDuration )
+ {
+ flDuration = clamp( flDuration, 1.f, (float)k_nKickWatchListMaxDuration );
+ if ( m_mapKickWatchList.Find( steamID ) == m_mapKickWatchList.InvalidIndex() )
+ {
+ m_mapKickWatchList.Insert( steamID, ( gpGlobals->curtime + flDuration ) );
+ }
+ }
+
+private:
+
+ CUtlMap< CSteamID, float > m_mapKickWatchList;
+ float m_flNextKickCheckTime;
+};
+
+CVoteControllerSystem VoteControllerSystem( "CVoteControllerSystem" );
//-----------------------------------------------------------------------------
// Purpose:
@@ -101,7 +192,7 @@ CON_COMMAND( callvote, "Start a vote on an issue." )
{
if ( pVoteCaller->GetTeamNumber() == TEAM_SPECTATOR )
{
- g_voteController->SendVoteFailedMessage( VOTE_FAILED_SPECTATOR, pVoteCaller );
+ g_voteController->SendVoteCreationFailedMessage( VOTE_FAILED_SPECTATOR, pVoteCaller );
return;
}
}
@@ -111,7 +202,7 @@ CON_COMMAND( callvote, "Start a vote on an issue." )
int nCooldown = 0;
if ( !g_voteController->CanEntityCallVote( pVoteCaller, nCooldown ) )
{
- g_voteController->SendVoteFailedMessage( VOTE_FAILED_RATE_EXCEEDED, pVoteCaller, nCooldown );
+ g_voteController->SendVoteCreationFailedMessage( VOTE_FAILED_RATE_EXCEEDED, pVoteCaller, nCooldown );
return;
}
#endif
@@ -381,7 +472,7 @@ bool CVoteController::CreateVote( int iEntIndex, const char *pszTypeString, cons
{
if ( !bDedicatedServer )
{
- SendVoteFailedMessage( nErrorCode, pVoteCaller, nTime );
+ SendVoteCreationFailedMessage( nErrorCode, pVoteCaller, nTime );
}
}
}
@@ -391,35 +482,43 @@ bool CVoteController::CreateVote( int iEntIndex, const char *pszTypeString, cons
}
//-----------------------------------------------------------------------------
-// Purpose: Sent to everyone, unless we pass a player pointer
+// Purpose: The vote failed to start - let the caller know why
//-----------------------------------------------------------------------------
-void CVoteController::SendVoteFailedMessage( vote_create_failed_t nReason, CBasePlayer *pVoteCaller, int nTime )
+void CVoteController::SendVoteCreationFailedMessage( vote_create_failed_t nReason, CBasePlayer *pVoteCaller, int nTime /*= -1*/ )
{
- // driller: need to merge all failure case stuff into a single path
- if ( pVoteCaller )
- {
- CSingleUserRecipientFilter user( pVoteCaller );
- user.MakeReliable();
+ Assert( pVoteCaller );
+ if ( !pVoteCaller )
+ return;
- UserMessageBegin( user, "CallVoteFailed" );
- WRITE_BYTE( nReason );
- WRITE_SHORT( nTime );
- MessageEnd();
- }
- else
- {
- UTIL_LogPrintf("Vote failed \"%s %s\" \n",
- m_potentialIssues[m_iActiveIssueIndex]->GetTypeString(),
- m_potentialIssues[m_iActiveIssueIndex]->GetDetailsString() );
+ CSingleUserRecipientFilter user( pVoteCaller );
+ user.MakeReliable();
- CBroadcastRecipientFilter filter;
- filter.MakeReliable();
+ UserMessageBegin( user, "CallVoteFailed" );
+ WRITE_BYTE( nReason );
+ WRITE_SHORT( nTime );
+ MessageEnd();
+}
- UserMessageBegin( filter, "VoteFailed" );
- WRITE_BYTE( m_iOnlyTeamToVote );
- WRITE_BYTE( nReason );
- MessageEnd();
- }
+//-----------------------------------------------------------------------------
+// Purpose: The vote was called, but failed to pass - let everyone know why
+//-----------------------------------------------------------------------------
+void CVoteController::SendVoteFailedToPassMessage( vote_create_failed_t nReason )
+{
+ Assert( m_potentialIssues[m_iActiveIssueIndex] );
+
+ // See if we have a player target.
+ CBasePlayer *pVoteTarget = m_potentialIssues[m_iActiveIssueIndex]->m_hPlayerTarget;
+ bool bFakeClient = ( pVoteTarget && ( pVoteTarget->IsFakeClient() || pVoteTarget->IsHLTV() || pVoteTarget->IsReplay() ) );
+
+ UTIL_LogPrintf( "Vote failed \"%s %s\" with code %i (proxy: %i) \n", m_potentialIssues[m_iActiveIssueIndex]->GetTypeString(), m_potentialIssues[m_iActiveIssueIndex]->GetDetailsString(), (int)nReason, bFakeClient );
+
+ CBroadcastRecipientFilter filter;
+ filter.MakeReliable();
+
+ UserMessageBegin( filter, "VoteFailed" );
+ WRITE_BYTE( m_iOnlyTeamToVote );
+ WRITE_BYTE( nReason );
+ MessageEnd();
}
//-----------------------------------------------------------------------------
@@ -577,7 +676,7 @@ void CVoteController::VoteControllerThink( void )
// Option1 is Yes
if ( nWinningVoteOption != VOTE_OPTION1 )
{
- SendVoteFailedMessage( VOTE_FAILED_YES_MUST_EXCEED_NO );
+ SendVoteFailedToPassMessage( VOTE_FAILED_YES_MUST_EXCEED_NO );
bVotePassed = false;
}
}
@@ -592,7 +691,7 @@ void CVoteController::VoteControllerThink( void )
}
else
{
- SendVoteFailedMessage( VOTE_FAILED_QUORUM_FAILURE );
+ SendVoteFailedToPassMessage( VOTE_FAILED_QUORUM_FAILURE );
bVotePassed = false;
}
@@ -601,9 +700,11 @@ void CVoteController::VoteControllerThink( void )
m_executeCommandTimer.Start( sv_vote_command_delay.GetFloat() );
m_resetVoteTimer.Start( 5.0 );
- UTIL_LogPrintf("Vote succeeded \"%s %s\"\n",
- m_potentialIssues[m_iActiveIssueIndex]->GetTypeString(),
- m_potentialIssues[m_iActiveIssueIndex]->GetDetailsString() );
+ // Target is not always a player (changelevel, etc)
+ CBasePlayer *pVoteTarget = m_potentialIssues[m_iActiveIssueIndex]->m_hPlayerTarget;
+ bool bFakeClient = ( pVoteTarget && ( pVoteTarget->IsFakeClient() || pVoteTarget->IsHLTV() || pVoteTarget->IsReplay() ) );
+
+ UTIL_LogPrintf( "Vote succeeded \"%s %s\" (proxy: %i) \n", m_potentialIssues[m_iActiveIssueIndex]->GetTypeString(), m_potentialIssues[m_iActiveIssueIndex]->GetDetailsString(), bFakeClient );
CBroadcastRecipientFilter filter;
filter.MakeReliable();
@@ -822,6 +923,14 @@ bool CVoteController::CanEntityCallVote( CBasePlayer *pPlayer, int &nCooldown )
};
//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVoteController::AddPlayerToKickWatchList( CSteamID steamID, float flDuration )
+{
+ VoteControllerSystem.AddPlayerToKickWatchList( steamID, flDuration );
+}
+
+//-----------------------------------------------------------------------------
// Purpose: BaseIssue
//-----------------------------------------------------------------------------
CBaseIssue::CBaseIssue( const char *pszTypeString )
@@ -831,6 +940,7 @@ CBaseIssue::CBaseIssue( const char *pszTypeString )
m_iNumYesVotes = 0;
m_iNumNoVotes = 0;
m_iNumPotentialVotes = 0;
+ m_flNextCallTime = -1.f;
ASSERT( g_voteController );
g_voteController->RegisterIssue( this );
@@ -943,9 +1053,18 @@ bool CBaseIssue::CanCallVote( int iEntIndex, const char *pszDetails, vote_create
return true;
// Bogus player
- if( iEntIndex == -1 )
+ if ( iEntIndex == -1 )
return false;
+ // Note: Issue timers reset on level change because the class is created/destroyed during transitions.
+ // It'd be nice to refactor the basic framework of the system to get rid of side-effects like this.
+ if ( m_flNextCallTime != -1.f && gpGlobals->curtime < m_flNextCallTime )
+ {
+ nFailCode = VOTE_FAILED_ON_COOLDOWN;
+ nTime = m_flNextCallTime - gpGlobals->curtime;
+ return false;
+ }
+
#ifdef TF_DLL
if ( TFGameRules() && TFGameRules()->IsInWaitingForPlayers() && !TFGameRules()->IsInTournamentMode() )
{
@@ -955,14 +1074,14 @@ bool CBaseIssue::CanCallVote( int iEntIndex, const char *pszDetails, vote_create
#endif // TF_DLL
CBaseEntity *pVoteCaller = UTIL_EntityByIndex( iEntIndex );
- if( pVoteCaller && !CanTeamCallVote( GetVoterTeam( pVoteCaller ) ) )
+ if ( pVoteCaller && !CanTeamCallVote( GetVoterTeam( pVoteCaller ) ) )
{
nFailCode = VOTE_FAILED_TEAM_CANT_CALL;
return false;
}
// Did this fail recently?
- for( int iIndex = 0; iIndex < m_FailedVotes.Count(); iIndex++ )
+ for ( int iIndex = 0; iIndex < m_FailedVotes.Count(); iIndex++ )
{
FailedVote *pCurrentFailure = m_FailedVotes[iIndex];
int nTimeRemaining = pCurrentFailure->flLockoutTime - gpGlobals->curtime;
@@ -988,7 +1107,7 @@ bool CBaseIssue::CanCallVote( int iEntIndex, const char *pszDetails, vote_create
if ( bFailed )
{
- nFailCode = VOTE_FAILED_FAILED_RECENTLY;
+ nFailCode = VOTE_FAILED_ON_COOLDOWN;
nTime = nTimeRemaining;
return false;
}
@@ -1065,36 +1184,4 @@ bool CBaseIssue::GetVoteOptions( CUtlVector <const char*> &vecNames )
return true;
}
-//-----------------------------------------------------------------------------
-// Purpose: Game system to detect maps without cameras in them, and move on
-//-----------------------------------------------------------------------------
-class CVoteControllerSystem : public CAutoGameSystemPerFrame
-{
-public:
- CVoteControllerSystem( char const *name ) : CAutoGameSystemPerFrame( name )
- {
- }
-
- virtual void LevelInitPreEntity()
- {
- }
-
- virtual void FrameUpdatePostEntityThink( void )
- {
- // Executing the vote controller command needs to happen in the PostEntityThink as it can restart levels and
- // blast entities, etc. If you're doing this during a regular think, this can cause entities thinking after
- // you in Physics_RunThinkFunctions() to get grumpy and crash.
- if( g_voteController )
- {
- // Vote passed - execute the command
- if( g_voteController->m_executeCommandTimer.HasStarted() && g_voteController->m_executeCommandTimer.IsElapsed() )
- {
- g_voteController->m_executeCommandTimer.Invalidate();
- g_voteController->m_potentialIssues[ g_voteController->m_iActiveIssueIndex ]->ExecuteCommand();
- }
- }
- }
-};
-
-CVoteControllerSystem VoteControllerSystem( "CVoteControllerSystem" );