From 6206027476f7c023a5127be8fd029a3132a87c8a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 13 Sep 2007 00:33:56 +0000 Subject: [PATCH] overhaul of the map timer idea -- function is now an interface, and the timer flag is removed --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401420 --- core/TimerSys.cpp | 212 +++++++++++++++++++++++++++--------------- core/TimerSys.h | 8 +- public/ITimerSystem.h | 64 +++++++++++-- 3 files changed, 199 insertions(+), 85 deletions(-) diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index b07a95b4..4a7e15fc 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -35,9 +35,13 @@ #include "sourcemm_api.h" #include "frame_hooks.h" +SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallback, SH_NOATTRIB, false, ConVar *, const char *); + TimerSystem g_Timers; float g_fUniversalTime = 0.0f; +float g_fMapStartTime = 0.0f; const float *g_pUniversalTime = &g_fUniversalTime; +ConVar *mp_timelimit = NULL; ConVar sm_time_adjustment("sm_time_adjustment", "0", 0, "Adjusts the server time in seconds"); @@ -56,6 +60,84 @@ time_t GetAdjustedTime(time_t *buf) return val; } +class DefaultMapTimer : + public IMapTimer, + public SMGlobalClass +{ +public: + DefaultMapTimer() + { + m_bInUse = false; + } + + int GetMapTimeLimit() + { + return mp_timelimit->GetInt(); + } + + void SetMapTimerStatus(bool enabled) + { + if (enabled && !m_bInUse) + { + Enable(); + } + else if (!enabled && m_bInUse) + { + Disable(); + } + m_bInUse = enabled; + } + + bool GetMapTimeLeft(int *time_left) + { + if (GetMapTimeLimit() == 0) + { + return false; + } + + *time_left = (int)((g_fMapStartTime + mp_timelimit->GetInt() * 60.0f) - g_fUniversalTime); + + return true; + } + + void ExtendMapTimeLimit(int extra_time) + { + extra_time /= 60; + + if (extra_time == 0) + { + mp_timelimit->SetValue(0); + return; + } + + mp_timelimit->SetValue(mp_timelimit->GetInt() + extra_time); + } + + void GlobalChangeCallback(ConVar *pVar, const char *old_value) + { + if (pVar != mp_timelimit) + { + return; + } + + g_Timers.MapTimeLimitExtended(atoi(old_value) * 60, pVar->GetInt() * 60); + } + +private: + void Enable() + { + SH_ADD_HOOK_MEMFUNC(ICvar, CallGlobalChangeCallback, icvar, this, &DefaultMapTimer::GlobalChangeCallback, false); + } + + void Disable() + { + SH_REMOVE_HOOK_MEMFUNC(ICvar, CallGlobalChangeCallback, icvar, this, &DefaultMapTimer::GlobalChangeCallback, false); + } + +private: + bool m_bInUse; +} s_DefaultMapTimer; + void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags) { m_Listener = pCallbacks; @@ -69,7 +151,7 @@ void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, TimerSystem::TimerSystem() { - m_fnTimeLeft = NULL; + m_pMapTimer = NULL; m_bHasMapTickedYet = false; m_fLastTickedTime = 0.0f; m_LastExecTime = 0.0f; @@ -91,8 +173,19 @@ void TimerSystem::OnSourceModAllInitialized() m_pOnGameFrame = g_Forwards.CreateForward("OnGameFrame", ET_Ignore, 0, NULL); } +void TimerSystem::OnSourceModGameInitialized() +{ + mp_timelimit = icvar->FindVar("mp_timelimit"); + + if (m_pMapTimer == NULL && mp_timelimit != NULL) + { + SetMapTimer(&s_DefaultMapTimer); + } +} + void TimerSystem::OnSourceModShutdown() { + SetMapTimer(NULL); g_Forwards.ReleaseForward(m_pOnGameFrame); } @@ -118,7 +211,11 @@ void TimerSystem::GameFrame(bool simulating) } m_fLastTickedTime = gpGlobals->curtime; - m_bHasMapTickedYet = true; + if (!m_bHasMapTickedYet) + { + g_fMapStartTime = g_fUniversalTime; + m_bHasMapTickedYet = true; + } if (g_fUniversalTime - m_LastExecTime >= 0.1) { @@ -154,25 +251,6 @@ void TimerSystem::RunFrame() } } - if (m_fnTimeLeft != NULL && m_MapEndTimers.size()) - { - float time_left = m_fnTimeLeft(); - for (iter=m_MapEndTimers.begin(); iter!=m_MapEndTimers.end();) - { - pTimer = (*iter); - if ((*iter)->m_Interval < time_left) - { - pTimer->m_InExec = true; - pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); - pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - iter = m_MapEndTimers.erase(iter); - m_FreeTimers.push(pTimer); - } else { - break; - } - } - } - ResultType res; for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); ) { @@ -203,12 +281,6 @@ ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void TimerIter iter; float to_exec = GetSimulatedTime() + fInterval; - if ((flags & TIMER_FLAG_BEFORE_MAP_END) - && m_fnTimeLeft == NULL) - { - return NULL; - } - if (m_FreeTimers.empty()) { pTimer = new ITimer; @@ -225,40 +297,26 @@ ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void goto return_timer; } - if (flags & TIMER_FLAG_BEFORE_MAP_END) + if (m_SingleTimers.size() >= 1) { - for (iter=m_MapEndTimers.begin(); iter!=m_MapEndTimers.end(); iter++) + iter = --m_SingleTimers.end(); + if ((*iter)->m_ToExec <= to_exec) { - if (fInterval >= (*iter)->m_Interval) - { - m_MapEndTimers.insert(iter, pTimer); - goto return_timer; - } + goto normal_insert_end; } + } - m_MapEndTimers.push_back(pTimer); - } else { - if (m_SingleTimers.size() >= 1) + for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++) + { + if ((*iter)->m_ToExec >= to_exec) { - iter = --m_SingleTimers.end(); - if ((*iter)->m_ToExec <= to_exec) - { - goto normal_insert_end; - } - } - - for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++) - { - if ((*iter)->m_ToExec >= to_exec) - { - m_SingleTimers.insert(iter, pTimer); - goto return_timer; - } + m_SingleTimers.insert(iter, pTimer); + goto return_timer; } + } normal_insert_end: - m_SingleTimers.push_back(pTimer); - } + m_SingleTimers.push_back(pTimer); return_timer: return pTimer; @@ -279,12 +337,7 @@ void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT)) { pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - if (pTimer->m_Flags & TIMER_FLAG_BEFORE_MAP_END) - { - m_MapEndTimers.remove(pTimer); - } else { - m_SingleTimers.remove(pTimer); - } + m_SingleTimers.remove(pTimer); m_FreeTimers.push(pTimer); } else { if ((res != Pl_Stop) && !pTimer->m_KillMe) @@ -321,8 +374,6 @@ void TimerSystem::KillTimer(ITimer *pTimer) if (pTimer->m_Flags & TIMER_FLAG_REPEAT) { m_LoopTimers.remove(pTimer); - } else if (pTimer->m_Flags & TIMER_FLAG_BEFORE_MAP_END) { - m_MapEndTimers.remove(pTimer); } else { m_SingleTimers.remove(pTimer); } @@ -354,15 +405,6 @@ void TimerSystem::MapChange(bool real_mapchange) } } - if (real_mapchange) - { - for (iter=m_MapEndTimers.begin(); iter!=m_MapEndTimers.end(); iter++) - { - pTimer = (*iter); - s_tokill.push(pTimer); - } - } - while (!s_tokill.empty()) { KillTimer(s_tokill.front()); @@ -370,10 +412,34 @@ void TimerSystem::MapChange(bool real_mapchange) } } -SM_TIMELEFT_FUNCTION TimerSystem::SetTimeLeftFunction(SM_TIMELEFT_FUNCTION fn) +IMapTimer *TimerSystem::SetMapTimer(IMapTimer *pTimer) { - SM_TIMELEFT_FUNCTION old = m_fnTimeLeft; - m_fnTimeLeft = fn; + IMapTimer *old = m_pMapTimer; + + m_pMapTimer = pTimer; + + if (m_pMapTimer) + { + m_pMapTimer->SetMapTimerStatus(true); + } + + if (old) + { + old->SetMapTimerStatus(false); + } + return old; } +IMapTimer *TimerSystem::GetMapTimer() +{ + return m_pMapTimer; +} + +void TimerSystem::MapTimeLimitExtended(int old_limit, int new_limit) +{ + if (old_limit == new_limit) + { + return; + } +} diff --git a/core/TimerSys.h b/core/TimerSys.h index 7c841f5f..8fca724c 100644 --- a/core/TimerSys.h +++ b/core/TimerSys.h @@ -68,23 +68,25 @@ public: //SMGlobalClass void OnSourceModAllInitialized(); void OnSourceModLevelChange(const char *mapName); void OnSourceModLevelEnd(); + void OnSourceModGameInitialized(); void OnSourceModShutdown(); public: //ITimerSystem ITimer *CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags); void KillTimer(ITimer *pTimer); void FireTimerOnce(ITimer *pTimer, bool delayExec=false); - SM_TIMELEFT_FUNCTION SetTimeLeftFunction(SM_TIMELEFT_FUNCTION fn); + void MapTimeLimitExtended(int old_limit, int new_limit); + IMapTimer *SetMapTimer(IMapTimer *pTimer); public: void RunFrame(); void MapChange(bool real_mapchange); void GameFrame(bool simulating); + IMapTimer *GetMapTimer(); private: List m_SingleTimers; List m_LoopTimers; - List m_MapEndTimers; CStack m_FreeTimers; float m_LastExecTime; - SM_TIMELEFT_FUNCTION m_fnTimeLeft; + IMapTimer *m_pMapTimer; /* This is stuff for our manual ticking escapades. */ bool m_bHasMapTickedYet; /** Has the map ticked yet? */ diff --git a/public/ITimerSystem.h b/public/ITimerSystem.h index 8f450929..dca2898b 100644 --- a/public/ITimerSystem.h +++ b/public/ITimerSystem.h @@ -48,7 +48,47 @@ namespace SourceMod { class ITimer; - typedef float (*SM_TIMELEFT_FUNCTION)(); + /** + * @brief Interface for map timers. + */ + class IMapTimer + { + public: + /** + * Returns the current map time limit in seconds. + * + * @return Time limit, in seconds, or + * 0 if there is no limit. + */ + virtual int GetMapTimeLimit() =0; + + /** + * Returns how much time is left in the map. + * + * @param time_left Pointer to store time, in seconds. + * @return True if there is a time limit, false + * if the time limit is 0. + */ + virtual bool GetMapTimeLeft(int *time_left) =0; + + /** + * Extends the map limit (either positively or negatively) in seconds. + * + * @param extra_time Time to extend map by. If 0, the map will + * be set to have no time limit. + */ + virtual void ExtendMapTimeLimit(int extra_time) =0; + + /** + * Tells the map timer whether it is being used or not. + * + * Map timers are automatically enabled when they are set, and + * automatically disabled if being un-set. + * + * @param enabled True if enabling, false if disabling. + */ + virtual void SetMapTimerStatus(bool enabled) =0; + }; /** * @brief Event callbacks for when a timer is executed. @@ -76,10 +116,6 @@ namespace SourceMod #define TIMER_FLAG_REPEAT (1<<0) /**< Timer will repeat until stopped */ #define TIMER_FLAG_NO_MAPCHANGE (1<<1) /**< Timer will not carry over mapchanges */ - #define TIMER_FLAG_BEFORE_MAP_END (1<<2) /**< Timer will fire seconds before map end. - This flag is cannot be used with REPEAT, - and TIMER_FLAG_NO_MAPCHANGE is implied. - */ class ITimerSystem : public SMInterface { @@ -130,12 +166,22 @@ namespace SourceMod virtual void FireTimerOnce(ITimer *pTimer, bool delayExec=false) =0; /** - * @brief Sets the function which is used to find the time left in the map. + * @brief Sets the interface for dealing with map time limits. * - * @param fn Function that returns the time left in seconds. - * @return The previous SM_TIMELEFT_FUNCTION pointer. + * @param pMapTimer Map timer interface pointer. + * @return Old pointer. */ - virtual SM_TIMELEFT_FUNCTION SetTimeLeftFunction(SM_TIMELEFT_FUNCTION fn) =0; + virtual IMapTimer *SetMapTimer(IMapTimer *pTimer) =0; + + /** + * @brief Notifies the timer that the map timelimit has been extended. + * + * A time limit of 0 implies that there is no limit. + * + * @param old_limit Old limit, in seconds. + * @param new_limit New limit, in seconds. + */ + virtual void MapTimeLimitExtended(int old_limit, int new_limit) =0; }; }