ds@1952: /**
ds@1952: * vim: set ts=4 :
ds@1952: * =============================================================================
ds@1952: * SourceMod
ds@1952: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
ds@1952: * =============================================================================
ds@1952: *
ds@1952: * This program is free software; you can redistribute it and/or modify it under
ds@1952: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952: * Free Software Foundation.
ds@1952: *
ds@1952: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1952: * details.
ds@1952: *
ds@1952: * You should have received a copy of the GNU General Public License along with
ds@1952: * this program. If not, see .
ds@1952: *
ds@1952: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1952: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1952: * this exception to all derivative works. AlliedModders LLC defines further
ds@1952: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952: * or .
ds@1952: *
ds@1952: * Version: $Id$
ds@1952: */
ds@1952:
ds@1952: #include
ds@1952: #include
ds@1952: #include "GameConfigs.h"
ds@1952: #include "sm_stringutil.h"
ds@1952: #include "sourcemod.h"
ds@1952: #include "sourcemm_api.h"
ds@1952: #include "HalfLife2.h"
ds@1952: #include "Logger.h"
ds@1952: #include "ShareSys.h"
ds@1952: #include "MemoryUtils.h"
ds@1952: #include "LibrarySys.h"
ds@1952: #include "HandleSys.h"
ds@1952: #include "sm_crc32.h"
ds@1952:
ds@1952: #if defined PLATFORM_LINUX
ds@1952: #include
ds@1952: #endif
ds@1952:
ds@1952: GameConfigManager g_GameConfigs;
ds@1952: IGameConfig *g_pGameConf = NULL;
ds@1952: char g_Game[256];
ds@1952: char g_GameDesc[256] = {'!', '\0'};
ds@1952: char g_GameName[256] = {'$', '\0'};
ds@1952:
ds@1952: #define PSTATE_NONE 0
ds@1952: #define PSTATE_GAMES 1
ds@1952: #define PSTATE_GAMEDEFS 2
ds@1952: #define PSTATE_GAMEDEFS_OFFSETS 3
ds@1952: #define PSTATE_GAMEDEFS_OFFSETS_OFFSET 4
ds@1952: #define PSTATE_GAMEDEFS_KEYS 5
ds@1952: #define PSTATE_GAMEDEFS_SUPPORTED 6
ds@1952: #define PSTATE_GAMEDEFS_SIGNATURES 7
ds@1952: #define PSTATE_GAMEDEFS_SIGNATURES_SIG 8
ds@1952: #define PSTATE_GAMEDEFS_CRC 9
ds@1952: #define PSTATE_GAMEDEFS_CRC_BINARY 10
ds@1952:
ds@1952: #if defined PLATFORM_WINDOWS
ds@1952: #define PLATFORM_NAME "windows"
ds@1952: #define PLATFORM_SERVER_BINARY "server.dll"
ds@1952: #elif defined PLATFORM_LINUX
ds@1952: #define PLATFORM_NAME "linux"
ds@1952: #define PLATFORM_SERVER_BINARY "server_i486.so"
ds@1952: #endif
ds@1952:
ds@1952: struct TempSigInfo
ds@1952: {
ds@1952: void Reset()
ds@1952: {
ds@1952: library[0] = '\0';
ds@1952: sig[0] = '\0';
ds@1952: }
ds@1952: char sig[512];
ds@1952: char library[64];
ds@1952: } s_TempSig;
ds@1952: unsigned int s_ServerBinCRC;
ds@1952: bool s_ServerBinCRC_Ok = false;
ds@1952:
ds@1952: CGameConfig::CGameConfig(const char *file)
ds@1952: {
ds@1952: m_pFile = sm_strdup(file);
ds@1952: m_pOffsets = sm_trie_create();
ds@1952: m_pProps = sm_trie_create();
ds@1952: m_pKeys = sm_trie_create();
ds@1952: m_pSigs = sm_trie_create();
ds@1952: m_pStrings = new BaseStringTable(512);
ds@1952: m_RefCount = 0;
ds@1952: }
ds@1952:
ds@1952: CGameConfig::~CGameConfig()
ds@1952: {
ds@1952: sm_trie_destroy(m_pOffsets);
ds@1952: sm_trie_destroy(m_pProps);
ds@1952: sm_trie_destroy(m_pKeys);
ds@1952: sm_trie_destroy(m_pSigs);
ds@1952: delete [] m_pFile;
ds@1952: delete m_pStrings;
ds@1952: }
ds@1952:
ds@1952: SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
ds@1952: {
ds@1952: if (m_IgnoreLevel)
ds@1952: {
ds@1952: m_IgnoreLevel++;
ds@1952: return SMCResult_Continue;
ds@1952: }
ds@1952:
ds@1952: switch (m_ParseState)
ds@1952: {
ds@1952: case PSTATE_NONE:
ds@1952: {
ds@1952: if (strcmp(name, "Games") == 0)
ds@1952: {
ds@1952: m_ParseState = PSTATE_GAMES;
ds@1952: } else {
ds@1952: m_IgnoreLevel++;
ds@1952: }
ds@1952: break;
ds@1952: }
ds@1952: case PSTATE_GAMES:
ds@1952: {
ds@1952: if ((strcmp(name, "*") == 0)
ds@1952: || (strcmp(name, "#default") == 0)
ds@1952: || (strcasecmp(name, g_Game) == 0)
ds@1952: || (strcasecmp(name, g_GameDesc) == 0)
ds@1952: || (strcasecmp(name, g_GameName) == 0))
ds@1952: {
ds@1952: bShouldBeReadingDefault = true;
ds@1952: m_ParseState = PSTATE_GAMEDEFS;
ds@1952: strncopy(m_Game, name, sizeof(m_Game));
ds@1952: } else {
ds@1952: m_IgnoreLevel++;
ds@1952: }
ds@1952: break;
ds@1952: }
ds@1952: case PSTATE_GAMEDEFS:
ds@1952: {
ds@1952: if (strcmp(name, "Offsets") == 0)
ds@1952: {
ds@1952: m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
ds@1952: }
ds@1952: else if (strcmp(name, "Keys") == 0)
ds@1952: {
ds@1952: m_ParseState = PSTATE_GAMEDEFS_KEYS;
ds@1952: }
ds@1952: else if ((strcmp(name, "#supported") == 0)
ds@1952: && (strcmp(m_Game, "#default") == 0))
ds@1952: {
ds@1952: m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
ds@1952: /* Ignore this section unless we get a game. */
ds@1952: bShouldBeReadingDefault = false;
ds@1952: }
ds@1952: else if (strcmp(name, "Signatures") == 0)
ds@1952: {
ds@1952: m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
ds@1952: }
ds@1952: else if (strcmp(name, "CRC") == 0)
ds@1952: {
ds@1952: m_ParseState = PSTATE_GAMEDEFS_CRC;
ds@1952: bShouldBeReadingDefault = false;
ds@1952: }
ds@1952: else
ds@1952: {
ds@1952: m_IgnoreLevel++;
ds@1952: }
ds@1952: break;
ds@1952: }
ds@1952: case PSTATE_GAMEDEFS_OFFSETS:
ds@1952: {
ds@1952: m_Prop[0] = '\0';
ds@1952: m_Class[0] = '\0';
ds@1952: strncopy(m_offset, name, sizeof(m_offset));
ds@1952: m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
ds@1952: break;
ds@1952: }
ds@1952: case PSTATE_GAMEDEFS_SIGNATURES:
ds@1952: {
ds@1952: strncopy(m_offset, name, sizeof(m_offset));
ds@1952: s_TempSig.Reset();
ds@1952: m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
ds@1952: break;
ds@1952: }
ds@1952: case PSTATE_GAMEDEFS_CRC:
ds@1952: {
ds@1952: char error[255];
ds@1952: error[0] = '\0';
ds@1952: if (strcmp(name, "server") != 0)
ds@1952: {
ds@1952: UTIL_Format(error, sizeof(error), "Unrecognized library \"%s\"", name);
ds@1952: }
ds@1952: else if (!s_ServerBinCRC_Ok)
ds@1952: {
ds@1952: FILE *fp;
ds@1952: char path[PLATFORM_MAX_PATH];
ds@1952:
ds@1952: g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "bin/" PLATFORM_SERVER_BINARY);
ds@1952: if ((fp = fopen(path, "rb")) == NULL)
ds@1952: {
ds@1952: UTIL_Format(error, sizeof(error), "Could not open binary: %s", path);
ds@1952: } else {
ds@1952: size_t size;
ds@1952: void *buffer;
ds@1952:
ds@1952: fseek(fp, 0, SEEK_END);
ds@1952: size = ftell(fp);
ds@1952: fseek(fp, 0, SEEK_SET);
ds@1952:
ds@1952: buffer = malloc(size);
ds@1952: fread(buffer, size, 1, fp);
ds@1952: s_ServerBinCRC = UTIL_CRC32(buffer, size);
ds@1952: free(buffer);
ds@1952: s_ServerBinCRC_Ok = true;
ds@1952: }
ds@1952: }
ds@1952: if (error[0] != '\0')
ds@1952: {
ds@1952: m_IgnoreLevel = 1;
ds@1952: g_Logger.LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_pFile);
ds@1952: g_Logger.LogError("[SM] %s", error);
ds@1952: } else {
ds@1952: m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY;
ds@1952: }
ds@1952: break;
ds@1952: }
ds@1952: /* No sub-sections allowed:
ds@1952: case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
ds@1952: case PSTATE_GAMEDEFS_KEYS:
ds@1952: case PSTATE_GAMEDEFS_SUPPORTED:
ds@1952: case PSTATE_GAMEDEFS_SIGNATURES_SIG:
ds@1952: case PSTATE_GAMEDEFS_CRC_BINARY:
ds@1952: */
ds@1952: default:
ds@1952: {
ds@1952: /* If we don't know what we got, start ignoring */
ds@1952: m_IgnoreLevel++;
ds@1952: break;
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: return SMCResult_Continue;
ds@1952: }
ds@1952:
ds@1952: SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
ds@1952: {
ds@1952: if (m_IgnoreLevel)
ds@1952: {
ds@1952: return SMCResult_Continue;
ds@1952: }
ds@1952:
ds@1952: if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET)
ds@1952: {
ds@1952: if (strcmp(key, "class") == 0)
ds@1952: {
ds@1952: strncopy(m_Class, value, sizeof(m_Class));
ds@1952: } else if (strcmp(key, "prop") == 0) {
ds@1952: strncopy(m_Prop, value, sizeof(m_Prop));
ds@1952: } else if (strcmp(key, PLATFORM_NAME) == 0) {
ds@1952: int val = atoi(value);
ds@1952: sm_trie_replace(m_pOffsets, m_offset, (void *)val);
ds@1952: }
ds@1952: } else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
ds@1952: int id = m_pStrings->AddString(value);
ds@1952: sm_trie_replace(m_pKeys, key, (void *)id);
ds@1952: } else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
ds@1952: if (strcmp(key, "game") == 0
ds@1952: && (strcasecmp(value, g_Game) == 0
ds@1952: || strcasecmp(value, g_GameDesc) == 0
ds@1952: || strcasecmp(value, g_GameName) == 0)
ds@1952: )
ds@1952: {
ds@1952: bShouldBeReadingDefault = true;
ds@1952: }
ds@1952: } else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
ds@1952: if (strcmp(key, PLATFORM_NAME) == 0)
ds@1952: {
ds@1952: strncopy(s_TempSig.sig, value, sizeof(s_TempSig.sig));
ds@1952: } else if (strcmp(key, "library") == 0) {
ds@1952: strncopy(s_TempSig.library, value, sizeof(s_TempSig.library));
ds@1952: }
ds@1952: } else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
ds@1952: if (strcmp(key, PLATFORM_NAME) == 0
ds@1952: && s_ServerBinCRC_Ok
ds@1952: && !bShouldBeReadingDefault)
ds@1952: {
ds@1952: unsigned int crc = 0;
ds@1952: sscanf(value, "%08X", &crc);
ds@1952: if (s_ServerBinCRC == crc)
ds@1952: {
ds@1952: bShouldBeReadingDefault = true;
ds@1952: }
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: return SMCResult_Continue;
ds@1952: }
ds@1952:
ds@1952: SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
ds@1952: {
ds@1952: if (m_IgnoreLevel)
ds@1952: {
ds@1952: m_IgnoreLevel--;
ds@1952: return SMCResult_Continue;
ds@1952: }
ds@1952:
ds@1952: switch (m_ParseState)
ds@1952: {
ds@1952: case PSTATE_GAMES:
ds@1952: {
ds@1952: m_ParseState = PSTATE_NONE;
ds@1952: break;
ds@1952: }
ds@1952: case PSTATE_GAMEDEFS:
ds@1952: {
ds@1952: m_ParseState = PSTATE_GAMES;
ds@1952: break;
ds@1952: }
ds@1952: case PSTATE_GAMEDEFS_KEYS:
ds@1952: case PSTATE_GAMEDEFS_OFFSETS:
ds@1952: {
ds@1952: m_ParseState = PSTATE_GAMEDEFS;
ds@1952: break;
ds@1952: }
ds@1952: case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
ds@1952: {
ds@1952: /* Parse the offset... */
ds@1952: if (m_Class[0] != '\0'
ds@1952: && m_Prop[0] != '\0')
ds@1952: {
ds@1952: SendProp *pProp = g_HL2.FindInSendTable(m_Class, m_Prop);
ds@1952: if (pProp)
ds@1952: {
ds@1952: int val = pProp->GetOffset();
ds@1952: sm_trie_replace(m_pOffsets, m_offset, (void *)val);
ds@1952: sm_trie_replace(m_pProps, m_offset, pProp);
ds@1952: } else {
ds@1952: /* Check if it's a non-default game and no offsets exist */
ds@1952: if (((strcmp(m_Game, "*") != 0) && strcmp(m_Game, "#default") != 0)
ds@1952: && (!sm_trie_retrieve(m_pOffsets, m_offset, NULL)))
ds@1952: {
ds@1952: g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")",
ds@1952: m_Class,
ds@1952: m_Prop,
ds@1952: m_pFile,
ds@1952: m_Game);
ds@1952: }
ds@1952: }
ds@1952: }
ds@1952: m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
ds@1952: break;
ds@1952: }
ds@1952: case PSTATE_GAMEDEFS_CRC:
ds@1952: case PSTATE_GAMEDEFS_SUPPORTED:
ds@1952: {
ds@1952: if (!bShouldBeReadingDefault)
ds@1952: {
ds@1952: /* If we shouldn't read the rest of this section, set the ignore level. */
ds@1952: m_IgnoreLevel = 1;
ds@1952: m_ParseState = PSTATE_GAMES;
ds@1952: } else {
ds@1952: m_ParseState = PSTATE_GAMEDEFS;
ds@1952: }
ds@1952: break;
ds@1952: }
ds@1952: case PSTATE_GAMEDEFS_CRC_BINARY:
ds@1952: {
ds@1952: m_ParseState = PSTATE_GAMEDEFS_CRC;
ds@1952: break;
ds@1952: }
ds@1952: case PSTATE_GAMEDEFS_SIGNATURES:
ds@1952: {
ds@1952: m_ParseState = PSTATE_GAMEDEFS;
ds@1952: break;
ds@1952: }
ds@1952: case PSTATE_GAMEDEFS_SIGNATURES_SIG:
ds@1952: {
ds@1952: if (s_TempSig.library[0] == '\0')
ds@1952: {
ds@1952: /* assume server */
ds@1952: strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library));
ds@1952: }
ds@1952: void *addrInBase = NULL;
ds@1952: if (strcmp(s_TempSig.library, "server") == 0)
ds@1952: {
ds@1952: addrInBase = (void *)g_SMAPI->GetServerFactory(false);
ds@1952: } else if (strcmp(s_TempSig.library, "engine") == 0) {
ds@1952: addrInBase = (void *)g_SMAPI->GetEngineFactory(false);
ds@1952: }
ds@1952: void *final_addr = NULL;
ds@1952: if (addrInBase == NULL)
ds@1952: {
ds@1952: g_Logger.LogError("[SM] Unrecognized library \"%s\" (gameconf \"%s\")",
ds@1952: s_TempSig.library,
ds@1952: m_pFile);
ds@1952: } else {
ds@1952: #if defined PLATFORM_LINUX
ds@1952: if (s_TempSig.sig[0] == '@')
ds@1952: {
ds@1952: Dl_info info;
ds@1952: /* GNU only: returns 0 on error, inconsistent! >:[ */
ds@1952: if (dladdr(addrInBase, &info) != 0)
ds@1952: {
ds@1952: void *handle = dlopen(info.dli_fname, RTLD_NOW);
ds@1952: if (handle)
ds@1952: {
ds@1952: final_addr = dlsym(handle, &s_TempSig.sig[1]);
ds@1952: dlclose(handle);
ds@1952: } else {
ds@1952: g_Logger.LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")",
ds@1952: s_TempSig.library,
ds@1952: m_pFile);
ds@1952: }
ds@1952: } else {
ds@1952: g_Logger.LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")",
ds@1952: s_TempSig.library,
ds@1952: m_pFile);
ds@1952: }
ds@1952: }
ds@1952: if (final_addr)
ds@1952: {
ds@1952: goto skip_find;
ds@1952: }
ds@1952: #endif
ds@1952: /* First, preprocess the signature */
ds@1952: char real_sig[511];
ds@1952: size_t real_bytes;
ds@1952: size_t length;
ds@1952:
ds@1952: real_bytes = 0;
ds@1952: length = strlen(s_TempSig.sig);
ds@1952:
ds@1952: for (size_t i=0; i= sizeof(real_sig))
ds@1952: {
ds@1952: break;
ds@1952: }
ds@1952: real_sig[real_bytes++] = s_TempSig.sig[i];
ds@1952: if (s_TempSig.sig[i] == '\\'
ds@1952: && s_TempSig.sig[i+1] == 'x')
ds@1952: {
ds@1952: if (i + 3 >= length)
ds@1952: {
ds@1952: continue;
ds@1952: }
ds@1952: /* Get the hex part */
ds@1952: char s_byte[3];
ds@1952: int r_byte;
ds@1952: s_byte[0] = s_TempSig.sig[i+2];
ds@1952: s_byte[1] = s_TempSig.sig[i+3];
ds@1952: s_byte[2] = '\0';
ds@1952: /* Read it as an integer */
ds@1952: sscanf(s_byte, "%x", &r_byte);
ds@1952: /* Save the value */
ds@1952: real_sig[real_bytes-1] = r_byte;
ds@1952: /* Adjust index */
ds@1952: i += 3;
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: if (real_bytes >= 1)
ds@1952: {
ds@1952: final_addr = g_MemUtils.FindPattern(addrInBase, real_sig, real_bytes);
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: #if defined PLATFORM_LINUX
ds@1952: skip_find:
ds@1952: #endif
ds@1952: sm_trie_replace(m_pSigs, m_offset, final_addr);
ds@1952: m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
ds@1952:
ds@1952: break;
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: return SMCResult_Continue;
ds@1952: }
ds@1952:
ds@1952: bool CGameConfig::Reparse(char *error, size_t maxlength)
ds@1952: {
ds@1952: SMCError err;
ds@1952: SMCStates state = {0, 0};
ds@1952:
ds@1952: char path[PLATFORM_MAX_PATH];
ds@1952: g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s.txt", m_pFile);
ds@1952: /* Backwards compatibility */
ds@1952: if (!g_LibSys.PathExists(path))
ds@1952: {
ds@1952: g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile);
ds@1952: }
ds@1952:
ds@1952: /* Initialize parse states */
ds@1952: m_IgnoreLevel = 0;
ds@1952: bShouldBeReadingDefault = true;
ds@1952: m_ParseState = PSTATE_NONE;
ds@1952: /* Reset cached data */
ds@1952: m_pStrings->Reset();
ds@1952: sm_trie_clear(m_pOffsets);
ds@1952: sm_trie_clear(m_pProps);
ds@1952: sm_trie_clear(m_pKeys);
ds@1952:
ds@1952: if ((err=textparsers->ParseSMCFile(path, this, &state, error, maxlength))
ds@1952: != SMCError_Okay)
ds@1952: {
ds@1952: const char *msg;
ds@1952:
ds@1952: msg = textparsers->GetSMCErrorString(err);
ds@1952:
ds@1952: g_Logger.LogError("[SM] Error parsing gameconfig file \"%s\":", path);
ds@1952: g_Logger.LogError("[SM] Error %d on line %d, col %d: %s",
ds@1952: err,
ds@1952: state.line,
ds@1952: state.col,
ds@1952: msg ? msg : "Unknown error");
ds@1952: return false;
ds@1952: }
ds@1952:
ds@1952: return true;
ds@1952: }
ds@1952:
ds@1952: bool CGameConfig::GetOffset(const char *key, int *value)
ds@1952: {
ds@1952: void *obj;
ds@1952:
ds@1952: if (!sm_trie_retrieve(m_pOffsets, key, &obj))
ds@1952: {
ds@1952: return false;
ds@1952: }
ds@1952:
ds@1952: *value = (int)obj;
ds@1952:
ds@1952: return true;
ds@1952: }
ds@1952:
ds@1952: const char *CGameConfig::GetKeyValue(const char *key)
ds@1952: {
ds@1952: void *obj;
ds@1952: if (!sm_trie_retrieve(m_pKeys, key, &obj))
ds@1952: {
ds@1952: return NULL;
ds@1952: }
ds@1952: return m_pStrings->GetString((int)obj);
ds@1952: }
ds@1952:
ds@1952: SendProp *CGameConfig::GetSendProp(const char *key)
ds@1952: {
ds@1952: SendProp *pProp;
ds@1952:
ds@1952: if (!sm_trie_retrieve(m_pProps, key, (void **)&pProp))
ds@1952: {
ds@1952: return NULL;
ds@1952: }
ds@1952:
ds@1952: return pProp;
ds@1952: }
ds@1952:
ds@1952: bool CGameConfig::GetMemSig(const char *key, void **addr)
ds@1952: {
ds@1952: return sm_trie_retrieve(m_pSigs, key, addr);
ds@1952: }
ds@1952:
ds@1952: void CGameConfig::IncRefCount()
ds@1952: {
ds@1952: m_RefCount++;
ds@1952: }
ds@1952:
ds@1952: unsigned int CGameConfig::DecRefCount()
ds@1952: {
ds@1952: m_RefCount--;
ds@1952: return m_RefCount;
ds@1952: }
ds@1952:
ds@1952: GameConfigManager::GameConfigManager()
ds@1952: {
ds@1952: m_pLookup = sm_trie_create();
ds@1952: }
ds@1952:
ds@1952: GameConfigManager::~GameConfigManager()
ds@1952: {
ds@1952: sm_trie_destroy(m_pLookup);
ds@1952: }
ds@1952:
ds@1952: void GameConfigManager::OnSourceModStartup(bool late)
ds@1952: {
ds@1952: LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
ds@1952:
ds@1952: strncopy(g_Game, g_SourceMod.GetGameFolderName(), sizeof(g_Game));
ds@1952: strncopy(g_GameDesc + 1, SERVER_CALL(GetGameDescription)(), sizeof(g_GameDesc) - 1);
ds@1952:
ds@1952: KeyValues *pGameInfo = new KeyValues("GameInfo");
ds@1952: if (g_HL2.KVLoadFromFile(pGameInfo, basefilesystem, "gameinfo.txt"))
ds@1952: {
ds@1952: const char *str;
ds@1952: if ((str = pGameInfo->GetString("game", NULL)) != NULL)
ds@1952: {
ds@1952: strncopy(g_GameName + 1, str, sizeof(g_GameName) - 1);
ds@1952: }
ds@1952: }
ds@1952: pGameInfo->deleteThis();
ds@1952: }
ds@1952:
ds@1952: void GameConfigManager::OnSourceModAllInitialized()
ds@1952: {
ds@1952: /* NOW initialize the game file */
ds@1952: CGameConfig *pGameConf = (CGameConfig *)g_pGameConf;
ds@1952:
ds@1952: char error[255];
ds@1952: if (!pGameConf->Reparse(error, sizeof(error)))
ds@1952: {
ds@1952: /* :TODO: log */
ds@1952: }
ds@1952:
ds@1952: g_ShareSys.AddInterface(NULL, this);
ds@1952: }
ds@1952:
ds@1952: void GameConfigManager::OnSourceModAllShutdown()
ds@1952: {
ds@1952: CloseGameConfigFile(g_pGameConf);
ds@1952: }
ds@1952:
ds@1952: bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength)
ds@1952: {
ds@1952: CGameConfig *pConfig;
ds@1952:
ds@1952: if (sm_trie_retrieve(m_pLookup, file, (void **)&pConfig))
ds@1952: {
ds@1952: pConfig->IncRefCount();
ds@1952: *_pConfig = pConfig;
ds@1952: return true;
ds@1952: }
ds@1952:
ds@1952: pConfig = new CGameConfig(file);
ds@1952:
ds@1952: /* :HACKHACK: Don't parse the main config file */
ds@1952: bool retval = true;
ds@1952: if (_pConfig != &g_pGameConf)
ds@1952: {
ds@1952: retval = pConfig->Reparse(error, maxlength);
ds@1952: }
ds@1952:
ds@1952: m_cfgs.push_back(pConfig);
ds@1952: sm_trie_insert(m_pLookup, file, pConfig);
ds@1952:
ds@1952: pConfig->IncRefCount();
ds@1952:
ds@1952: *_pConfig = pConfig;
ds@1952:
ds@1952: return retval;
ds@1952: }
ds@1952:
ds@1952: void GameConfigManager::CloseGameConfigFile(IGameConfig *cfg)
ds@1952: {
ds@1952: CGameConfig *pConfig = (CGameConfig *)cfg;
ds@1952:
ds@1952: if (pConfig->DecRefCount() == 0)
ds@1952: {
ds@1952: sm_trie_delete(m_pLookup, pConfig->m_pFile);
ds@1952: delete pConfig;
ds@1952: }
ds@1952: }
ds@1952:
ds@1952: extern HandleType_t g_GameConfigsType;
ds@1952:
ds@1952: IGameConfig *GameConfigManager::ReadHandle(Handle_t hndl, IdentityToken_t *ident, HandleError *err)
ds@1952: {
ds@1952: HandleSecurity sec(ident, g_pCoreIdent);
ds@1952: IGameConfig *conf = NULL;
ds@1952: HandleError _err = g_HandleSys.ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&conf);
ds@1952:
ds@1952: if (err)
ds@1952: {
ds@1952: *err = _err;
ds@1952: }
ds@1952:
ds@1952: return conf;
ds@1952: }