core/GameConfigs.cpp
author David Anderson <dvander@alliedmods.net>
Sat Mar 10 21:26:04 2007 +0000 (2007-03-10)
changeset 592 c2a2c38f1331
parent 591 core/CGameConfigs.cpp@86e97f3eda1f
child 616 d5b1dcf38c07
permissions -rw-r--r--
part 2 of singleton renaming
     1 /**
     2  * ===============================================================
     3  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     4  * ===============================================================
     5  *
     6  * This file is not open source and may not be copied without explicit
     7  * written permission of AlliedModders LLC.  This file may not be redistributed 
     8  * in whole or significant part.
     9  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    10  *
    11  * Version: $Id$
    12  */
    13 
    14 #include <string.h>
    15 #include <stdlib.h>
    16 #include "GameConfigs.h"
    17 #include "TextParsers.h"
    18 #include "sm_stringutil.h"
    19 #include "sourcemod.h"
    20 #include "sourcemm_api.h"
    21 #include "HalfLife2.h"
    22 #include "Logger.h"
    23 #include "ShareSys.h"
    24 
    25 CGameConfigManager g_GameConfigs;
    26 IGameConfig *g_pGameConf = NULL;
    27 char g_mod[255];
    28 
    29 #define PSTATE_NONE						0
    30 #define PSTATE_GAMES					1
    31 #define PSTATE_GAMEDEFS					2
    32 #define PSTATE_GAMEDEFS_OFFSETS			3
    33 #define PSTATE_GAMEDEFS_OFFSETS_OFFSET	4
    34 #define PSTATE_GAMEDEFS_KEYS			5
    35 
    36 #if defined PLATFORM_WINDOWS
    37 #define PLATFORM_NAME	"windows"
    38 #elif defined PLATFORM_LINUX
    39 #define PLATFORM_NAME	"linux"
    40 #endif
    41 
    42 CGameConfig::CGameConfig(const char *file)
    43 {
    44 	m_pFile = sm_strdup(file);
    45 	m_pOffsets = sm_trie_create();
    46 	m_pProps = sm_trie_create();
    47 	m_pKeys = sm_trie_create();
    48 	m_pStrings = new BaseStringTable(512);
    49 }
    50 
    51 CGameConfig::~CGameConfig()
    52 {
    53 	sm_trie_destroy(m_pOffsets);
    54 	sm_trie_destroy(m_pProps);
    55 	sm_trie_destroy(m_pKeys);
    56 	delete [] m_pFile;
    57 	delete m_pStrings;
    58 }
    59 
    60 SMCParseResult CGameConfig::ReadSMC_NewSection(const char *name, bool opt_quotes)
    61 {
    62 	if (m_IgnoreLevel)
    63 	{
    64 		m_IgnoreLevel++;
    65 		return SMCParse_Continue;
    66 	}
    67 	switch (m_ParseState)
    68 	{
    69 	case PSTATE_NONE:
    70 		{
    71 			if (strcmp(name, "Games") == 0)
    72 			{
    73 				m_ParseState = PSTATE_GAMES;
    74 			} else {
    75 				m_IgnoreLevel++;
    76 			}
    77 			break;
    78 		}
    79 	case PSTATE_GAMES:
    80 		{
    81 			if ((strcmp(name, "*") == 0)
    82 				|| (strcmp(name, g_mod) == 0))
    83 			{
    84 				m_ParseState = PSTATE_GAMEDEFS;
    85 				strncopy(m_mod, name, sizeof(m_mod));
    86 			} else {
    87 				m_IgnoreLevel++;
    88 			}
    89 			break;
    90 		}
    91 	case PSTATE_GAMEDEFS:
    92 		{
    93 			if (strcmp(name, "Offsets") == 0)
    94 			{
    95 				m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
    96 			} else if (strcmp(name, "Keys") == 0) {
    97 				m_ParseState = PSTATE_GAMEDEFS_KEYS;
    98 			} else {
    99 				m_IgnoreLevel++;
   100 			}
   101 			break;
   102 		}
   103 	case PSTATE_GAMEDEFS_OFFSETS:
   104 		{
   105 			m_prop[0] = '\0';
   106 			m_class[0] = '\0';
   107 			strncopy(m_offset, name, sizeof(m_offset));
   108 			m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
   109 			break;
   110 		}
   111 	/* No sub-sections allowed:
   112 	 case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
   113 	 case PSTATE_GAMEDEFS_KEYS:
   114 	 */
   115 	default:
   116 		{
   117 			/* If we don't know what we got, start ignoring */
   118 			m_IgnoreLevel++;
   119 			break;
   120 		}
   121 	}
   122 
   123 	return SMCParse_Continue;
   124 }
   125 
   126 SMCParseResult CGameConfig::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
   127 {
   128 	if (m_IgnoreLevel)
   129 	{
   130 		return SMCParse_Continue;
   131 	}
   132 
   133 	if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET)
   134 	{
   135 		if (strcmp(key, "class") == 0)
   136 		{
   137 			strncopy(m_class, value, sizeof(m_class));
   138 		} else if (strcmp(key, "prop") == 0) {
   139 			strncopy(m_prop, value, sizeof(m_prop));
   140 		} else if (strcmp(key, PLATFORM_NAME) == 0) {
   141 			int val = atoi(value);
   142 			sm_trie_insert(m_pOffsets, m_offset, (void *)val);
   143 		}
   144 	} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
   145 		int id = m_pStrings->AddString(value);
   146 		sm_trie_insert(m_pKeys, key, (void *)id);
   147 	}
   148 
   149 	return SMCParse_Continue;
   150 }
   151 
   152 SMCParseResult CGameConfig::ReadSMC_LeavingSection()
   153 {
   154 	if (m_IgnoreLevel)
   155 	{
   156 		m_IgnoreLevel--;
   157 		return SMCParse_Continue;
   158 	}
   159 
   160 	switch (m_ParseState)
   161 	{
   162 	case PSTATE_GAMES:
   163 		{
   164 			m_ParseState = PSTATE_NONE;
   165 			break;
   166 		}
   167 	case PSTATE_GAMEDEFS:
   168 		{
   169 			m_ParseState = PSTATE_GAMES;
   170 			break;
   171 		}
   172 	case PSTATE_GAMEDEFS_KEYS:
   173 	case PSTATE_GAMEDEFS_OFFSETS:
   174 		{
   175 			m_ParseState = PSTATE_GAMEDEFS;
   176 			break;
   177 		}
   178 	case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
   179 		{
   180 			/* Parse the offset... */
   181 			if (m_class[0] != '\0'
   182 				&& m_prop[0] != '\0')
   183 			{
   184 				SendProp *pProp = g_HL2.FindInSendTable(m_class, m_prop);
   185 				if (pProp)
   186 				{
   187 					int val = pProp->GetOffset();
   188 					sm_trie_insert(m_pOffsets, m_offset, (void *)val);
   189 					sm_trie_insert(m_pProps, m_offset, pProp);
   190 				} else {
   191 					/* Check if it's a non-default game and no offsets exist */
   192 					if ((strcmp(m_mod, "*") != 0)
   193 						&& (!sm_trie_retrieve(m_pOffsets, m_offset, NULL)))
   194 					{
   195 						g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")", 
   196 							m_class,
   197 							m_prop,
   198 							m_pFile,
   199 							m_mod);
   200 					}
   201 				}
   202 			}
   203 			m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
   204 			break;
   205 		}
   206 	}
   207 
   208 	return SMCParse_Continue;
   209 }
   210 
   211 bool CGameConfig::Reparse(char *error, size_t maxlength)
   212 {
   213 	SMCParseError err;
   214 
   215 	char path[PLATFORM_MAX_PATH];
   216 	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile);
   217 
   218 	/* Initialize parse states */
   219 	m_IgnoreLevel = 0;
   220 	m_ParseState = PSTATE_NONE;
   221 	/* Reset cached data */
   222 	m_pStrings->Reset();
   223 	sm_trie_clear(m_pOffsets);
   224 	sm_trie_clear(m_pProps);
   225 	sm_trie_clear(m_pKeys);
   226 
   227 	if ((err=g_TextParser.ParseFile_SMC(path, this, NULL, NULL))
   228 		!= SMCParse_Okay)
   229 	{
   230 		if (error && (err != SMCParse_Custom))
   231 		{
   232 			const char *str = g_TextParser.GetSMCErrorString(err);
   233 			snprintf(error, maxlength, "%s", str);
   234 		}
   235 		return false;
   236 	}
   237 
   238 	return true;
   239 }
   240 
   241 bool CGameConfig::GetOffset(const char *key, int *value)
   242 {
   243 	void *obj;
   244 
   245 	if (!sm_trie_retrieve(m_pOffsets, key, &obj))
   246 	{
   247 		return false;
   248 	}
   249 
   250 	*value = (int)obj;
   251 	
   252 	return true;
   253 }
   254 
   255 const char *CGameConfig::GetKeyValue(const char *key)
   256 {
   257 	void *obj;
   258 	if (!sm_trie_retrieve(m_pKeys, key, &obj))
   259 	{
   260 		return NULL;
   261 	}
   262 	return m_pStrings->GetString((int)obj);
   263 }
   264 
   265 SendProp *CGameConfig::GetSendProp(const char *key)
   266 {
   267 	SendProp *pProp;
   268 
   269 	if (!sm_trie_retrieve(m_pProps, key, (void **)&pProp))
   270 	{
   271 		return NULL;
   272 	}
   273 
   274 	return pProp;
   275 }
   276 
   277 void CGameConfig::IncRefCount()
   278 {
   279 	m_RefCount++;
   280 }
   281 
   282 unsigned int CGameConfig::DecRefCount()
   283 {
   284 	m_RefCount--;
   285 	return m_RefCount;
   286 }
   287 
   288 CGameConfigManager::CGameConfigManager()
   289 {
   290 	m_pLookup = sm_trie_create();
   291 }
   292 
   293 CGameConfigManager::~CGameConfigManager()
   294 {
   295 	sm_trie_destroy(m_pLookup);
   296 }
   297 
   298 void CGameConfigManager::OnSourceModStartup(bool late)
   299 {
   300 	LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
   301 
   302 	char mod[255];
   303 	engine->GetGameDir(mod, sizeof(mod));
   304 
   305 	g_mod[0] = '\0';
   306 	size_t len = strlen(mod);
   307 	for (size_t i=len-1; i>=0 && i<len; i++)
   308 	{
   309 		if (mod[i] == '/')
   310 		{
   311 			if (i == len-1)
   312 			{
   313 				mod[i] = '\0';
   314 				continue;
   315 			}
   316 			strcpy(g_mod, &mod[i]);
   317 			break;
   318 		}
   319 	}
   320 	if (g_mod[0] != '\0')
   321 	{
   322 		strcpy(g_mod, mod);
   323 	}
   324 }
   325 
   326 void CGameConfigManager::OnSourceModAllInitialized()
   327 {
   328 	/* NOW initialize the game file */
   329 	CGameConfig *pGameConf = (CGameConfig *)g_pGameConf;
   330 	
   331 	char error[255];
   332 	if (!pGameConf->Reparse(error, sizeof(error)))
   333 	{
   334 		/* :TODO: log */
   335 	}
   336 
   337 	g_ShareSys.AddInterface(NULL, this);
   338 }
   339 
   340 void CGameConfigManager::OnSourceModAllShutdown()
   341 {
   342 	CloseGameConfigFile(g_pGameConf);
   343 }
   344 
   345 bool CGameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength)
   346 {
   347 	CGameConfig *pConfig;
   348 
   349 	if (sm_trie_retrieve(m_pLookup, file, (void **)&pConfig))
   350 	{
   351 		pConfig->IncRefCount();
   352 		*_pConfig = pConfig;
   353 		return true;
   354 	}
   355 
   356 	pConfig = new CGameConfig(file);
   357 
   358 	/* :HACKHACK: Don't parse the main config file */
   359 	bool retval = true;
   360 	if (_pConfig != &g_pGameConf)
   361 	{
   362 		retval = pConfig->Reparse(error, maxlength);
   363 	}
   364 
   365 	m_cfgs.push_back(pConfig);
   366 	sm_trie_insert(m_pLookup, file, pConfig);
   367 
   368 	pConfig->IncRefCount();
   369 
   370 	*_pConfig = pConfig;
   371 
   372 	return retval;
   373 }
   374 
   375 void CGameConfigManager::CloseGameConfigFile(IGameConfig *cfg)
   376 {
   377 	CGameConfig *pConfig = (CGameConfig *)cfg;
   378 
   379 	if (pConfig->DecRefCount() == 0)
   380 	{
   381 		delete pConfig;
   382 	}
   383 }