removed tick simulator and added api to help with mapchanges

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401413
This commit is contained in:
David Anderson 2007-09-11 18:02:59 +00:00
parent 017da078ef
commit 293705f63f
5 changed files with 104 additions and 106 deletions

View File

@ -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;
}

View File

@ -44,13 +44,6 @@ using namespace SourceMod;
typedef List<ITimer *> TimerList;
typedef List<ITimer *>::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<ITimer *> m_SingleTimers;
List<ITimer *> m_LoopTimers;
List<ITimer *> m_MapEndTimers;
CStack<ITimer *> 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_

View File

@ -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);
}

View File

@ -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();

View File

@ -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 <interval> 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_