core/TimerSys.cpp
author Michael McKoy <ferret99gt@gmail.com>
Wed Aug 08 23:45:24 2007 +0000 (2007-08-08)
changeset 1284 ac293d8351a3
parent 1231 17badaf66ce4
child 1330 ab94316bb52b
permissions -rw-r--r--
Import of baseplugins.sp
dvander@592
     1
/**
ds@653
     2
 * vim: set ts=4 :
dvander@1231
     3
 * ================================================================
dvander@1231
     4
 * SourceMod
dvander@1231
     5
 * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
dvander@1231
     6
 * ================================================================
ds@653
     7
 *
dvander@1231
     8
 * This program is free software; you can redistribute it and/or 
dvander@1231
     9
 * modify it under the terms of the GNU General Public License, 
dvander@1231
    10
 * version 3.0, as published by the Free Software Foundation.
dvander@1231
    11
 * 
dvander@1231
    12
 * This program is distributed in the hope that it will be useful,
dvander@1231
    13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
dvander@1231
    14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
dvander@1231
    15
 * GNU General Public License for more details.
dvander@1231
    16
 *
dvander@1231
    17
 * You should have received a copy of the GNU General Public License
dvander@1231
    18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
dvander@1231
    20
 * As a special exception, AlliedModders LLC gives you permission to 
dvander@1231
    21
 * link the code of this program (as well as its derivative works) to 
dvander@1231
    22
 * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any 
dvander@1231
    23
 * Game MODs that run on software by the Valve Corporation.  You must 
dvander@1231
    24
 * obey the GNU General Public License in all respects for all other 
dvander@1231
    25
 * code used. Additionally, AlliedModders LLC grants this exception 
dvander@1231
    26
 * to all derivative works. AlliedModders LLC defines further 
dvander@1231
    27
 * exceptions, found in LICENSE.txt (as of this writing, version 
dvander@1231
    28
 * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
ds@653
    29
 *
ds@653
    30
 * Version: $Id$
ds@653
    31
 */
dvander@592
    32
dvander@592
    33
#include "TimerSys.h"
dvander@592
    34
dvander@616
    35
TimerSystem g_Timers;
dvander@727
    36
TickInfo g_SimTicks;
dvander@727
    37
dvander@727
    38
inline float GetSimulatedTime()
dvander@727
    39
{
dvander@727
    40
	if (g_SimTicks.ticking)
dvander@727
    41
	{
dvander@727
    42
		return gpGlobals->curtime;
dvander@727
    43
	} else {
dvander@727
    44
		return g_SimTicks.ticktime;
dvander@727
    45
	}
dvander@727
    46
}
dvander@592
    47
dvander@592
    48
void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags)
dvander@592
    49
{
dvander@592
    50
	m_Listener = pCallbacks;
dvander@592
    51
	m_Interval = fInterval;
dvander@592
    52
	m_ToExec = fToExec;
dvander@592
    53
	m_pData = pData;
dvander@592
    54
	m_Flags = flags;
dvander@592
    55
	m_InExec = false;
dvander@592
    56
	m_KillMe = false;
dvander@592
    57
}
dvander@592
    58
faluco@641
    59
TimerSystem::~TimerSystem()
faluco@641
    60
{
faluco@641
    61
	CStack<ITimer *>::iterator iter;
faluco@641
    62
	for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
faluco@641
    63
	{
faluco@641
    64
		delete (*iter);
faluco@641
    65
	}
faluco@641
    66
	m_FreeTimers.popall();
faluco@641
    67
}
faluco@641
    68
dvander@616
    69
void TimerSystem::OnSourceModAllInitialized()
dvander@592
    70
{
dvander@592
    71
	g_ShareSys.AddInterface(NULL, this);
dvander@592
    72
}
dvander@592
    73
dvander@673
    74
void TimerSystem::OnSourceModLevelChange(const char *mapName)
dvander@673
    75
{
dvander@1142
    76
	MapChange(true);
dvander@673
    77
}
dvander@673
    78
dvander@616
    79
