1.1 --- a/core/TimerSys.cpp Fri Jul 11 06:51:21 2008 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,487 +0,0 @@
1.4 -/**
1.5 - * vim: set ts=4 :
1.6 - * =============================================================================
1.7 - * SourceMod
1.8 - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 - * =============================================================================
1.10 - *
1.11 - * This program is free software; you can redistribute it and/or modify it under
1.12 - * the terms of the GNU General Public License, version 3.0, as published by the
1.13 - * Free Software Foundation.
1.14 - *
1.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 - * details.
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License along with
1.21 - * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 - *
1.23 - * As a special exception, AlliedModders LLC gives you permission to link the
1.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 - * by the Valve Corporation. You must obey the GNU General Public License in
1.27 - * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 - * this exception to all derivative works. AlliedModders LLC defines further
1.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 - * or <http://www.sourcemod.net/license.php>.
1.31 - *
1.32 - * Version: $Id$
1.33 - */
1.34 -
1.35 -#include <time.h>
1.36 -#include "TimerSys.h"
1.37 -#include "ForwardSys.h"
1.38 -#include "sourcemm_api.h"
1.39 -#include "frame_hooks.h"
1.40 -#include "ConVarManager.h"
1.41 -
1.42 -#define TIMER_MIN_ACCURACY 0.1
1.43 -
1.44 -TimerSystem g_Timers;
1.45 -double g_fUniversalTime = 0.0f;
1.46 -float g_fGameStartTime = 0.0f; /* Game game start time, non-universal */
1.47 -double g_fTimerThink = 0.0f; /* Timer's next think time */
1.48 -const double *g_pUniversalTime = &g_fUniversalTime;
1.49 -ConVar *mp_timelimit = NULL;
1.50 -int g_TimeLeftMode = 0;
1.51 -
1.52 -ConVar sm_time_adjustment("sm_time_adjustment", "0", 0, "Adjusts the server time in seconds");
1.53 -
1.54 -inline double GetSimulatedTime()
1.55 -{
1.56 - return g_fUniversalTime;
1.57 -}
1.58 -
1.59 -time_t GetAdjustedTime(time_t *buf)
1.60 -{
1.61 - time_t val = time(NULL) + sm_time_adjustment.GetInt();
1.62 - if (buf)
1.63 - {
1.64 - *buf = val;
1.65 - }
1.66 - return val;
1.67 -}
1.68 -
1.69 -class DefaultMapTimer :
1.70 - public IMapTimer,
1.71 - public SMGlobalClass,
1.72 - public IConVarChangeListener
1.73 -{
1.74 -public:
1.75 - DefaultMapTimer()
1.76 - {
1.77 - m_bInUse = false;
1.78 - }
1.79 -
1.80 - void OnSourceModLevelChange(const char *mapName)
1.81 - {
1.82 - g_fGameStartTime = 0.0f;
1.83 - }
1.84 -
1.85 - int GetMapTimeLimit()
1.86 - {
1.87 - return mp_timelimit->GetInt();
1.88 - }
1.89 -
1.90 - void SetMapTimerStatus(bool enabled)
1.91 - {
1.92 - if (enabled && !m_bInUse)
1.93 - {
1.94 - Enable();
1.95 - }
1.96 - else if (!enabled && m_bInUse)
1.97 - {
1.98 - Disable();
1.99 - }
1.100 - m_bInUse = enabled;
1.101 - }
1.102 -
1.103 - void ExtendMapTimeLimit(int extra_time)
1.104 - {
1.105 - if (extra_time == 0)
1.106 - {
1.107 - mp_timelimit->SetValue(0);
1.108 - return;
1.109 - }
1.110 -
1.111 - extra_time /= 60;
1.112 -
1.113 - mp_timelimit->SetValue(mp_timelimit->GetInt() + extra_time);
1.114 - }
1.115 -
1.116 - void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue)
1.117 - {
1.118 - g_Timers.MapTimeLeftChanged();
1.119 - }
1.120 -
1.121 -private:
1.122 - void Enable()
1.123 - {
1.124 - g_ConVarManager.AddConVarChangeListener("mp_timelimit", this);
1.125 - }
1.126 -
1.127 - void Disable()
1.128 - {
1.129 - g_ConVarManager.RemoveConVarChangeListener("mp_timelimit", this);
1.130 - }
1.131 -
1.132 -private:
1.133 - bool m_bInUse;
1.134 -} s_DefaultMapTimer;
1.135 -
1.136 -/**
1.137 - * If the ticking process has run amok (should be impossible), we
1.138 - * take care of this by "skipping" the in-between time, to prevent
1.139 - * a bazillion times from firing on accident. This has the result
1.140 - * that a drastic jump in time will continue acting normally. Users
1.141 - * may not expect this, but... I think it is the best solution.
1.142 - */
1.143 -inline double CalcNextThink(double last, float interval)
1.144 -{
1.145 - if (g_fUniversalTime - last - interval <= TIMER_MIN_ACCURACY)
1.146 - {
1.147 - return last + interval;
1.148 - }
1.149 - else
1.150 - {
1.151 - return g_fUniversalTime + interval;
1.152 - }
1.153 -}
1.154 -
1.155 -void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags)
1.156 -{
1.157 - m_Listener = pCallbacks;
1.158 - m_Interval = fInterval;
1.159 - m_ToExec = fToExec;
1.160 - m_pData = pData;
1.161 - m_Flags = flags;
1.162 - m_InExec = false;
1.163 - m_KillMe = false;
1.164 -}
1.165 -
1.166 -TimerSystem::TimerSystem()
1.167 -{
1.168 - m_pMapTimer = NULL;
1.169 - m_bHasMapTickedYet = false;
1.170 - m_bHasMapSimulatedYet = false;
1.171 - m_fLastTickedTime = 0.0f;
1.172 -}
1.173 -
1.174 -TimerSystem::~TimerSystem()
1.175 -{
1.176 - CStack<ITimer *>::iterator iter;
1.177 - for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
1.178 - {
1.179 - delete (*iter);
1.180 - }
1.181 - m_FreeTimers.popall();
1.182 -}
1.183 -
1.184 -void TimerSystem::OnSourceModAllInitialized()
1.185 -{
1.186 - g_ShareSys.AddInterface(NULL, this);
1.187 - m_pOnGameFrame = g_Forwards.CreateForward("OnGameFrame", ET_Ignore, 0, NULL);
1.188 - m_pOnMapTimeLeftChanged = g_Forwards.CreateForward("OnMapTimeLeftChanged", ET_Ignore, 0, NULL);
1.189 -}
1.190 -
1.191 -void TimerSystem::OnSourceModGameInitialized()
1.192 -{
1.193 - mp_timelimit = icvar->FindVar("mp_timelimit");
1.194 -
1.195 - if (m_pMapTimer == NULL && mp_timelimit != NULL)
1.196 - {
1.197 - SetMapTimer(&s_DefaultMapTimer);
1.198 - }
1.199 -}
1.200 -
1.201 -void TimerSystem::OnSourceModShutdown()
1.202 -{
1.203 - SetMapTimer(NULL);
1.204 - g_Forwards.ReleaseForward(m_pOnGameFrame);
1.205 - g_Forwards.ReleaseForward(m_pOnMapTimeLeftChanged);
1.206 -}
1.207 -
1.208 -void TimerSystem::OnSourceModLevelEnd()
1.209 -{
1.210 - m_bHasMapTickedYet = false;
1.211 - m_bHasMapSimulatedYet = false;
1.212 -}
1.213 -
1.214 -void TimerSystem::GameFrame(bool simulating)
1.215 -{
1.216 - if (simulating && m_bHasMapTickedYet)
1.217 - {
1.218 - g_fUniversalTime += gpGlobals->curtime - m_fLastTickedTime;
1.219 - if (!m_bHasMapSimulatedYet)
1.220 - {
1.221 - m_bHasMapSimulatedYet = true;
1.222 - MapTimeLeftChanged();
1.223 - }
1.224 - }
1.225 - else
1.226 - {
1.227 - g_fUniversalTime += gpGlobals->interval_per_tick;
1.228 - }
1.229 -
1.230 - m_fLastTickedTime = gpGlobals->curtime;
1.231 - m_bHasMapTickedYet = true;
1.232 -
1.233 - if (g_fUniversalTime >= g_fTimerThink)
1.234 - {
1.235 - RunFrame();
1.236 -
1.237 - g_fTimerThink = CalcNextThink(g_fTimerThink, TIMER_MIN_ACCURACY);
1.238 - }
1.239 -
1.240 - RunFrameHooks(simulating);
1.241 -
1.242 - if (m_pOnGameFrame->GetFunctionCount())
1.243 - {
1.244 - m_pOnGameFrame->Execute(NULL);
1.245 - }
1.246 -}
1.247 -
1.248 -void TimerSystem::RunFrame()
1.249 -{
1.250 - ITimer *pTimer;
1.251 - TimerIter iter;
1.252 -
1.253 - double curtime = GetSimulatedTime();
1.254 - for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
1.255 - {
1.256 - pTimer = (*iter);
1.257 - if (curtime >= pTimer->m_ToExec)
1.258 - {
1.259 - pTimer->m_InExec = true;
1.260 - pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
1.261 - pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
1.262 - iter = m_SingleTimers.erase(iter);
1.263 - m_FreeTimers.push(pTimer);
1.264 - }
1.265 - else
1.266 - {
1.267 - break;
1.268 - }
1.269 - }
1.270 -
1.271 - ResultType res;
1.272 - for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); )
1.273 - {
1.274 - pTimer = (*iter);
1.275 - if (curtime >= pTimer->m_ToExec)
1.276 - {
1.277 - pTimer->m_InExec = true;
1.278 - res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
1.279 - if (pTimer->m_KillMe || (res == Pl_Stop))
1.280 - {
1.281 - pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
1.282 - iter = m_LoopTimers.erase(iter);
1.283 - m_FreeTimers.push(pTimer);
1.284 - continue;
1.285 - }
1.286 - pTimer->m_InExec = false;
1.287 - pTimer->m_ToExec = CalcNextThink(pTimer->m_ToExec, pTimer->m_Interval);
1.288 - }
1.289 - iter++;
1.290 - }
1.291 -}
1.292 -
1.293 -ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags)
1.294 -{
1.295 - ITimer *pTimer;
1.296 - TimerIter iter;
1.297 - float to_exec = GetSimulatedTime() + fInterval;
1.298 -
1.299 - if (m_FreeTimers.empty())
1.300 - {
1.301 - pTimer = new ITimer;
1.302 - } else {
1.303 - pTimer = m_FreeTimers.front();
1.304 - m_FreeTimers.pop();
1.305 - }
1.306 -
1.307 - pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags);
1.308 -
1.309 - if (flags & TIMER_FLAG_REPEAT)
1.310 - {
1.311 - m_LoopTimers.push_back(pTimer);
1.312 - goto return_timer;
1.313 - }
1.314 -
1.315 - if (m_SingleTimers.size() >= 1)
1.316 - {
1.317 - iter = --m_SingleTimers.end();
1.318 - if ((*iter)->m_ToExec <= to_exec)
1.319 - {
1.320 - goto normal_insert_end;
1.321 - }
1.322 - }
1.323 -
1.324 - for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
1.325 - {
1.326 - if ((*iter)->m_ToExec >= to_exec)
1.327 - {
1.328 - m_SingleTimers.insert(iter, pTimer);
1.329 - goto return_timer;
1.330 - }
1.331 - }
1.332 -
1.333 -normal_insert_end:
1.334 - m_SingleTimers.push_back(pTimer);
1.335 -
1.336 -return_timer:
1.337 - return pTimer;
1.338 -}
1.339 -
1.340 -void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec)
1.341 -{
1.342 - ResultType res;
1.343 -
1.344 - if (pTimer->m_InExec)
1.345 - {
1.346 - return;
1.347 - }
1.348 -
1.349 - pTimer->m_InExec = true;
1.350 - res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
1.351 -
1.352 - if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT))
1.353 - {
1.354 - pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
1.355 - m_SingleTimers.remove(pTimer);
1.356 - m_FreeTimers.push(pTimer);
1.357 - }
1.358 - else
1.359 - {
1.360 - if ((res != Pl_Stop) && !pTimer->m_KillMe)
1.361 - {
1.362 - if (delayExec)
1.363 - {
1.364 - pTimer->m_ToExec = GetSimulatedTime() + pTimer->m_Interval;
1.365 - }
1.366 - pTimer->m_InExec = false;
1.367 - return;
1.368 - }
1.369 - pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
1.370 - m_LoopTimers.remove(pTimer);
1.371 - m_FreeTimers.push(pTimer);
1.372 - }
1.373 -}
1.374 -
1.375 -void TimerSystem::KillTimer(ITimer *pTimer)
1.376 -{
1.377 - if (pTimer->m_KillMe)
1.378 - {
1.379 - return;
1.380 - }
1.381 -
1.382 - if (pTimer->m_InExec)
1.383 - {
1.384 - pTimer->m_KillMe = true;
1.385 - return;
1.386 - }
1.387 -
1.388 - pTimer->m_InExec = true; /* The timer it's not really executed but this check needs to be done */
1.389 - pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
1.390 -
1.391 - if (pTimer->m_Flags & TIMER_FLAG_REPEAT)
1.392 - {
1.393 - m_LoopTimers.remove(pTimer);
1.394 - } else {
1.395 - m_SingleTimers.remove(pTimer);
1.396 - }
1.397 -
1.398 - m_FreeTimers.push(pTimer);
1.399 -}
1.400 -
1.401 -CStack<ITimer *> s_tokill;
1.402 -void TimerSystem::RemoveMapChangeTimers()
1.403 -{
1.404 - ITimer *pTimer;
1.405 - TimerIter iter;
1.406 -
1.407 - for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
1.408 - {
1.409 - pTimer = (*iter);
1.410 - if (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE)
1.411 - {
1.412 - s_tokill.push(pTimer);
1.413 - }
1.414 - }
1.415 -
1.416 - for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++)
1.417 - {
1.418 - pTimer = (*iter);
1.419 - if (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE)
1.420 - {
1.421 - s_tokill.push(pTimer);
1.422 - }
1.423 - }
1.424 -
1.425 - while (!s_tokill.empty())
1.426 - {
1.427 - KillTimer(s_tokill.front());
1.428 - s_tokill.pop();
1.429 - }
1.430 -}
1.431 -
1.432 -IMapTimer *TimerSystem::SetMapTimer(IMapTimer *pTimer)
1.433 -{
1.434 - IMapTimer *old = m_pMapTimer;
1.435 -
1.436 - m_pMapTimer = pTimer;
1.437 -
1.438 - if (m_pMapTimer)
1.439 - {
1.440 - m_pMapTimer->SetMapTimerStatus(true);
1.441 - }
1.442 -
1.443 - if (old)
1.444 - {
1.445 - old->SetMapTimerStatus(false);
1.446 - }
1.447 -
1.448 - return old;
1.449 -}
1.450 -
1.451 -IMapTimer *TimerSystem::GetMapTimer()
1.452 -{
1.453 - return m_pMapTimer;
1.454 -}
1.455 -
1.456 -void TimerSystem::MapTimeLeftChanged()
1.457 -{
1.458 - m_pOnMapTimeLeftChanged->Execute(NULL);
1.459 -}
1.460 -
1.461 -void TimerSystem::NotifyOfGameStart(float offset)
1.462 -{
1.463 - g_fGameStartTime = gpGlobals->curtime + offset;
1.464 -}
1.465 -
1.466 -float TimerSystem::GetTickedTime()
1.467 -{
1.468 - return g_fUniversalTime;
1.469 -}
1.470 -
1.471 -bool TimerSystem::GetMapTimeLeft(float *time_left)
1.472 -{
1.473 - if (!m_pMapTimer)
1.474 - {
1.475 - return false;
1.476 - }
1.477 -
1.478 - int time_limit;
1.479 - if (!m_bHasMapSimulatedYet || (time_limit = m_pMapTimer->GetMapTimeLimit()) < 1)
1.480 - {
1.481 - *time_left = -1.0f;
1.482 - }
1.483 - else
1.484 - {
1.485 - *time_left = (g_fGameStartTime + time_limit * 60.0f) - gpGlobals->curtime;
1.486 - }
1.487 -
1.488 - return true;
1.489 -}
1.490 -