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