void TimerSystem::RunFrame()
dvander@592
    80
{
dvander@592
    81
	ITimer *pTimer;
dvander@592
    82
	TimerIter iter;
dvander@592
    83
dvander@727
    84
	float curtime = GetSimulatedTime();
dvander@592
    85
	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
dvander@592
    86
	{
dvander@592
    87
		pTimer = (*iter);
dvander@727
    88
		if (curtime >= pTimer->m_ToExec)
dvander@592
    89
		{
dvander@592
    90
			pTimer->m_InExec = true;
dvander@592
    91
			pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
faluco@612
    92
			pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
dvander@592
    93
			iter = m_SingleTimers.erase(iter);
dvander@592
    94
			m_FreeTimers.push(pTimer);
dvander@592
    95
		} else {
dvander@592
    96
			break;
dvander@592
    97
		}
dvander@592
    98
	}
dvander@592
    99
dvander@592
   100
	ResultType res;
dvander@592
   101
	for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); )
dvander@592
   102
	{
dvander@592
   103
		pTimer = (*iter);
dvander@727
   104
		if (curtime >= pTimer->m_ToExec)
dvander@592
   105
		{
dvander@592
   106
			pTimer->m_InExec = true;
dvander@592
   107
			res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
dvander@592
   108
			if (pTimer->m_KillMe || (res == Pl_Stop))
dvander@592
   109
			{
dvander@592
   110
				pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
dvander@592
   111
				iter = m_LoopTimers.erase(iter);
dvander@592
   112
				m_FreeTimers.push(pTimer);
dvander@592
   113
				continue;
dvander@592
   114
			}
dvander@592
   115
			pTimer->m_InExec = false;
dvander@727
   116
			pTimer->m_ToExec = curtime + pTimer->m_Interval;
dvander@592
   117
		}
dvander@592
   118
		iter++;
dvander@592
   119
	}
dvander@592
   120
dvander@727
   121
	m_LastExecTime = curtime;
dvander@592
   122
}
dvander@592
   123
dvander@616
   124
ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags)
dvander@592
   125
{
dvander@592
   126
	ITimer *pTimer;
dvander@592
   127
	TimerIter iter;
dvander@727
   128
	float to_exec = GetSimulatedTime() + fInterval;
dvander@592
   129
dvander@592
   130
	if (m_FreeTimers.empty())
dvander@592
   131
	{
dvander@592
   132
		pTimer = new ITimer;
dvander@592
   133
	} else {
dvander@592
   134
		pTimer = m_FreeTimers.front();
dvander@592
   135
		m_FreeTimers.pop();
dvander@592
   136
	}
dvander@592
   137
dvander@592
   138
	pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags);
dvander@592
   139
dvander@592
   140
	if (flags & TIMER_FLAG_REPEAT)
dvander@592
   141
	{
dvander@592
   142
		m_LoopTimers.push_back(pTimer);
dvander@592
   143
		goto return_timer;
dvander@592
   144
	}
dvander@592
   145
dvander@592
   146
	if (m_SingleTimers.size() >= 1)
dvander@592
   147
	{
dvander@592
   148
		iter = --m_SingleTimers.end();
dvander@592
   149
		if ((*iter)->m_ToExec <= to_exec)
dvander@592
   150
		{
dvander@592
   151
			goto insert_end;
dvander@592
   152
		}
dvander@592
   153
	}
dvander@592
   154
dvander@592
   155
	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
dvander@592
   156
	{
dvander@592
   157
		if ((*iter)->m_ToExec >= to_exec)
dvander@592
   158
		{
dvander@592
   159
			m_SingleTimers.insert(iter, pTimer);
dvander@592
   160
			goto return_timer;
dvander@592
   161
		}
dvander@592
   162
	}
dvander@592
   163
dvander@592
   164
insert_end:
dvander@592
   165
	m_SingleTimers.push_back(pTimer);
dvander@592
   166
dvander@592
   167
return_timer:
dvander@592
   168
	return pTimer;
dvander@592
   169
}
dvander@592
   170
dvander@616
   171
