diff --git a/core/GameConfigs.cpp b/core/GameConfigs.cpp index 78d9b894..4f5e0048 100644 --- a/core/GameConfigs.cpp +++ b/core/GameConfigs.cpp @@ -65,6 +65,7 @@ char g_GameName[256] = {'$', '\0'}; #define PSTATE_GAMEDEFS_SIGNATURES_SIG 8 #define PSTATE_GAMEDEFS_CRC 9 #define PSTATE_GAMEDEFS_CRC_BINARY 10 +#define PSTATE_GAMEDEFS_CUSTOM 11 #if defined PLATFORM_WINDOWS #define PLATFORM_NAME "windows" @@ -96,6 +97,9 @@ CGameConfig::CGameConfig(const char *file) m_pSigs = sm_trie_create(); m_pStrings = new BaseStringTable(512); m_RefCount = 0; + + m_CustomLevel = 0; + m_CustomHandler = NULL; } CGameConfig::~CGameConfig() @@ -172,6 +176,17 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n } else { + ITextListener_SMC **pListen = g_GameConfigs.m_customHandlers.retrieve(name); + + if (pListen != NULL) + { + m_CustomLevel = 0; + m_ParseState = PSTATE_GAMEDEFS_CUSTOM; + m_CustomHandler = *pListen; + m_CustomHandler->ReadSMC_ParseStart(); + break; + } + m_IgnoreLevel++; } break; @@ -233,6 +248,12 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n } break; } + case PSTATE_GAMEDEFS_CUSTOM: + { + m_CustomLevel++; + return m_CustomHandler->ReadSMC_NewSection(states, name); + break; + } /* No sub-sections allowed: case PSTATE_GAMEDEFS_OFFSETS_OFFSET: case PSTATE_GAMEDEFS_KEYS: @@ -300,6 +321,8 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key bShouldBeReadingDefault = true; } } + } else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) { + return m_CustomHandler->ReadSMC_KeyValue(states, key, value); } return SMCResult_Continue; @@ -313,6 +336,13 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states) return SMCResult_Continue; } + if (m_CustomLevel) + { + m_CustomLevel--; + m_CustomHandler->ReadSMC_LeavingSection(states); + return SMCResult_Continue; + } + switch (m_ParseState) { case PSTATE_GAMES: @@ -325,6 +355,12 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states) m_ParseState = PSTATE_GAMES; break; } + case PSTATE_GAMEDEFS_CUSTOM: + { + m_ParseState = PSTATE_GAMEDEFS; + m_CustomHandler->ReadSMC_ParseEnd(false, false); + break; + } case PSTATE_GAMEDEFS_KEYS: case PSTATE_GAMEDEFS_OFFSETS: { @@ -523,6 +559,15 @@ bool CGameConfig::Reparse(char *error, size_t maxlength) state.line, state.col, msg ? msg : "Unknown error"); + + if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) + { + //error occurred while parsing a custom section + m_CustomHandler->ReadSMC_ParseEnd(true, true); + m_CustomHandler = NULL; + m_CustomLevel = 0; + } + return false; } @@ -692,3 +737,27 @@ IGameConfig *GameConfigManager::ReadHandle(Handle_t hndl, IdentityToken_t *ident return conf; } + +void GameConfigManager::AddUserConfigHook( const char *sectionname, ITextListener_SMC *listener ) +{ + m_customHandlers.insert(sectionname, listener); +} + +void GameConfigManager::RemoveUserConfigHook( const char *sectionname, ITextListener_SMC *listener ) +{ + ITextListener_SMC **pListener = m_customHandlers.retrieve(sectionname); + + if (pListener == NULL) + { + return; + } + + if (*pListener != listener) + { + return; + } + + m_customHandlers.remove(sectionname); + + return; +} diff --git a/core/GameConfigs.h b/core/GameConfigs.h index 4b447084..c3a27953 100644 --- a/core/GameConfigs.h +++ b/core/GameConfigs.h @@ -38,6 +38,7 @@ #include "sm_trie.h" #include "sm_globals.h" #include "sm_memtable.h" +#include "sm_trie_tpl.h" using namespace SourceMod; using namespace SourceHook; @@ -82,6 +83,10 @@ private: char m_offset[64]; char m_Game[256]; bool bShouldBeReadingDefault; + + /* Custom Sections */ + unsigned int m_CustomLevel; + ITextListener_SMC *m_CustomHandler; }; class GameConfigManager : @@ -97,6 +102,8 @@ public: //IGameConfigManager IGameConfig *ReadHandle(Handle_t hndl, IdentityToken_t *ident, HandleError *err); + void AddUserConfigHook(const char *sectionname, ITextListener_SMC *listener); + void RemoveUserConfigHook(const char *sectionname, ITextListener_SMC *listener); public: //SMGlobalClass void OnSourceModStartup(bool late); void OnSourceModAllInitialized(); @@ -104,6 +111,8 @@ public: //SMGlobalClass private: List m_cfgs; Trie *m_pLookup; +public: + KTrie m_customHandlers; }; extern GameConfigManager g_GameConfigs; diff --git a/public/IGameConfigs.h b/public/IGameConfigs.h index 6e555cc3..cb52ae2a 100644 --- a/public/IGameConfigs.h +++ b/public/IGameConfigs.h @@ -34,6 +34,7 @@ #include #include +#include /** * @file IGameConfigs.h @@ -41,7 +42,7 @@ */ #define SMINTERFACE_GAMECONFIG_NAME "IGameConfigManager" -#define SMINTERFACE_GAMECONFIG_VERSION 3 +#define SMINTERFACE_GAMECONFIG_VERSION 4 class SendProp; @@ -141,7 +142,25 @@ namespace SourceMod */ virtual IGameConfig *ReadHandle(Handle_t hndl, IdentityToken_t *ident, - HandleError *err) =0; + HandleError *err) =0; + + /** + * @brief Adds a custom gamedata section hook. + * + * @param sectionname Section name to hook. + * @param listener Listener callback. + * @noreturn + */ + virtual void AddUserConfigHook(const char *sectionname, ITextListener_SMC *listener) =0; + + /** + * @brief Removes a custom gamedata section hook. + * + * @param sectionname Section name to unhook. + * @param listener Listener callback. + * @noreturn + */ + virtual void RemoveUserConfigHook(const char *sectionname, ITextListener_SMC *listener) =0; }; }