diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index 05c00274..f5cc8bcd 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -39,9 +39,10 @@ SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallback, SH_NOATTRIB, false, ConVar * TimerSystem g_Timers; float g_fUniversalTime = 0.0f; -float g_fMapStartTime = 0.0f; +float g_fGameStartTime = 0.0f; /* Game game start time, non-universal */ const float *g_pUniversalTime = &g_fUniversalTime; ConVar *mp_timelimit = NULL; +int g_TimeLeftMode = 0; ConVar sm_time_adjustment("sm_time_adjustment", "0", 0, "Adjusts the server time in seconds"); @@ -70,6 +71,11 @@ public: m_bInUse = false; } + void OnSourceModLevelChange(const char *mapName) + { + g_fGameStartTime = 0.0f; + } + int GetMapTimeLimit() { return mp_timelimit->GetInt(); @@ -88,18 +94,6 @@ public: 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; @@ -176,6 +170,7 @@ void TimerSystem::OnSourceModAllInitialized() { g_ShareSys.AddInterface(NULL, this); m_pOnGameFrame = g_Forwards.CreateForward("OnGameFrame", ET_Ignore, 0, NULL); + m_pOnMapTimeLeftChanged = g_Forwards.CreateForward("OnMapTimeLeftChanged", ET_Ignore, 0, NULL); } void TimerSystem::OnSourceModGameInitialized() @@ -192,6 +187,7 @@ void TimerSystem::OnSourceModShutdown() { SetMapTimer(NULL); g_Forwards.ReleaseForward(m_pOnGameFrame); + g_Forwards.ReleaseForward(m_pOnMapTimeLeftChanged); } void TimerSystem::OnSourceModLevelChange(const char *mapName) @@ -216,11 +212,7 @@ void TimerSystem::GameFrame(bool simulating) } m_fLastTickedTime = gpGlobals->curtime; - if (!m_bHasMapTickedYet) - { - g_fMapStartTime = g_fUniversalTime; - m_bHasMapTickedYet = true; - } + m_bHasMapTickedYet = true; if (g_fUniversalTime - m_LastExecTime >= 0.1) { @@ -443,10 +435,28 @@ IMapTimer *TimerSystem::GetMapTimer() void TimerSystem::MapTimeLeftChanged() { + m_pOnMapTimeLeftChanged->Execute(NULL); +} +void TimerSystem::NotifyOfGameStart(float offset) +{ + g_fGameStartTime = gpGlobals->curtime + offset; } float TimerSystem::GetTickedTime() { return g_fUniversalTime; } + +bool TimerSystem::GetMapTimeLeft(float *time_left) +{ + int time_limit; + if (!m_pMapTimer || (time_limit = m_pMapTimer->GetMapTimeLimit()) < 1) + { + return false; + } + + *time_left = (g_fGameStartTime + time_limit * 60.0f) - gpGlobals->curtime; + + return true; +} diff --git a/core/TimerSys.h b/core/TimerSys.h index 84a3ede8..bc80c17e 100644 --- a/core/TimerSys.h +++ b/core/TimerSys.h @@ -77,6 +77,8 @@ public: //ITimerSystem void MapTimeLeftChanged(); IMapTimer *SetMapTimer(IMapTimer *pTimer); float GetTickedTime(); + void NotifyOfGameStart(float offset /* = 0.0f */); + bool GetMapTimeLeft(float *pTime); public: void RunFrame(); void MapChange(bool real_mapchange); @@ -96,12 +98,14 @@ private: */ IForward *m_pOnGameFrame; + IForward *m_pOnMapTimeLeftChanged; }; time_t GetAdjustedTime(time_t *buf = NULL); extern const float *g_pUniversalTime; extern TimerSystem g_Timers; +extern int g_TimeLeftMode; #endif //_INCLUDE_SOURCEMOD_CTIMERSYS_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 17102642..68db9142 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -298,6 +298,24 @@ + + + + + + LocalToPhysAddr(params[1], &addr); - int time_left; - if (!pMapTimer->GetMapTimeLeft(&time_left)) + float time_left; + int int_time; + if (!g_Timers.GetMapTimeLeft(&time_left)) { - time_left = -1; + int_time = -1; + } + else + { + int_time = (int)time_left; } - *addr = time_left; + *addr = int_time; return true; } @@ -312,6 +310,11 @@ static cell_t smn_ExtendMapTimeLimit(IPluginContext *pContext, const cell_t *par return 1; } +static cell_t smn_IsServerTicking(IPluginContext *pContext, const cell_t *params) +{ + return (gpGlobals->frametime > 0.0f) ? 1 : 0; +} + REGISTER_NATIVES(timernatives) { {"CreateTimer", smn_CreateTimer}, @@ -321,5 +324,6 @@ REGISTER_NATIVES(timernatives) {"GetMapTimeLeft", smn_GetMapTimeLeft}, {"GetMapTimeLimit", smn_GetMapTimeLimit}, {"ExtendMapTimeLimit", smn_ExtendMapTimeLimit}, + {"IsServerTicking", smn_IsServerTicking}, {NULL, NULL} }; diff --git a/extensions/cstrike/extension.cpp b/extensions/cstrike/extension.cpp index e2787094..3c24e0e5 100644 --- a/extensions/cstrike/extension.cpp +++ b/extensions/cstrike/extension.cpp @@ -31,15 +31,20 @@ #include "extension.h" #include "RegNatives.h" +#include "timeleft.h" /** * @file extension.cpp * @brief Implement extension code here. */ +SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); + CStrike g_CStrike; /**< Global singleton for extension's main interface */ IBinTools *g_pBinTools = NULL; IGameConfig *g_pGameConf = NULL; +IGameEventManager2 *gameevents = NULL; +bool hooked_everything = false; SMEXT_LINK(&g_CStrike); @@ -49,8 +54,13 @@ bool CStrike::SDK_OnLoad(char *error, size_t maxlength, bool late) { sharesys->AddDependency(myself, "bintools.ext", true, true); - if (!gameconfs->LoadGameConfigFile("sm-cstrike.games", &g_pGameConf, error, maxlength)) + char conf_error[255]; + if (!gameconfs->LoadGameConfigFile("sm-cstrike.games", &g_pGameConf, conf_error, sizeof(conf_error))) { + if (error) + { + snprintf(error, maxlength, "Could not read sm-cstrike.games.txt: %s", conf_error); + } return false; } @@ -59,14 +69,33 @@ bool CStrike::SDK_OnLoad(char *error, size_t maxlength, bool late) return true; } +bool CStrike::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + GET_V_IFACE_CURRENT(engineFactory, gameevents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2); + GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + + return true; +} + void CStrike::SDK_OnUnload() { + if (hooked_everything) + { + gameevents->RemoveListener(&g_TimeLeftEvents); + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, &g_TimeLeftEvents, &TimeLeftEvents::LevelInit, true); + hooked_everything = false; + } g_RegNatives.UnregisterAll(); gameconfs->CloseGameConfigFile(g_pGameConf); } void CStrike::SDK_OnAllLoaded() { + gameevents->AddListener(&g_TimeLeftEvents, "round_start", true); + gameevents->AddListener(&g_TimeLeftEvents, "round_end", true); + SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, &g_TimeLeftEvents, &TimeLeftEvents::LevelInit, true); + hooked_everything = true; + SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools); } diff --git a/extensions/cstrike/extension.h b/extensions/cstrike/extension.h index 0f2b87f1..916bb2d2 100644 --- a/extensions/cstrike/extension.h +++ b/extensions/cstrike/extension.h @@ -94,7 +94,7 @@ public: * @param late Whether or not Metamod considers this a late load. * @return True to succeed, false to fail. */ - //virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); + virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late); /** * @brief Called when Metamod is detaching, after the extension version is called. diff --git a/extensions/cstrike/msvc8/cstrike.vcproj b/extensions/cstrike/msvc8/cstrike.vcproj index 6394bcf6..70ddd817 100644 --- a/extensions/cstrike/msvc8/cstrike.vcproj +++ b/extensions/cstrike/msvc8/cstrike.vcproj @@ -1,7 +1,7 @@ + + + + + + . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id: svn_version.h 1336 2007-08-15 06:19:30Z damagedsoul $ + */ + +/** + * Autogenerated by build scripts + */ + +#ifndef _INCLUDE_SDKTOOLS_VERSION_H_ +#define _INCLUDE_SDKTOOLS_VERSION_H_ + +#define SVN_FULL_VERSION "1.0.0.1336" +#define SVN_FILE_VERSION 1,0,0,1336 + +#endif //_INCLUDE_SDKTOOLS_VERSION_H_ diff --git a/extensions/cstrike/svn_version.tpl b/extensions/cstrike/svn_version.tpl new file mode 100644 index 00000000..ad458193 --- /dev/null +++ b/extensions/cstrike/svn_version.tpl @@ -0,0 +1,42 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod SDKTools Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +/** + * Autogenerated by build scripts + */ + +#ifndef _INCLUDE_SDKTOOLS_VERSION_H_ +#define _INCLUDE_SDKTOOLS_VERSION_H_ + +#define SVN_FULL_VERSION "$PMAJOR$.$PMINOR$.$PREVISION$.$LOCAL_BUILD$" +#define SVN_FILE_VERSION $PMAJOR$,$PMINOR$,$PREVISION$,$LOCAL_BUILD$ + +#endif //_INCLUDE_SDKTOOLS_VERSION_H_ diff --git a/extensions/cstrike/timeleft.cpp b/extensions/cstrike/timeleft.cpp new file mode 100644 index 00000000..ce0c82b5 --- /dev/null +++ b/extensions/cstrike/timeleft.cpp @@ -0,0 +1,43 @@ +#include "extension.h" +#include "timeleft.h" + +TimeLeftEvents g_TimeLeftEvents; +bool get_new_timeleft_offset = false; +bool round_end_found = false; + +bool TimeLeftEvents::LevelInit(char const *pMapName, + char const *pMapEntities, + char const *pOldLevel, + char const *pLandmarkName, + bool loadGame, + bool background) +{ + round_end_found = true; + get_new_timeleft_offset = false; + + return true; +} + +void TimeLeftEvents::FireGameEvent(IGameEvent *event) +{ + const char *name = event->GetName(); + + if (strcmp(name, "round_start") == 0) + { + if (get_new_timeleft_offset || !round_end_found) + { + get_new_timeleft_offset = false; + timersys->NotifyOfGameStart(); + timersys->MapTimeLeftChanged(); + } + round_end_found = false; + } + else if (strcmp(name, "round_end") == 0) + { + if (event->GetInt("reason") == 16) + { + get_new_timeleft_offset = true; + } + round_end_found = true; + } +} diff --git a/extensions/cstrike/timeleft.h b/extensions/cstrike/timeleft.h new file mode 100644 index 00000000..7fa7b60c --- /dev/null +++ b/extensions/cstrike/timeleft.h @@ -0,0 +1,17 @@ +#ifndef _INCLUDE_SOURCEMOD_CSTRIKE_EVENTS_H_ +#define _INCLUDE_SOURCEMOD_CSTRIKE_EVENTS_H_ + +#include +#include + +class TimeLeftEvents : public IGameEventListener2 +{ +public: + bool LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background); + virtual void FireGameEvent(IGameEvent *event); +}; + +extern TimeLeftEvents g_TimeLeftEvents; + +#endif //_INCLUDE_SOURCEMOD_CSTRIKE_EVENTS_H_ + diff --git a/extensions/cstrike/version.rc b/extensions/cstrike/version.rc new file mode 100644 index 00000000..37d14dad --- /dev/null +++ b/extensions/cstrike/version.rc @@ -0,0 +1,104 @@ +// Microsoft Visual C++ generated resource script. +// +//#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +#include "svn_version.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION SVN_FILE_VERSION + PRODUCTVERSION SVN_FILE_VERSION + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "SourceMod CS:S Extension" + VALUE "FileDescription", "SourceMod CS:S Extension" + VALUE "FileVersion", SVN_FULL_VERSION + VALUE "InternalName", "SourceMod CS:S Extension" + VALUE "LegalCopyright", "Copyright (c) 2004-2007, AlliedModders LLC" + VALUE "OriginalFilename", "game.cstrike.ext.dll" + VALUE "ProductName", "SourceMod CS:S Extension" + VALUE "ProductVersion", SVN_FULL_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc index 50c64658..3d7e0e4a 100644 --- a/plugins/include/cstrike.inc +++ b/plugins/include/cstrike.inc @@ -39,8 +39,13 @@ #define CS_TEAM_NONE 0 /**< No team yet. */ #define CS_TEAM_SPECTATOR 1 /**< Spectators. */ -#define CS_TEAM_T 2 /**< Terrorists. */ -#define CS_TEAM_CT 3 /**< Counter-Terrorists. */ +#define CS_TEAM_T 2 /**< Terrorists. */ +#define CS_TEAM_CT 3 /**< Counter-Terrorists. */ + +#define CS_SLOT_PRIMARY 0 /**< Primary weapon slot. */ +#define CS_SLOT_SECONDARY 1 /**< Secondary weapon slot. */ +#define CS_SLOT_GRENADE 3 /**< Grenade slot (will only return one grenade). */ +#define CS_SLOT_C4 4 /**< C4 slot. */ /** * Respawns a player. @@ -67,7 +72,7 @@ native CS_SwitchTeam(client, team); public Extension:__ext_cstrike = { name = "CStrike", - file = "game.cstrike.ext", + file = "games/game.cstrike.ext", #if defined AUTOLOAD_EXTENSIONS autoload = 1, #else @@ -78,4 +83,4 @@ public Extension:__ext_cstrike = #else required = 0, #endif -}; \ No newline at end of file +}; diff --git a/plugins/include/timers.inc b/plugins/include/timers.inc index c1758a0c..81ca5fb9 100644 --- a/plugins/include/timers.inc +++ b/plugins/include/timers.inc @@ -160,6 +160,17 @@ native bool:ExtendMapTimeLimit(time); */ forward OnMapTimeLeftChanged(); +/** + * Returns whether or not the server is processing frames or not. + * + * The server does not process frames until at least one client joins the game. + * Once the first player has in, even if that player, leaves, the server's + * timers and entities will work. + * + * @return True if the server is ticking, false otherwise. + */ +native bool:IsServerProcessing(); + /** * Creates a timer associated with a new data pack, and returns the datapack. * @note The datapack is automatically freed when the timer ends. diff --git a/public/ITimerSystem.h b/public/ITimerSystem.h index 28eae204..00fa57bb 100644 --- a/public/ITimerSystem.h +++ b/public/ITimerSystem.h @@ -42,7 +42,7 @@ #include #define SMINTERFACE_TIMERSYS_NAME "ITimerSys" -#define SMINTERFACE_TIMERSYS_VERSION 1 +#define SMINTERFACE_TIMERSYS_VERSION 3 namespace SourceMod { @@ -62,15 +62,6 @@ namespace SourceMod */ 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. * @@ -194,6 +185,23 @@ namespace SourceMod * @return Universal ticked time. */ virtual float GetTickedTime() =0; + + /** + * @brief Notification that the "starting point" in the game has has + * changed. This does not invoke MapTimeLeftChanged() automatically. + * + * @param offset Optional offset to add to the new time. + */ + virtual void NotifyOfGameStart(float offset = 0.0f) =0; + + /** + * @brief Returns the time left in the map. + * + * @param pTime Pointer to store time left, in seconds. + * @return True on success, false if there no time limit + * or if the time limit could not be determined. + */ + virtual bool GetMapTimeLeft(float *pTime) =0; }; }