1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/GameConfigs.cpp Sun Jul 06 04:49:55 2008 +0000
1.3 @@ -0,0 +1,694 @@
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 <string.h>
1.36 +#include <stdlib.h>
1.37 +#include "GameConfigs.h"
1.38 +#include "sm_stringutil.h"
1.39 +#include "sourcemod.h"
1.40 +#include "sourcemm_api.h"
1.41 +#include "HalfLife2.h"
1.42 +#include "Logger.h"
1.43 +#include "ShareSys.h"
1.44 +#include "MemoryUtils.h"
1.45 +#include "LibrarySys.h"
1.46 +#include "HandleSys.h"
1.47 +#include "sm_crc32.h"
1.48 +#include "GameDataFetcher.h"
1.49 +
1.50 +#if defined PLATFORM_LINUX
1.51 +#include <dlfcn.h>
1.52 +#endif
1.53 +
1.54 +GameConfigManager g_GameConfigs;
1.55 +IGameConfig *g_pGameConf = NULL;
1.56 +char g_Game[256];
1.57 +char g_GameDesc[256] = {'!', '\0'};
1.58 +char g_GameName[256] = {'$', '\0'};
1.59 +
1.60 +#define PSTATE_NONE 0
1.61 +#define PSTATE_GAMES 1
1.62 +#define PSTATE_GAMEDEFS 2
1.63 +#define PSTATE_GAMEDEFS_OFFSETS 3
1.64 +#define PSTATE_GAMEDEFS_OFFSETS_OFFSET 4
1.65 +#define PSTATE_GAMEDEFS_KEYS 5
1.66 +#define PSTATE_GAMEDEFS_SUPPORTED 6
1.67 +#define PSTATE_GAMEDEFS_SIGNATURES 7
1.68 +#define PSTATE_GAMEDEFS_SIGNATURES_SIG 8
1.69 +#define PSTATE_GAMEDEFS_CRC 9
1.70 +#define PSTATE_GAMEDEFS_CRC_BINARY 10
1.71 +
1.72 +#if defined PLATFORM_WINDOWS
1.73 +#define PLATFORM_NAME "windows"
1.74 +#define PLATFORM_SERVER_BINARY "server.dll"
1.75 +#elif defined PLATFORM_LINUX
1.76 +#define PLATFORM_NAME "linux"
1.77 +#define PLATFORM_SERVER_BINARY "server_i486.so"
1.78 +#endif
1.79 +
1.80 +struct TempSigInfo
1.81 +{
1.82 + void Reset()
1.83 + {
1.84 + library[0] = '\0';
1.85 + sig[0] = '\0';
1.86 + }
1.87 + char sig[512];
1.88 + char library[64];
1.89 +} s_TempSig;
1.90 +unsigned int s_ServerBinCRC;
1.91 +bool s_ServerBinCRC_Ok = false;
1.92 +
1.93 +CGameConfig::CGameConfig(const char *file)
1.94 +{
1.95 + m_pFile = sm_strdup(file);
1.96 + m_pOffsets = sm_trie_create();
1.97 + m_pProps = sm_trie_create();
1.98 + m_pKeys = sm_trie_create();
1.99 + m_pSigs = sm_trie_create();
1.100 + m_pStrings = new BaseStringTable(512);
1.101 + m_RefCount = 0;
1.102 +}
1.103 +
1.104 +CGameConfig::~CGameConfig()
1.105 +{
1.106 + sm_trie_destroy(m_pOffsets);
1.107 + sm_trie_destroy(m_pProps);
1.108 + sm_trie_destroy(m_pKeys);
1.109 + sm_trie_destroy(m_pSigs);
1.110 + delete [] m_pFile;
1.111 + delete m_pStrings;
1.112 +}
1.113 +
1.114 +SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
1.115 +{
1.116 + if (m_IgnoreLevel)
1.117 + {
1.118 + m_IgnoreLevel++;
1.119 + return SMCResult_Continue;
1.120 + }
1.121 +
1.122 + switch (m_ParseState)
1.123 + {
1.124 + case PSTATE_NONE:
1.125 + {
1.126 + if (strcmp(name, "Games") == 0)
1.127 + {
1.128 + m_ParseState = PSTATE_GAMES;
1.129 + } else {
1.130 + m_IgnoreLevel++;
1.131 + }
1.132 + break;
1.133 + }
1.134 + case PSTATE_GAMES:
1.135 + {
1.136 + if ((strcmp(name, "*") == 0)
1.137 + || (strcmp(name, "#default") == 0)
1.138 + || (strcasecmp(name, g_Game) == 0)
1.139 + || (strcasecmp(name, g_GameDesc) == 0)
1.140 + || (strcasecmp(name, g_GameName) == 0))
1.141 + {
1.142 + bShouldBeReadingDefault = true;
1.143 + m_ParseState = PSTATE_GAMEDEFS;
1.144 + strncopy(m_Game, name, sizeof(m_Game));
1.145 + } else {
1.146 + m_IgnoreLevel++;
1.147 + }
1.148 + break;
1.149 + }
1.150 + case PSTATE_GAMEDEFS:
1.151 + {
1.152 + if (strcmp(name, "Offsets") == 0)
1.153 + {
1.154 + m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
1.155 + }
1.156 + else if (strcmp(name, "Keys") == 0)
1.157 + {
1.158 + m_ParseState = PSTATE_GAMEDEFS_KEYS;
1.159 + }
1.160 + else if ((strcmp(name, "#supported") == 0)
1.161 + && (strcmp(m_Game, "#default") == 0))
1.162 + {
1.163 + m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
1.164 + /* Ignore this section unless we get a game. */
1.165 + bShouldBeReadingDefault = false;
1.166 + }
1.167 + else if (strcmp(name, "Signatures") == 0)
1.168 + {
1.169 + m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
1.170 + }
1.171 + else if (strcmp(name, "CRC") == 0)
1.172 + {
1.173 + m_ParseState = PSTATE_GAMEDEFS_CRC;
1.174 + bShouldBeReadingDefault = false;
1.175 + }
1.176 + else
1.177 + {
1.178 + m_IgnoreLevel++;
1.179 + }
1.180 + break;
1.181 + }
1.182 + case PSTATE_GAMEDEFS_OFFSETS:
1.183 + {
1.184 + m_Prop[0] = '\0';
1.185 + m_Class[0] = '\0';
1.186 + strncopy(m_offset, name, sizeof(m_offset));
1.187 + m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
1.188 + break;
1.189 + }
1.190 + case PSTATE_GAMEDEFS_SIGNATURES:
1.191 + {
1.192 + strncopy(m_offset, name, sizeof(m_offset));
1.193 + s_TempSig.Reset();
1.194 + m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
1.195 + break;
1.196 + }
1.197 + case PSTATE_GAMEDEFS_CRC:
1.198 + {
1.199 + char error[255];
1.200 + error[0] = '\0';
1.201 + if (strcmp(name, "server") != 0)
1.202 + {
1.203 + UTIL_Format(error, sizeof(error), "Unrecognized library \"%s\"", name);
1.204 + }
1.205 + else if (!s_ServerBinCRC_Ok)
1.206 + {
1.207 + FILE *fp;
1.208 + char path[PLATFORM_MAX_PATH];
1.209 +
1.210 + g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "bin/" PLATFORM_SERVER_BINARY);
1.211 + if ((fp = fopen(path, "rb")) == NULL)
1.212 + {
1.213 + UTIL_Format(error, sizeof(error), "Could not open binary: %s", path);
1.214 + } else {
1.215 + size_t size;
1.216 + void *buffer;
1.217 +
1.218 + fseek(fp, 0, SEEK_END);
1.219 + size = ftell(fp);
1.220 + fseek(fp, 0, SEEK_SET);
1.221 +
1.222 + buffer = malloc(size);
1.223 + fread(buffer, size, 1, fp);
1.224 + s_ServerBinCRC = UTIL_CRC32(buffer, size);
1.225 + free(buffer);
1.226 + s_ServerBinCRC_Ok = true;
1.227 + }
1.228 + }
1.229 + if (error[0] != '\0')
1.230 + {
1.231 + m_IgnoreLevel = 1;
1.232 + g_Logger.LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_pFile);
1.233 + g_Logger.LogError("[SM] %s", error);
1.234 + } else {
1.235 + m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY;
1.236 + }
1.237 + break;
1.238 + }
1.239 + /* No sub-sections allowed:
1.240 + case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
1.241 + case PSTATE_GAMEDEFS_KEYS:
1.242 + case PSTATE_GAMEDEFS_SUPPORTED:
1.243 + case PSTATE_GAMEDEFS_SIGNATURES_SIG:
1.244 + case PSTATE_GAMEDEFS_CRC_BINARY:
1.245 + */
1.246 + default:
1.247 + {
1.248 + /* If we don't know what we got, start ignoring */
1.249 + m_IgnoreLevel++;
1.250 + break;
1.251 + }
1.252 + }
1.253 +
1.254 + return SMCResult_Continue;
1.255 +}
1.256 +
1.257 +SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
1.258 +{
1.259 + if (m_IgnoreLevel)
1.260 + {
1.261 + return SMCResult_Continue;
1.262 + }
1.263 +
1.264 + if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET)
1.265 + {
1.266 + if (strcmp(key, "class") == 0)
1.267 + {
1.268 + strncopy(m_Class, value, sizeof(m_Class));
1.269 + } else if (strcmp(key, "prop") == 0) {
1.270 + strncopy(m_Prop, value, sizeof(m_Prop));
1.271 + } else if (strcmp(key, PLATFORM_NAME) == 0) {
1.272 + int val = atoi(value);
1.273 + sm_trie_replace(m_pOffsets, m_offset, (void *)val);
1.274 + }
1.275 + } else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
1.276 + int id = m_pStrings->AddString(value);
1.277 + sm_trie_replace(m_pKeys, key, (void *)id);
1.278 + } else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
1.279 + if (strcmp(key, "game") == 0
1.280 + && (strcasecmp(value, g_Game) == 0
1.281 + || strcasecmp(value, g_GameDesc) == 0
1.282 + || strcasecmp(value, g_GameName) == 0)
1.283 + )
1.284 + {
1.285 + bShouldBeReadingDefault = true;
1.286 + }
1.287 + } else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
1.288 + if (strcmp(key, PLATFORM_NAME) == 0)
1.289 + {
1.290 + strncopy(s_TempSig.sig, value, sizeof(s_TempSig.sig));
1.291 + } else if (strcmp(key, "library") == 0) {
1.292 + strncopy(s_TempSig.library, value, sizeof(s_TempSig.library));
1.293 + }
1.294 + } else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
1.295 + if (strcmp(key, PLATFORM_NAME) == 0
1.296 + && s_ServerBinCRC_Ok
1.297 + && !bShouldBeReadingDefault)
1.298 + {
1.299 + unsigned int crc = 0;
1.300 + sscanf(value, "%08X", &crc);
1.301 + if (s_ServerBinCRC == crc)
1.302 + {
1.303 + bShouldBeReadingDefault = true;
1.304 + }
1.305 + }
1.306 + }
1.307 +
1.308 + return SMCResult_Continue;
1.309 +}
1.310 +
1.311 +SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
1.312 +{
1.313 + if (m_IgnoreLevel)
1.314 + {
1.315 + m_IgnoreLevel--;
1.316 + return SMCResult_Continue;
1.317 + }
1.318 +
1.319 + switch (m_ParseState)
1.320 + {
1.321 + case PSTATE_GAMES:
1.322 + {
1.323 + m_ParseState = PSTATE_NONE;
1.324 + break;
1.325 + }
1.326 + case PSTATE_GAMEDEFS:
1.327 + {
1.328 + m_ParseState = PSTATE_GAMES;
1.329 + break;
1.330 + }
1.331 + case PSTATE_GAMEDEFS_KEYS:
1.332 + case PSTATE_GAMEDEFS_OFFSETS:
1.333 + {
1.334 + m_ParseState = PSTATE_GAMEDEFS;
1.335 + break;
1.336 + }
1.337 + case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
1.338 + {
1.339 + /* Parse the offset... */
1.340 + if (m_Class[0] != '\0'
1.341 + && m_Prop[0] != '\0')
1.342 + {
1.343 + SendProp *pProp = g_HL2.FindInSendTable(m_Class, m_Prop);
1.344 + if (pProp)
1.345 + {
1.346 + int val = pProp->GetOffset();
1.347 + sm_trie_replace(m_pOffsets, m_offset, (void *)val);
1.348 + sm_trie_replace(m_pProps, m_offset, pProp);
1.349 + } else {
1.350 + /* Check if it's a non-default game and no offsets exist */
1.351 + if (((strcmp(m_Game, "*") != 0) && strcmp(m_Game, "#default") != 0)
1.352 + && (!sm_trie_retrieve(m_pOffsets, m_offset, NULL)))
1.353 + {
1.354 + g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")",
1.355 + m_Class,
1.356 + m_Prop,
1.357 + m_pFile,
1.358 + m_Game);
1.359 + }
1.360 + }
1.361 + }
1.362 + m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
1.363 + break;
1.364 + }
1.365 + case PSTATE_GAMEDEFS_CRC:
1.366 + case PSTATE_GAMEDEFS_SUPPORTED:
1.367 + {
1.368 + if (!bShouldBeReadingDefault)
1.369 + {
1.370 + /* If we shouldn't read the rest of this section, set the ignore level. */
1.371 + m_IgnoreLevel = 1;
1.372 + m_ParseState = PSTATE_GAMES;
1.373 + } else {
1.374 + m_ParseState = PSTATE_GAMEDEFS;
1.375 + }
1.376 + break;
1.377 + }
1.378 + case PSTATE_GAMEDEFS_CRC_BINARY:
1.379 + {
1.380 + m_ParseState = PSTATE_GAMEDEFS_CRC;
1.381 + break;
1.382 + }
1.383 + case PSTATE_GAMEDEFS_SIGNATURES:
1.384 + {
1.385 + m_ParseState = PSTATE_GAMEDEFS;
1.386 + break;
1.387 + }
1.388 + case PSTATE_GAMEDEFS_SIGNATURES_SIG:
1.389 + {
1.390 + if (s_TempSig.library[0] == '\0')
1.391 + {
1.392 + /* assume server */
1.393 + strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library));
1.394 + }
1.395 + void *addrInBase = NULL;
1.396 + if (strcmp(s_TempSig.library, "server") == 0)
1.397 + {
1.398 + addrInBase = (void *)g_SMAPI->GetServerFactory(false);
1.399 + } else if (strcmp(s_TempSig.library, "engine") == 0) {
1.400 + addrInBase = (void *)g_SMAPI->GetEngineFactory(false);
1.401 + }
1.402 + void *final_addr = NULL;
1.403 + if (addrInBase == NULL)
1.404 + {
1.405 + g_Logger.LogError("[SM] Unrecognized library \"%s\" (gameconf \"%s\")",
1.406 + s_TempSig.library,
1.407 + m_pFile);
1.408 + } else {
1.409 +#if defined PLATFORM_LINUX
1.410 + if (s_TempSig.sig[0] == '@')
1.411 + {
1.412 + Dl_info info;
1.413 + /* GNU only: returns 0 on error, inconsistent! >:[ */
1.414 + if (dladdr(addrInBase, &info) != 0)
1.415 + {
1.416 + void *handle = dlopen(info.dli_fname, RTLD_NOW);
1.417 + if (handle)
1.418 + {
1.419 + final_addr = dlsym(handle, &s_TempSig.sig[1]);
1.420 + dlclose(handle);
1.421 + } else {
1.422 + g_Logger.LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")",
1.423 + s_TempSig.library,
1.424 + m_pFile);
1.425 + }
1.426 + } else {
1.427 + g_Logger.LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")",
1.428 + s_TempSig.library,
1.429 + m_pFile);
1.430 + }
1.431 + }
1.432 + if (final_addr)
1.433 + {
1.434 + goto skip_find;
1.435 + }
1.436 +#endif
1.437 + /* First, preprocess the signature */
1.438 + char real_sig[511];
1.439 + size_t real_bytes;
1.440 + size_t length;
1.441 +
1.442 + real_bytes = 0;
1.443 + length = strlen(s_TempSig.sig);
1.444 +
1.445 + for (size_t i=0; i<length; i++)
1.446 + {
1.447 + if (real_bytes >= sizeof(real_sig))
1.448 + {
1.449 + break;
1.450 + }
1.451 + real_sig[real_bytes++] = s_TempSig.sig[i];
1.452 + if (s_TempSig.sig[i] == '\\'
1.453 + && s_TempSig.sig[i+1] == 'x')
1.454 + {
1.455 + if (i + 3 >= length)
1.456 + {
1.457 + continue;
1.458 + }
1.459 + /* Get the hex part */
1.460 + char s_byte[3];
1.461 + int r_byte;
1.462 + s_byte[0] = s_TempSig.sig[i+2];
1.463 + s_byte[1] = s_TempSig.sig[i+3];
1.464 + s_byte[2] = '\0';
1.465 + /* Read it as an integer */
1.466 + sscanf(s_byte, "%x", &r_byte);
1.467 + /* Save the value */
1.468 + real_sig[real_bytes-1] = r_byte;
1.469 + /* Adjust index */
1.470 + i += 3;
1.471 + }
1.472 + }
1.473 +
1.474 + if (real_bytes >= 1)
1.475 + {
1.476 + final_addr = g_MemUtils.FindPattern(addrInBase, real_sig, real_bytes);
1.477 + }
1.478 + }
1.479 +
1.480 +#if defined PLATFORM_LINUX
1.481 +skip_find:
1.482 +#endif
1.483 + sm_trie_replace(m_pSigs, m_offset, final_addr);
1.484 + m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
1.485 +
1.486 + break;
1.487 + }
1.488 + }
1.489 +
1.490 + return SMCResult_Continue;
1.491 +}
1.492 +
1.493 +bool CGameConfig::Reparse(char *error, size_t maxlength)
1.494 +{
1.495 + SMCError err;
1.496 + SMCStates state = {0, 0};
1.497 +
1.498 + char path[PLATFORM_MAX_PATH];
1.499 + g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s.txt", m_pFile);
1.500 + /* Backwards compatibility */
1.501 + if (!g_LibSys.PathExists(path))
1.502 + {
1.503 + g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile);
1.504 + }
1.505 +
1.506 + /* Initialize parse states */
1.507 + m_IgnoreLevel = 0;
1.508 + bShouldBeReadingDefault = true;
1.509 + m_ParseState = PSTATE_NONE;
1.510 + /* Reset cached data */
1.511 + m_pStrings->Reset();
1.512 + sm_trie_clear(m_pOffsets);
1.513 + sm_trie_clear(m_pProps);
1.514 + sm_trie_clear(m_pKeys);
1.515 +
1.516 + if ((err=textparsers->ParseSMCFile(path, this, &state, error, maxlength))
1.517 + != SMCError_Okay)
1.518 + {
1.519 + const char *msg;
1.520 +
1.521 + msg = textparsers->GetSMCErrorString(err);
1.522 +
1.523 + g_Logger.LogError("[SM] Error parsing gameconfig file \"%s\":", path);
1.524 + g_Logger.LogError("[SM] Error %d on line %d, col %d: %s",
1.525 + err,
1.526 + state.line,
1.527 + state.col,
1.528 + msg ? msg : "Unknown error");
1.529 + return false;
1.530 + }
1.531 +
1.532 + return true;
1.533 +}
1.534 +
1.535 +bool CGameConfig::GetOffset(const char *key, int *value)
1.536 +{
1.537 + void *obj;
1.538 +
1.539 + if (!sm_trie_retrieve(m_pOffsets, key, &obj))
1.540 + {
1.541 + return false;
1.542 + }
1.543 +
1.544 + *value = (int)obj;
1.545 +
1.546 + return true;
1.547 +}
1.548 +
1.549 +const char *CGameConfig::GetKeyValue(const char *key)
1.550 +{
1.551 + void *obj;
1.552 + if (!sm_trie_retrieve(m_pKeys, key, &obj))
1.553 + {
1.554 + return NULL;
1.555 + }
1.556 + return m_pStrings->GetString((int)obj);
1.557 +}
1.558 +
1.559 +SendProp *CGameConfig::GetSendProp(const char *key)
1.560 +{
1.561 + SendProp *pProp;
1.562 +
1.563 + if (!sm_trie_retrieve(m_pProps, key, (void **)&pProp))
1.564 + {
1.565 + return NULL;
1.566 + }
1.567 +
1.568 + return pProp;
1.569 +}
1.570 +
1.571 +bool CGameConfig::GetMemSig(const char *key, void **addr)
1.572 +{
1.573 + return sm_trie_retrieve(m_pSigs, key, addr);
1.574 +}
1.575 +
1.576 +void CGameConfig::IncRefCount()
1.577 +{
1.578 + m_RefCount++;
1.579 +}
1.580 +
1.581 +unsigned int CGameConfig::DecRefCount()
1.582 +{
1.583 + m_RefCount--;
1.584 + return m_RefCount;
1.585 +}
1.586 +
1.587 +GameConfigManager::GameConfigManager()
1.588 +{
1.589 + m_pLookup = sm_trie_create();
1.590 +}
1.591 +
1.592 +GameConfigManager::~GameConfigManager()
1.593 +{
1.594 + sm_trie_destroy(m_pLookup);
1.595 +}
1.596 +
1.597 +void GameConfigManager::OnSourceModStartup(bool late)
1.598 +{
1.599 + LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
1.600 +
1.601 + strncopy(g_Game, g_SourceMod.GetGameFolderName(), sizeof(g_Game));
1.602 + strncopy(g_GameDesc + 1, SERVER_CALL(GetGameDescription)(), sizeof(g_GameDesc) - 1);
1.603 +
1.604 + KeyValues *pGameInfo = new KeyValues("GameInfo");
1.605 + if (g_HL2.KVLoadFromFile(pGameInfo, basefilesystem, "gameinfo.txt"))
1.606 + {
1.607 + const char *str;
1.608 + if ((str = pGameInfo->GetString("game", NULL)) != NULL)
1.609 + {
1.610 + strncopy(g_GameName + 1, str, sizeof(g_GameName) - 1);
1.611 + }
1.612 + }
1.613 + pGameInfo->deleteThis();
1.614 +}
1.615 +
1.616 +void GameConfigManager::OnSourceModAllInitialized()
1.617 +{
1.618 + /* NOW initialize the game file */
1.619 + CGameConfig *pGameConf = (CGameConfig *)g_pGameConf;
1.620 +
1.621 + char error[255];
1.622 + if (!pGameConf->Reparse(error, sizeof(error)))
1.623 + {
1.624 + /* :TODO: log */
1.625 + }
1.626 +
1.627 + g_ShareSys.AddInterface(NULL, this);
1.628 +}
1.629 +
1.630 +void GameConfigManager::OnSourceModAllShutdown()
1.631 +{
1.632 + CloseGameConfigFile(g_pGameConf);
1.633 +}
1.634 +
1.635 +bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength)
1.636 +{
1.637 + /* A crash was detected during last load - We block the gamedata loading so it hopefully won't happen again */
1.638 + if (g_blockGameDataLoad)
1.639 + {
1.640 + UTIL_Format(error, maxlength, "GameData loaded blocked due to detected crash");
1.641 + return false;
1.642 + }
1.643 +
1.644 + CGameConfig *pConfig;
1.645 +
1.646 + if (sm_trie_retrieve(m_pLookup, file, (void **)&pConfig))
1.647 + {
1.648 + pConfig->IncRefCount();
1.649 + *_pConfig = pConfig;
1.650 + return true;
1.651 + }
1.652 +
1.653 + pConfig = new CGameConfig(file);
1.654 +
1.655 + /* :HACKHACK: Don't parse the main config file */
1.656 + bool retval = true;
1.657 + if (_pConfig != &g_pGameConf)
1.658 + {
1.659 + retval = pConfig->Reparse(error, maxlength);
1.660 + }
1.661 +
1.662 + m_cfgs.push_back(pConfig);
1.663 + sm_trie_insert(m_pLookup, file, pConfig);
1.664 +
1.665 + pConfig->IncRefCount();
1.666 +
1.667 + *_pConfig = pConfig;
1.668 +
1.669 + return retval;
1.670 +}
1.671 +
1.672 +void GameConfigManager::CloseGameConfigFile(IGameConfig *cfg)
1.673 +{
1.674 + CGameConfig *pConfig = (CGameConfig *)cfg;
1.675 +
1.676 + if (pConfig->DecRefCount() == 0)
1.677 + {
1.678 + sm_trie_delete(m_pLookup, pConfig->m_pFile);
1.679 + delete pConfig;
1.680 + }
1.681 +}
1.682 +
1.683 +extern HandleType_t g_GameConfigsType;
1.684 +
1.685 +IGameConfig *GameConfigManager::ReadHandle(Handle_t hndl, IdentityToken_t *ident, HandleError *err)
1.686 +{
1.687 + HandleSecurity sec(ident, g_pCoreIdent);
1.688 + IGameConfig *conf = NULL;
1.689 + HandleError _err = g_HandleSys.ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&conf);
1.690 +
1.691 + if (err)
1.692 + {
1.693 + *err = _err;
1.694 + }
1.695 +
1.696 + return conf;
1.697 +}