From c5a88981f4b22537a59b478e8137b5875bc1bc4f Mon Sep 17 00:00:00 2001 From: happs Date: Sat, 24 Oct 2015 20:36:36 -0400 Subject: [PATCH] track time spent alive and computes average healing over it --- sizzlinglib/PlayerClassTracker.cpp | 35 +++++++++++++++++++++- sizzlinglib/include/PlayerClassTracker.h | 12 +++++++- sizzlingstats/PlayerDataManager.cpp | 21 +++++++++++++ sizzlingstats/PlayerDataManager.h | 3 ++ sizzlingstats/SizzlingStats.cpp | 38 ++++++++++++++++++++++-- sizzlingstats/SizzlingStats.h | 3 +- sizzlingstats/serverplugin_empty.cpp | 10 ++++++- 7 files changed, 115 insertions(+), 7 deletions(-) diff --git a/sizzlinglib/PlayerClassTracker.cpp b/sizzlinglib/PlayerClassTracker.cpp index 4d5e7e0..4615837 100644 --- a/sizzlinglib/PlayerClassTracker.cpp +++ b/sizzlinglib/PlayerClassTracker.cpp @@ -11,6 +11,10 @@ #include "PlayerClassTracker.h" +#define IS_SET(flag, bit) ((flag) & (bit)) +#define SET_BIT(var, bit) ((var) |= (bit)) +#define REMOVE_BIT(var, bit) ((var) &= ~(bit)) + void CPlayerClassTracker::Reset( EPlayerClass player_class /*= k_ePlayerClassUnknown*/, uint64 curtime /*= 0*/ ) @@ -34,8 +38,28 @@ void CPlayerClassTracker::Reset( void CPlayerClassTracker::StartRecording( EPlayerClass player_class, uint64 curtime ) { Reset(player_class, curtime); + REMOVE_BIT(m_classflags, PLAYER_DO_NOT_TRACK); +} + +void CPlayerClassTracker::PlayerSpawned( EPlayerClass player_class, uint64 curtime ) +{ + REMOVE_BIT(m_classflags, PLAYER_DO_NOT_TRACK); + m_lastUpdate = curtime; +} + +/* + * Called when: + * 1) Player has died + * 2) Round has ended + * 3) Player has disconnected + */ +void CPlayerClassTracker::PlayerNoTrack( uint64 curtime ) +{ + UpdateTimes(curtime); + SET_BIT(m_classflags, PLAYER_DO_NOT_TRACK); } + void CPlayerClassTracker::PlayerChangedClass( EPlayerClass player_class, uint64 curtime ) { uint16 iPlayerClass = static_cast(player_class); @@ -50,7 +74,7 @@ void CPlayerClassTracker::PlayerChangedClass( EPlayerClass player_class, uint64 void CPlayerClassTracker::UpdateTimes( uint64 curtime ) { - if (IsTFClass(m_currentClass)) + if (IsTFClass(m_currentClass) && !IS_SET(m_classflags,PLAYER_DO_NOT_TRACK)) { m_timeplayed[m_currentClass-1] += (curtime - m_lastUpdate); UpdateMostPlayedClass(curtime); @@ -76,6 +100,15 @@ void CPlayerClassTracker::UpdateMostPlayedClass( uint64 curtime ) } } +uint64 CPlayerClassTracker::GetPlayedTimeAs(uint16 player_class) const +{ + if(!IsTFClass(player_class)) + return 0; + + return m_timeplayed[player_class-1]; +} + + void CPlayerClassTracker::FlagClassAsPlayed( uint16 player_class ) { if (IsTFClass(player_class)) diff --git a/sizzlinglib/include/PlayerClassTracker.h b/sizzlinglib/include/PlayerClassTracker.h index d8dfc94..29a7de4 100644 --- a/sizzlinglib/include/PlayerClassTracker.h +++ b/sizzlinglib/include/PlayerClassTracker.h @@ -39,6 +39,11 @@ enum EPlayerClass #define PLAYED_SPY ( 1 << 7 ) #define PLAYED_ENGINEER ( 1 << 8 ) + +#define PLAYER_DO_NOT_TRACK (1 << 9 ) + + + class CPlayerClassTracker { public: @@ -50,10 +55,15 @@ class CPlayerClassTracker void StartRecording( EPlayerClass player_class, uint64 curtime ); void StopRecording( uint64 curtime ); + void PlayerSpawned( EPlayerClass player_class, uint64 curtime ); + void PlayerNoTrack( uint64 curtime ); void PlayerChangedClass( EPlayerClass player_class, uint64 curtime ); EPlayerClass GetMostPlayedClass(); uint16 GetPlayedClasses(); + + uint64 GetPlayedTimeAs(uint16 player_class) const; + /* bool PlayedScout() const { return (m_classflags & PLAYED_SCOUT); } bool PlayedSoldier() const { return (m_classflags & PLAYED_SOLDIER); } @@ -113,7 +123,7 @@ inline EPlayerClass CPlayerClassTracker::GetMostPlayedClass() inline uint16 CPlayerClassTracker::GetPlayedClasses() { - return m_classflags; + return m_classflags & 0x000000FF; } inline void CPlayerClassTracker::ResetFlags( uint16 player_class ) diff --git a/sizzlingstats/PlayerDataManager.cpp b/sizzlingstats/PlayerDataManager.cpp index 1f9bf97..5b9913d 100644 --- a/sizzlingstats/PlayerDataManager.cpp +++ b/sizzlingstats/PlayerDataManager.cpp @@ -115,6 +115,27 @@ void CPlayerDataManager::StopClassTracking( uint64 curtime ) } } +void CPlayerDataManager::PlayerAliveAndTrack( int ent_index, EPlayerClass player_class, uint64 curtime ) +{ + ent_index--; + if (m_pPlayerData[ent_index].GetBaseEntity()) + { + CPlayerClassTracker *pTracker = m_pPlayerData[ent_index].GetClassTracker(); + pTracker->PlayerSpawned(player_class, curtime); + } +} + +void CPlayerDataManager::PlayerDoNotTrack( int ent_index, uint64 curtime ) +{ + ent_index--; + if (m_pPlayerData[ent_index].GetBaseEntity()) + { + CPlayerClassTracker *pTracker = m_pPlayerData[ent_index].GetClassTracker(); + pTracker->PlayerNoTrack(curtime); + } +} + + void CPlayerDataManager::PlayerChangedClass( int ent_index, EPlayerClass player_class, uint64 curtime ) { // normalize with a -1 for array indexing diff --git a/sizzlingstats/PlayerDataManager.h b/sizzlingstats/PlayerDataManager.h index 9640d89..c90cd67 100644 --- a/sizzlingstats/PlayerDataManager.h +++ b/sizzlingstats/PlayerDataManager.h @@ -44,6 +44,9 @@ class CPlayerDataManager void ResetAndStartClassTracking( uint64 curtime ); void StopClassTracking( uint64 curtime ); + + void PlayerAliveAndTrack( int ent_index, EPlayerClass player_class, uint64 curtime ); + void PlayerDoNotTrack( int ent_index, uint64 curtime ); void PlayerChangedClass( int ent_index, EPlayerClass player_class, uint64 curtime ); void SetCapFix( int ent_index ); diff --git a/sizzlingstats/SizzlingStats.cpp b/sizzlingstats/SizzlingStats.cpp index 8504d69..854d09b 100644 --- a/sizzlingstats/SizzlingStats.cpp +++ b/sizzlingstats/SizzlingStats.cpp @@ -143,8 +143,19 @@ void SizzlingStats::UberDropped( int entindex ) data.m_pExtraData->ubersdropped += 1; } -void SizzlingStats::OnPlayerDeath(int inflictorEntIndex, int victimEntIndex) +void SizzlingStats::OnPlayerSpawn( int entindex, EPlayerClass player_class ) { + m_PlayerDataManager.PlayerAliveAndTrack( entindex, player_class, SCHelpers::RoundDBL(Plat_FloatTime()) ); +} + +void SizzlingStats::OnPlayerDeath( int inflictorEntIndex, int victimEntIndex ) +{ + + if(victimEntIndex <= 0) + return; + + m_PlayerDataManager.PlayerDoNotTrack( victimEntIndex, SCHelpers::RoundDBL(Plat_FloatTime()) ); + if (inflictorEntIndex <= 0 || victimEntIndex <= 0 || inflictorEntIndex == victimEntIndex) { @@ -339,6 +350,7 @@ void SizzlingStats::SS_PlayerDisconnect( CSizzPluginContext *pPluginContext, edi { if (m_PlayerDataManager.IsValidPlayer(ent_index)) { + m_PlayerDataManager.PlayerDoNotTrack(ent_index,SCHelpers::RoundDBL(Plat_FloatTime())); playerAndExtra_t data = m_PlayerDataManager.GetPlayerData(ent_index); data.m_pPlayerData->UpdateRoundStatsData(m_aPropOffsets); data.m_pPlayerData->UpdateRoundExtraData(*data.m_pExtraData); @@ -544,18 +556,37 @@ void SizzlingStats::SS_DisplayStats( CSizzPluginContext *pPluginContext, int ent if ( amounthealed != 0 ) { + CPlayerClassTracker *pTracker = playerData.GetClassTracker(); + uint64 play_time = pTracker->GetPlayedTimeAs(k_ePlayerClassMedic); + + /* memset( pText, 0, sizeof(pText) ); - V_snprintf( pText, 64, "Amount Healed: %i\n", amounthealed ); + V_snprintf( pText, 64, "DEBUG medic playtime: %llu\n", play_time); SS_SingleUserChatMessage(pPluginContext, ent_index, pText); + */ + + if(play_time > 0) + { + double avg_healing = ((1.00) * amounthealed) / play_time; + memset( pText, 0, sizeof(pText) ); + V_snprintf( pText, 64, "Average Healing: %.2f hp/sec\n", avg_healing); + SS_SingleUserChatMessage(pPluginContext, ent_index, pText); + } + } + if ( amounthealed != 0 ) + { + memset( pText, 0, sizeof(pText) ); + V_snprintf( pText, 64, "Amount Healed: %i\n", amounthealed ); + SS_SingleUserChatMessage(pPluginContext, ent_index, pText); + } if ( medpicks != 0 ) { memset( pText, 0, sizeof(pText) ); V_snprintf( pText, 64, "Medic Picks: %i\n", medpicks ); SS_SingleUserChatMessage(pPluginContext, ent_index, pText); } - if ( (backstabs != 0) && (headshots != 0) ) { memset( pText, 0, sizeof(pText) ); @@ -590,6 +621,7 @@ void SizzlingStats::SS_EndOfRound( CSizzPluginContext *pPluginContext ) { if (m_PlayerDataManager.IsValidPlayer(i)) { + m_PlayerDataManager.PlayerDoNotTrack(i,SCHelpers::RoundDBL(Plat_FloatTime())); playerAndExtra_t data = m_PlayerDataManager.GetPlayerData(i); data.m_pPlayerData->UpdateRoundStatsData(m_aPropOffsets); data.m_pPlayerData->UpdateRoundExtraData(*data.m_pExtraData); diff --git a/sizzlingstats/SizzlingStats.h b/sizzlingstats/SizzlingStats.h index 54bbc3c..f484e20 100644 --- a/sizzlingstats/SizzlingStats.h +++ b/sizzlingstats/SizzlingStats.h @@ -53,7 +53,8 @@ class SizzlingStats void PlayerHealed( int entindex, int amount ); void MedPick( int entindex ); void UberDropped( int entindex ); - void OnPlayerDeath(int inflictorEntIndex, int victimEntIndex); + void OnPlayerSpawn( int entindex, EPlayerClass player_class ); + void OnPlayerDeath( int inflictorEntIndex, int victimEntIndex); // this needs to be called whenever the player switches classes or goes to spec // set player_class to k_ePlayerClassUndefined if switching to spec diff --git a/sizzlingstats/serverplugin_empty.cpp b/sizzlingstats/serverplugin_empty.cpp index dca683e..c70cf95 100644 --- a/sizzlingstats/serverplugin_empty.cpp +++ b/sizzlingstats/serverplugin_empty.cpp @@ -307,11 +307,11 @@ bool CEmptyServerPlugin::Load( CreateInterfaceFn interfaceFactory, CreateInterfa m_plugin_context.AddListener( this, "player_team", true ); m_plugin_context.AddListener( this, "player_death", true ); + m_plugin_context.AddListener( this, "player_spawn", true ); // when a player spawns... //m_plugin_context.AddListener( this, "tournament_stateupdate", true ); // for getting team names //m_plugin_context.AddListener( this, "player_shoot", true ); // for accuracy stats //m_plugin_context.AddListener( this, "player_chargedeployed", true ); // when a medic deploys uber/kritz - //m_plugin_context.AddListener( this, "player_spawn", true ); // when a player spawns... //m_plugin_context.AddListener( this, "teamplay_suddendeath_end", true ); //m_plugin_context.AddListener( this, "teamplay_overtime_end", true ); @@ -848,6 +848,14 @@ void CEmptyServerPlugin::FireGameEvent( IGameEvent *event ) m_SizzlingStats.OnPlayerDeath(inflictor, victim); //m_SizzlingStats.CheckPlayerDropped( &m_plugin_context, victim ); } + else if ( m_bShouldRecord && FStrEq( name, "player_spawn" ) ) + { + const int victim = m_plugin_context.EntIndexFromUserID(event->GetInt( "userid" )); + const int team = event->GetInt("team"); + EPlayerClass player_class = static_cast(event->GetInt("class")); + + m_SizzlingStats.OnPlayerSpawn(victim,player_class); + } else if ( m_bShouldRecord && FStrEq( name, "medic_death" ) ) { int killerIndex = m_plugin_context.EntIndexFromUserID(event->GetInt( "attacker" )); // med picks