From 8d29b2c02ecf5b5948cb8469ae2fb8e9cc48c159 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 1 Mar 2007 01:02:47 +0000 Subject: [PATCH] initial import of game compatibility backend --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40553 --- configs/gamedata/core.games.txt | 14 ++ core/CConCmdManager.cpp | 22 +- core/CGameConfigs.cpp | 363 ++++++++++++++++++++++++++++++++ core/CGameConfigs.h | 85 ++++++++ core/CHalfLife2.cpp | 111 ++++++++++ core/CHalfLife2.h | 49 +++++ core/msvc8/sourcemod_mm.vcproj | 18 +- public/IGameConfigs.h | 118 +++++++++++ 8 files changed, 768 insertions(+), 12 deletions(-) create mode 100644 configs/gamedata/core.games.txt create mode 100644 core/CGameConfigs.cpp create mode 100644 core/CGameConfigs.h create mode 100644 core/CHalfLife2.cpp create mode 100644 core/CHalfLife2.h create mode 100644 public/IGameConfigs.h diff --git a/configs/gamedata/core.games.txt b/configs/gamedata/core.games.txt new file mode 100644 index 00000000..910da115 --- /dev/null +++ b/configs/gamedata/core.games.txt @@ -0,0 +1,14 @@ +"Games" +{ + "*" + { + "Offsets" + { + "GetDataDescMap" + { + "windows" "13" + "linux" "14" + } + } + } +} diff --git a/core/CConCmdManager.cpp b/core/CConCmdManager.cpp index 6ce12a22..4e56d4cc 100644 --- a/core/CConCmdManager.cpp +++ b/core/CConCmdManager.cpp @@ -1,15 +1,15 @@ /** -* =============================================================== -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. -* =============================================================== -* -* This file is not open source and may not be copied without explicit -* written permission of AlliedModders LLC. This file may not be redistributed -* in whole or significant part. -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php -* -* Version: $Id$ -*/ + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ #include "CConCmdManager.h" #include "sm_srvcmds.h" diff --git a/core/CGameConfigs.cpp b/core/CGameConfigs.cpp new file mode 100644 index 00000000..fa390991 --- /dev/null +++ b/core/CGameConfigs.cpp @@ -0,0 +1,363 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include +#include +#include "CGameConfigs.h" +#include "CTextParsers.h" +#include "sm_stringutil.h" +#include "sourcemod.h" +#include "sourcemm_api.h" +#include "CHalfLife2.h" +#include "CLogger.h" +#include "ShareSys.h" + +CGameConfigManager g_GameConfigs; +IGameConfig *g_pGameConf = NULL; +char g_mod[255]; + +#define PSTATE_NONE 0 +#define PSTATE_GAMES 1 +#define PSTATE_GAMEDEFS 2 +#define PSTATE_GAMEDEFS_OFFSETS 3 +#define PSTATE_GAMEDEFS_OFFSETS_OFFSET 4 + +#if defined PLATFORM_WINDOWS +#define PLATFORM_NAME "windows" +#elif defined PLATFORM_LINUX +#define PLATFORM_NAME "linux" +#endif + +CGameConfig::CGameConfig(const char *file) +{ + m_pFile = sm_strdup(file); + m_pOffsets = sm_trie_create(); + m_pProps = sm_trie_create(); +} + +CGameConfig::~CGameConfig() +{ + sm_trie_destroy(m_pOffsets); + sm_trie_destroy(m_pProps); + delete [] m_pFile; +} + +SMCParseResult CGameConfig::ReadSMC_NewSection(const char *name, bool opt_quotes) +{ + if (m_IgnoreLevel) + { + m_IgnoreLevel++; + return SMCParse_Continue; + } + switch (m_ParseState) + { + case PSTATE_NONE: + { + if (strcmp(name, "Games") == 0) + { + m_ParseState = PSTATE_GAMES; + } else { + m_IgnoreLevel++; + } + break; + } + case PSTATE_GAMES: + { + if ((strcmp(name, "*") == 0) + || (strcmp(name, g_mod) == 0)) + { + m_ParseState = PSTATE_GAMEDEFS; + strncopy(m_mod, name, sizeof(m_mod)); + } else { + m_IgnoreLevel++; + } + break; + } + case PSTATE_GAMEDEFS: + { + if (strcmp(name, "Offsets") == 0) + { + m_ParseState = PSTATE_GAMEDEFS_OFFSETS; + } else { + m_IgnoreLevel++; + } + break; + } + case PSTATE_GAMEDEFS_OFFSETS: + { + m_prop[0] = '\0'; + m_class[0] = '\0'; + strncopy(m_offset, name, sizeof(m_offset)); + m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET; + break; + } + /* No sub-sections allowed: + case PSTATE_GAMEDEFS_OFFSETS_OFFSET: + */ + default: + { + /* If we don't know what we got, start ignoring */ + m_IgnoreLevel++; + break; + } + } + + return SMCParse_Continue; +} + +SMCParseResult CGameConfig::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes) +{ + if (m_IgnoreLevel) + { + return SMCParse_Continue; + } + + if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET) + { + if (strcmp(key, "class") == 0) + { + strncopy(m_class, value, sizeof(m_class)); + } else if (strcmp(key, "prop") == 0) { + strncopy(m_prop, value, sizeof(m_prop)); + } else if (strcmp(key, PLATFORM_NAME) == 0) { + int val = atoi(value); + sm_trie_insert(m_pOffsets, m_offset, (void *)val); + } + } + + return SMCParse_Continue; +} + +SMCParseResult CGameConfig::ReadSMC_LeavingSection() +{ + if (m_IgnoreLevel) + { + m_IgnoreLevel--; + return SMCParse_Continue; + } + + switch (m_ParseState) + { + case PSTATE_GAMES: + { + m_ParseState = PSTATE_NONE; + break; + } + case PSTATE_GAMEDEFS: + { + m_ParseState = PSTATE_GAMES; + break; + } + case PSTATE_GAMEDEFS_OFFSETS: + { + m_ParseState = PSTATE_GAMEDEFS; + break; + } + case PSTATE_GAMEDEFS_OFFSETS_OFFSET: + { + /* Parse the offset... */ + if (m_class[0] != '\0' + && m_prop[0] != '\0') + { + SendProp *pProp = g_HL2.FindInSendTable(m_class, m_prop); + if (pProp) + { + int val = pProp->GetOffset(); + sm_trie_insert(m_pOffsets, m_offset, (void *)val); + sm_trie_insert(m_pProps, m_offset, pProp); + } else { + /* Check if it's a non-default game and no offsets exist */ + if ((strcmp(m_mod, "*") != 0) + && (!sm_trie_retrieve(m_pOffsets, m_offset, NULL))) + { + g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")", + m_class, + m_prop, + m_pFile, + m_mod); + } + } + } + m_ParseState = PSTATE_GAMEDEFS_OFFSETS; + break; + } + } + + return SMCParse_Continue; +} + +bool CGameConfig::Reparse(char *error, size_t maxlength) +{ + SMCParseError err; + + char path[PLATFORM_MAX_PATH]; + g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile); + + /* Initialize states */ + m_IgnoreLevel = 0; + m_ParseState = PSTATE_NONE; + sm_trie_clear(m_pOffsets); + + if ((err=g_TextParser.ParseFile_SMC(path, this, NULL, NULL)) + != SMCParse_Okay) + { + if (error && (err != SMCParse_Custom)) + { + const char *str = g_TextParser.GetSMCErrorString(err); + snprintf(error, maxlength, "%s", err); + } + return false; + } + + return true; +} + +bool CGameConfig::GetOffset(const char *key, int *value) +{ + void *obj; + + if (!sm_trie_retrieve(m_pOffsets, key, &obj)) + { + return false; + } + + *value = (int)obj; + + return true; +} + +const char *CGameConfig::GetKeyValue(const char *key) +{ + /* :TODO: implement */ + return false; +} + +SendProp *CGameConfig::GetSendProp(const char *key) +{ + SendProp *pProp; + + if (!sm_trie_retrieve(m_pProps, key, (void **)&pProp)) + { + return NULL; + } + + return pProp; +} + +void CGameConfig::IncRefCount() +{ + m_RefCount++; +} + +unsigned int CGameConfig::DecRefCount() +{ + m_RefCount--; + return m_RefCount; +} + +CGameConfigManager::CGameConfigManager() +{ + m_pLookup = sm_trie_create(); +} + +CGameConfigManager::~CGameConfigManager() +{ + sm_trie_destroy(m_pLookup); +} + +void CGameConfigManager::OnSourceModStartup(bool late) +{ + LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0); + + char mod[255]; + engine->GetGameDir(mod, sizeof(mod)); + + g_mod[0] = '\0'; + size_t len = strlen(mod); + for (size_t i=len-1; i>=0 && iReparse(error, sizeof(error))) + { + /* :TODO: log */ + } + + g_ShareSys.AddInterface(NULL, this); +} + +void CGameConfigManager::OnSourceModAllShutdown() +{ + CloseGameConfigFile(g_pGameConf); +} + +bool CGameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength) +{ + CGameConfig *pConfig; + + if (sm_trie_retrieve(m_pLookup, file, (void **)&pConfig)) + { + pConfig->IncRefCount(); + *_pConfig = pConfig; + return true; + } + + pConfig = new CGameConfig(file); + + /* :HACKHACK: Don't parse the main config file */ + bool retval = true; + if (_pConfig != &g_pGameConf) + { + retval = pConfig->Reparse(error, maxlength); + } + + m_cfgs.push_back(pConfig); + sm_trie_insert(m_pLookup, file, pConfig); + + pConfig->IncRefCount(); + + *_pConfig = pConfig; + + return retval; +} + +void CGameConfigManager::CloseGameConfigFile(IGameConfig *cfg) +{ + CGameConfig *pConfig = (CGameConfig *)cfg; + + if (pConfig->DecRefCount() == 0) + { + delete pConfig; + } +} diff --git a/core/CGameConfigs.h b/core/CGameConfigs.h new file mode 100644 index 00000000..dcfb994f --- /dev/null +++ b/core/CGameConfigs.h @@ -0,0 +1,85 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_ +#define _INCLUDE_SOURCEMOD_CGAMECONFIGS_H_ + +#include +#include +#include +#include "sm_trie.h" +#include "sm_globals.h" + +using namespace SourceMod; +using namespace SourceHook; + +class SendProp; + +class CGameConfig : + public ITextListener_SMC, + public IGameConfig +{ +public: + CGameConfig(const char *file); + ~CGameConfig(); +public: + bool Reparse(char *error, size_t maxlength); +public: //ITextListener_SMC + SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes); + SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes); + SMCParseResult ReadSMC_LeavingSection(); +public: //IGameConfig + const char *GetKeyValue(const char *key); + bool GetOffset(const char *key, int *value); + SendProp *GetSendProp(const char *key); +public: + void IncRefCount(); + unsigned int DecRefCount(); +private: + char *m_pFile; + Trie *m_pOffsets; + Trie *m_pProps; + unsigned int m_RefCount; + /* Parse states */ + int m_ParseState; + unsigned int m_IgnoreLevel; + char m_class[64]; + char m_prop[64]; + char m_offset[64]; + char m_mod[255]; +}; + +class CGameConfigManager : + public IGameConfigManager, + public SMGlobalClass +{ +public: + CGameConfigManager(); + ~CGameConfigManager(); +public: //IGameConfigManager + bool LoadGameConfigFile(const char *file, IGameConfig **pConfig, char *error, size_t maxlength); + void CloseGameConfigFile(IGameConfig *cfg); +public: //SMGlobalClass + void OnSourceModStartup(bool late); + void OnSourceModAllInitialized(); + void OnSourceModAllShutdown(); +private: + List m_cfgs; + Trie *m_pLookup; +}; + +extern CGameConfigManager g_GameConfigs; +extern IGameConfig *g_pGameConf; + +#endif //_INCLUDE_SOURCEMOD_CGAMECONFIGS_H_ diff --git a/core/CHalfLife2.cpp b/core/CHalfLife2.cpp new file mode 100644 index 00000000..2a724b3f --- /dev/null +++ b/core/CHalfLife2.cpp @@ -0,0 +1,111 @@ +/** + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#include "CHalfLife2.h" +#include "sourcemm_api.h" + +CHalfLife2 g_HL2; + +CHalfLife2::CHalfLife2() +{ + m_pClasses = sm_trie_create(); +} + +CHalfLife2::~CHalfLife2() +{ + sm_trie_destroy(m_pClasses); + + List::iterator iter; + DataTableInfo *pInfo; + for (iter=m_Tables.begin(); iter!=m_Tables.end(); iter++) + { + pInfo = (*iter); + sm_trie_destroy(pInfo->lookup); + delete pInfo; + } + + m_Tables.clear(); +} + +#if 0 +void CHalfLife2::OnSourceModStartup(bool late) +{ +} + +void CHalfLife2::OnSourceModAllShutdown() +{ +} +#endif + +SendProp *UTIL_FindInSendTable(SendTable *pTable, const char *name) +{ + const char *pname; + int props = pTable->GetNumProps(); + SendProp *prop; + + for (int i=0; iGetProp(i); + pname = prop->GetName(); + if (pname && strcmp(name, pname) == 0) + { + return prop; + } + if (prop->GetDataTable()) + { + if ((prop=UTIL_FindInSendTable(prop->GetDataTable(), name)) != NULL) + { + return prop; + } + } + } + + return NULL; +} + +SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset) +{ + DataTableInfo *pInfo = NULL; + + if (!sm_trie_retrieve(m_pClasses, classname, (void **)&pInfo)) + { + ServerClass *sc = gamedll->GetAllServerClasses(); + while (sc) + { + if (strcmp(classname, sc->GetName()) == 0) + { + pInfo = new DataTableInfo; + pInfo->lookup = sm_trie_create(); + pInfo->sc = sc; + sm_trie_insert(m_pClasses, classname, pInfo); + break; + } + sc = sc->m_pNext; + } + if (!pInfo) + { + return NULL; + } + } + + SendProp *pProp; + if (!sm_trie_retrieve(pInfo->lookup, offset, (void **)&pProp)) + { + if ((pProp = UTIL_FindInSendTable(pInfo->sc->m_pTable, offset)) != NULL) + { + sm_trie_insert(pInfo->lookup, offset, pProp); + } + } + + return pProp; +} diff --git a/core/CHalfLife2.h b/core/CHalfLife2.h new file mode 100644 index 00000000..f540d670 --- /dev/null +++ b/core/CHalfLife2.h @@ -0,0 +1,49 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is not open source and may not be copied without explicit + * written permission of AlliedModders LLC. This file may not be redistributed + * in whole or significant part. + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_CHALFLIFE2_H_ +#define _INCLUDE_SOURCEMOD_CHALFLIFE2_H_ + +#include +#include "sm_trie.h" +#include "sm_globals.h" +#include "dt_send.h" +#include "server_class.h" + +using namespace SourceHook; + +struct DataTableInfo +{ + ServerClass *sc; + Trie *lookup; +}; + +class CHalfLife2 +{ +public: + CHalfLife2(); + ~CHalfLife2(); +public: + /*void OnSourceModStartup(bool late); + void OnSourceModAllShutdown();*/ +public: + SendProp *FindInSendTable(const char *classname, const char *offset); +public: + Trie *m_pClasses; + List m_Tables; +}; + +extern CHalfLife2 g_HL2; + +#endif //_INCLUDE_SOURCEMOD_CHALFLIFE2_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 345569a5..11888d8b 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -199,6 +199,14 @@ RelativePath="..\CDbgReporter.cpp" > + + + + @@ -274,7 +282,11 @@ > + + + + diff --git a/public/IGameConfigs.h b/public/IGameConfigs.h new file mode 100644 index 00000000..8823c53f --- /dev/null +++ b/public/IGameConfigs.h @@ -0,0 +1,118 @@ +/** +* vim: set ts=4 : +* =============================================================== +* SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. +* All rights reserved. +* =============================================================== +* +* This file is part of the SourceMod/SourcePawn SDK. This file may only be +* used or modified under the Terms and Conditions of its License Agreement, +* which is found in public/licenses/LICENSE.txt. As of this notice, derivative +* works must be licensed under the GNU General Public License (version 2 or +* greater). A copy of the GPL is included under public/licenses/GPL.txt. +* +* To view the latest information, see: http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_GAMECONFIG_SYSTEM_H_ +#define _INCLUDE_SOURCEMOD_GAMECONFIG_SYSTEM_H_ + +#include + +/** + * @file IGameConfig.h + * @brief Abstracts game private data configuration. + */ + +#define SMINTERFACE_GAMECONFIG_NAME "IGameConfigManager" +#define SMINTERFACE_GAMECONFIG_VERSION 1 + +class SendProp; + +namespace SourceMod +{ + /** + * @brief Details the property types. + */ + enum PropType + { + PropType_Unknown = 0, /**< Property type is not known */ + PropType_Send = 1, /**< Property type is a networkable property */ + PropType_Data = 2, /**< Property type is a data/save property */ + }; + + enum PropError + { + PropError_Okay = 0, /**< No error */ + PropError_NotSet, /**< Property is not set in the config file */ + PropError_NotFound, /**< Property was not found in the game */ + }; + + #define INVALID_PROPERTY_VALUE -1 /**< Property value is not valid */ + + /** + * @brief Describes a game private data config file + */ + class IGameConfig + { + public: + /** + * @brief Returns an offset value. + * + * @param key Key to retrieve from the offset section. + * @param value Pointer to store the offset value in. + * @return True if found, false otherwise. + */ + virtual bool GetOffset(const char *key, int *value) =0; + + /** + * @brief Returns information about a property. + * + * @param key Key to retrieve from the property section. + * @param value Pointer to store the offset value. Will be -1 on failure. + * @return A PropError error code. + */ + virtual SendProp *GetSendProp(const char *key) =0; + }; + + /** + * @brief Manages game config files + */ + class IGameConfigManager : public SMInterface + { + public: + const char *GetInterfaceName() + { + return SMINTERFACE_GAMECONFIG_NAME; + } + unsigned int GetInterfaceVersion() + { + return SMINTERFACE_GAMECONFIG_VERSION; + } + public: + /** + * @brief Loads or finds an already loaded game config file. + * + * @param file File to load. The path must be relative to the 'gamedata' + * folder under the config folder, and the extension should be ommitted. + * @param pConfig Pointer to store the game config pointer. Pointer will be valid even on failure. + * @param error Optional error message buffer. + * @param maxlength Maximum length of the error buffer. + * @return True on success, false if the file failed. + */ + virtual bool LoadGameConfigFile(const char *file, IGameConfig **pConfig, char *error, size_t maxlength) =0; + + /** + * @brief Closes an IGameConfig pointer. Since a file can be loaded more than once, + * the file will not actually be removed from memory until it is closed once for each + * call to LoadGameConfigfile(). + * + * @param cfg Pointer to the IGameConfig to close. + */ + virtual void CloseGameConfigFile(IGameConfig *cfg) =0; + }; +} + +#endif //_INCLUDE_SOURCEMOD_GAMECONFIG_SYSTEM_H_