diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index bbe7d4d0..37f13caa 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -34,7 +34,6 @@ #include "sourcemm_api.h" TimerSystem g_Timers; -TickInfo g_SimTicks; ConVar sm_time_adjustment("sm_time_adjustment", "0", 0, "Adjusts the server time in seconds"); @@ -50,12 +49,7 @@ time_t GetAdjustedTime(time_t *buf) inline float GetSimulatedTime() { - if (g_SimTicks.ticking) - { - return gpGlobals->curtime; - } else { - return g_SimTicks.ticktime; - } + return engine->Time(); } void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags) @@ -110,6 +104,25 @@ 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(); ) { @@ -156,26 +169,40 @@ ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void goto return_timer; } - if (m_SingleTimers.size() >= 1) + if (flags & TIMER_FLAG_BEFORE_MAP_END) { - iter = --m_SingleTimers.end(); - if ((*iter)->m_ToExec <= to_exec) + for (iter=m_MapEndTimers.begin(); iter!=m_MapEndTimers.end(); iter++) { - goto insert_end; + if (fInterval >= (*iter)->m_Interval) + { + m_MapEndTimers.insert(iter, pTimer); + goto return_timer; + } } - } - for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++) - { - if ((*iter)->m_ToExec >= to_exec) + m_MapEndTimers.push_back(pTimer); + } else { + if (m_SingleTimers.size() >= 1) { - m_SingleTimers.insert(iter, pTimer); - goto return_timer; + 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; + } } - } -insert_end: - m_SingleTimers.push_back(pTimer); +normal_insert_end: + m_SingleTimers.push_back(pTimer); + } return_timer: return pTimer; @@ -196,7 +223,12 @@ void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT)) { pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - m_SingleTimers.remove(pTimer); + if (pTimer->m_Flags & TIMER_FLAG_BEFORE_MAP_END) + { + m_MapEndTimers.remove(pTimer); + } else { + m_SingleTimers.remove(pTimer); + } m_FreeTimers.push(pTimer); } else { if ((res != Pl_Stop) && !pTimer->m_KillMe) @@ -232,7 +264,14 @@ void TimerSystem::KillTimer(ITimer *pTimer) pTimer->m_InExec = true; /* The timer it's not really executed but this check needs to be done */ pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - pList = (pTimer->m_Flags & TIMER_FLAG_REPEAT) ? &m_LoopTimers : &m_SingleTimers; + 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); + } pList->remove(pTimer); m_FreeTimers.push(pTimer); @@ -266,6 +305,15 @@ 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()); @@ -274,3 +322,11 @@ void TimerSystem::MapChange(bool real_mapchange) m_LastExecTime = GetSimulatedTime(); } + +SM_TIMELEFT_FUNCTION TimerSystem::SetTimeLeftFunction(SM_TIMELEFT_FUNCTION fn) +{ + SM_TIMELEFT_FUNCTION old = m_fnTimeLeft; + m_fnTimeLeft = fn; + return old; +} + diff --git a/core/TimerSys.h b/core/TimerSys.h index 41bf9527..9dc3ca63 100644 --- a/core/TimerSys.h +++ b/core/TimerSys.h @@ -44,13 +44,6 @@ using namespace SourceMod; typedef List TimerList; typedef List::iterator TimerIter; -struct TickInfo -{ - bool ticking; /* true=game is ticking, false=we're ticking */ - unsigned int tickcount; /* number of simulated ticks we've done */ - float ticktime; /* tick time we're maintaining */ -}; - class SourceMod::ITimer { public: @@ -77,19 +70,22 @@ 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); public: void RunFrame(); void MapChange(bool real_mapchange); private: List m_SingleTimers; List m_LoopTimers; + List m_MapEndTimers; CStack m_FreeTimers; float m_LastExecTime; + SM_TIMELEFT_FUNCTION m_fnTimeLeft; }; time_t GetAdjustedTime(time_t *buf = NULL); extern TimerSystem g_Timers; -extern TickInfo g_SimTicks; #endif //_INCLUDE_SOURCEMOD_CTIMERSYS_H_ + diff --git a/core/smn_timers.cpp b/core/smn_timers.cpp index ab6f6710..f65580f2 100644 --- a/core/smn_timers.cpp +++ b/core/smn_timers.cpp @@ -248,12 +248,7 @@ static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params) static cell_t smn_GetTickedTime(IPluginContext *pContext, const cell_t *params) { - cell_t *simulating; - pContext->LocalToPhysAddr(params[1], &simulating); - - *simulating = g_SimTicks.ticking ? 0 : 1; - - float t = g_SimTicks.ticking ? gpGlobals->curtime : g_SimTicks.ticktime; + float t = engine->Time(); return sp_ftoc(t); } diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 738253cf..51ba5a5a 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -71,8 +71,6 @@ float g_LastAuthCheck = 0.0f; IForward *g_pOnGameFrame = NULL; IForward *g_pOnMapEnd = NULL; bool g_Loaded = false; -int g_StillFrames = 0; -float g_StillTime = 0.0f; IExtension *g_pGameExt = NULL; typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *); @@ -335,10 +333,6 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch g_LastTime = 0.0f; g_LastMenuTime = 0.0f; g_LastAuthCheck = 0.0f; - g_SimTicks.ticking = true; - g_SimTicks.tickcount = 0; - g_StillTime = 0.0f; - g_StillFrames = 0; /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; @@ -375,27 +369,6 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch RETURN_META_VALUE(MRES_IGNORED, true); } -void StartTickSimulation() -{ - g_SimTicks.ticking = false; - g_SimTicks.tickcount = 0; - g_SimTicks.ticktime = gpGlobals->curtime; -} - -void StopTickSimulation() -{ - g_SimTicks.ticking = true; - g_Timers.MapChange(false); - g_StillFrames = 0; - g_LastTime = gpGlobals->curtime; -} - -void SimulateTick() -{ - g_SimTicks.tickcount++; - g_SimTicks.ticktime = g_StillTime + (g_SimTicks.tickcount * gpGlobals->interval_per_tick); -} - void SourceModBase::GameFrame(bool simulating) { g_DBMan.RunFrame(); @@ -405,46 +378,7 @@ void SourceModBase::GameFrame(bool simulating) * Note: This is all hardcoded rather than delegated to save * precious CPU cycles. */ - float curtime = gpGlobals->curtime; - int framecount = gpGlobals->framecount; - - /* Verify that we're still ticking */ - if (g_SimTicks.ticking) - { - if (g_StillFrames == 0) - { - g_StillFrames = framecount; - g_StillTime = curtime; - } else { - /* Try to detect when we've stopped ticking. - * We do this once 10 frames pass and there have been no ticks. - */ - if (g_StillTime == curtime) - { - if (framecount - g_StillFrames >= 5) - { - StartTickSimulation(); - return; - } - } else { - /* We're definitely ticking we get here, - * but update everything as a precaution */ - g_StillFrames = framecount; - g_StillTime = curtime; - } - } - } else { - /* We need to make sure we should still be simulating. */ - if (g_StillTime != curtime) - { - /* Wow, we're ticking again! It's time to revert. */ - StopTickSimulation(); - return; - } - /* Nope, not ticking. Simulate! */ - SimulateTick(); - curtime = g_SimTicks.ticktime; - } + float curtime = engine->Time(); if (curtime - g_LastTime >= 0.1f) { @@ -459,7 +393,7 @@ void SourceModBase::GameFrame(bool simulating) g_LastTime = curtime; } - if (g_SimTicks.ticking && curtime - g_LastMenuTime >= 1.0f) + if (gpGlobals->curtime - g_LastMenuTime >= 1.0f) { g_ValveMenuStyle.ProcessWatchList(); g_RadioMenuStyle.ProcessWatchList(); diff --git a/public/ITimerSystem.h b/public/ITimerSystem.h index c2137983..8f450929 100644 --- a/public/ITimerSystem.h +++ b/public/ITimerSystem.h @@ -48,6 +48,8 @@ namespace SourceMod { class ITimer; + typedef float (*SM_TIMELEFT_FUNCTION)(); + /** * @brief Event callbacks for when a timer is executed. */ @@ -74,6 +76,10 @@ 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 { @@ -95,7 +101,8 @@ namespace SourceMod * The smallest allowed interval is 0.1 seconds. * @param pData Private data to pass on to the timer. * @param flags Extra flags to pass on to the timer. - * @return An ITimer pointer on success, NULL on failure. + * @return An ITimer pointer on success, NULL on + * failure. */ virtual ITimer *CreateTimer(ITimedEvent *pCallbacks, float fInterval, @@ -116,11 +123,21 @@ namespace SourceMod * * @param pTimer Pointer to the ITimer structure. * @param delayExec If true, and the timer is repeating, the - * next execution will be delayed by its interval. + * next execution will be delayed by its + * interval. * @return */ virtual void FireTimerOnce(ITimer *pTimer, bool delayExec=false) =0; + + /** + * @brief Sets the function which is used to find the time left in the map. + * + * @param fn Function that returns the time left in seconds. + * @return The previous SM_TIMELEFT_FUNCTION pointer. + */ + virtual SM_TIMELEFT_FUNCTION SetTimeLeftFunction(SM_TIMELEFT_FUNCTION fn) =0; }; } #endif //_INCLUDE_SOURCEMOD_TIMER_SYSTEM_H_ +