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