void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec)
dvander@592
   172
{
dvander@592
   173
	ResultType res;
dvander@592
   174
dvander@592
   175
	if (pTimer->m_InExec)
dvander@592
   176
	{
dvander@592
   177
		return;
dvander@592
   178
	}
dvander@592
   179
dvander@592
   180
	pTimer->m_InExec = true;
dvander@592
   181
	res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
dvander@592
   182
dvander@592
   183
	if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT))
dvander@592
   184
	{
dvander@592
   185
		pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
dvander@592
   186
		m_SingleTimers.remove(pTimer);
dvander@592
   187
		m_FreeTimers.push(pTimer);
dvander@592
   188
	} else {
faluco@612
   189
		if ((res != Pl_Stop) && !pTimer->m_KillMe)
dvander@592
   190
		{
faluco@612
   191
			if (delayExec)
faluco@612
   192
			{
dvander@727
   193
				pTimer->m_ToExec = GetSimulatedTime() + pTimer->m_Interval;
faluco@612
   194
			}
dvander@592
   195
			pTimer->m_InExec = false;
dvander@592
   196
			return;
dvander@592
   197
		}
dvander@592
   198
		pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
dvander@592
   199
		m_LoopTimers.remove(pTimer);
dvander@592
   200
		m_FreeTimers.push(pTimer);
dvander@592
   201
	}
dvander@592
   202
}
dvander@592
   203
dvander@616
   204
void TimerSystem::KillTimer(ITimer *pTimer)
dvander@592
   205
{
dvander@592
   206
	TimerList *pList;
dvander@592
   207
dvander@592
   208
	if (pTimer->m_KillMe)
dvander@592
   209
	{
dvander@592
   210
		return;
dvander@592
   211
	}
dvander@592
   212
dvander@592
   213
	if (pTimer->m_InExec)
dvander@592
   214
	{
dvander@592
   215
		pTimer->m_KillMe = true;
dvander@592
   216
		return;
dvander@592
   217
	}
dvander@592
   218
dvander@592
   219
	pTimer->m_InExec = true; /* The timer it's not really executed but this check needs to be done */
dvander@592
   220
	pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
dvander@592
   221
dvander@592
   222
	pList = (pTimer->m_Flags & TIMER_FLAG_REPEAT) ? &m_LoopTimers : &m_SingleTimers;
dvander@592
   223
dvander@592
   224
	pList->remove(pTimer);
dvander@592
   225
	m_FreeTimers.push(pTimer);
dvander@592
   226
}
dvander@592
   227
dvander@1108
   228
CStack<ITimer *> s_tokill;
dvander@1142
   229
void TimerSystem::MapChange(bool real_mapchange)
dvander@592
   230
{
dvander@592
   231
	ITimer *pTimer;
dvander@592
   232
	TimerIter iter;
dvander@592
   233
dvander@592
   234
	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
dvander@592
   235
	{
dvander@592
   236
		pTimer = (*iter);
dvander@1142
   237
		if (real_mapchange && (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE))
dvander@1108
   238
		{
dvander@1108
   239
			s_tokill.push(pTimer);
dvander@1108
   240
		} else {
dvander@1108
   241
			pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime();
dvander@1108
   242
		}
dvander@592
   243
	}
dvander@592
   244
dvander@592
   245
	for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++)
dvander@592
   246
	{
dvander@592
   247
		pTimer = (*iter);
dvander@1142
   248
		if (real_mapchange && (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE))
dvander@1108
   249
		{
dvander@1108
   250
			s_tokill.push(pTimer);
dvander@1108
   251
		} else {
dvander@1108
   252
			pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime();
dvander@1108
   253
		}
dvander@1108
   254
	}
dvander@1108
   255
dvander@1108
   256
	while (!s_tokill.empty())
dvander@1108
   257
	{
dvander@1108
   258
		KillTimer(s_tokill.front());
dvander@1108
   259
		s_tokill.pop();
dvander@592
   260
	}
dvander@727
   261
dvander@727
   262
	m_LastExecTime = GetSimulatedTime();
dvander@592
   263
}