- moved gamedata out of "configs"
- added signature scanning to gameconfs - renamed "*" to "#default" in gameconfs - added new inheritance feature to gameconfs --HG-- rename : configs/gamedata/core.games.txt => gamedata/core.games.txt rename : configs/gamedata/sdktools.games.txt => gamedata/sdktools.games.txt extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40953
This commit is contained in:
		
							parent
							
								
									fa92af4907
								
							
						
					
					
						commit
						b706a6990c
					
				@ -22,6 +22,12 @@
 | 
			
		||||
#include "HalfLife2.h"
 | 
			
		||||
#include "Logger.h"
 | 
			
		||||
#include "ShareSys.h"
 | 
			
		||||
#include "MemoryUtils.h"
 | 
			
		||||
#include "LibrarySys.h"
 | 
			
		||||
 | 
			
		||||
#if defined PLATFORM_LINUX
 | 
			
		||||
#include <dlfcn.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
GameConfigManager g_GameConfigs;
 | 
			
		||||
IGameConfig *g_pGameConf = NULL;
 | 
			
		||||
@ -33,6 +39,9 @@ char g_mod[255];
 | 
			
		||||
#define PSTATE_GAMEDEFS_OFFSETS			3
 | 
			
		||||
#define PSTATE_GAMEDEFS_OFFSETS_OFFSET	4
 | 
			
		||||
#define PSTATE_GAMEDEFS_KEYS			5
 | 
			
		||||
#define PSTATE_GAMEDEFS_SUPPORTED		6
 | 
			
		||||
#define PSTATE_GAMEDEFS_SIGNATURES		7
 | 
			
		||||
#define PSTATE_GAMEDEFS_SIGNATURES_SIG	8
 | 
			
		||||
 | 
			
		||||
#if defined PLATFORM_WINDOWS
 | 
			
		||||
#define PLATFORM_NAME	"windows"
 | 
			
		||||
@ -40,12 +49,24 @@ char g_mod[255];
 | 
			
		||||
#define PLATFORM_NAME	"linux"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct TempSigInfo
 | 
			
		||||
{
 | 
			
		||||
	void Reset()
 | 
			
		||||
	{
 | 
			
		||||
		library[0] = '\0';
 | 
			
		||||
		sig[0] = '\0';
 | 
			
		||||
	}
 | 
			
		||||
	char sig[512];
 | 
			
		||||
	char library[64];
 | 
			
		||||
} s_TempSig;
 | 
			
		||||
 | 
			
		||||
CGameConfig::CGameConfig(const char *file)
 | 
			
		||||
{
 | 
			
		||||
	m_pFile = sm_strdup(file);
 | 
			
		||||
	m_pOffsets = sm_trie_create();
 | 
			
		||||
	m_pProps = sm_trie_create();
 | 
			
		||||
	m_pKeys = sm_trie_create();
 | 
			
		||||
	m_pSigs = sm_trie_create();
 | 
			
		||||
	m_pStrings = new BaseStringTable(512);
 | 
			
		||||
	m_RefCount = 0;
 | 
			
		||||
}
 | 
			
		||||
@ -55,6 +76,7 @@ CGameConfig::~CGameConfig()
 | 
			
		||||
	sm_trie_destroy(m_pOffsets);
 | 
			
		||||
	sm_trie_destroy(m_pProps);
 | 
			
		||||
	sm_trie_destroy(m_pKeys);
 | 
			
		||||
	sm_trie_destroy(m_pSigs);
 | 
			
		||||
	delete [] m_pFile;
 | 
			
		||||
	delete m_pStrings;
 | 
			
		||||
}
 | 
			
		||||
@ -66,6 +88,7 @@ SMCParseResult CGameConfig::ReadSMC_NewSection(const char *name, bool opt_quotes
 | 
			
		||||
		m_IgnoreLevel++;
 | 
			
		||||
		return SMCParse_Continue;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (m_ParseState)
 | 
			
		||||
	{
 | 
			
		||||
	case PSTATE_NONE:
 | 
			
		||||
@ -81,6 +104,7 @@ SMCParseResult CGameConfig::ReadSMC_NewSection(const char *name, bool opt_quotes
 | 
			
		||||
	case PSTATE_GAMES:
 | 
			
		||||
		{
 | 
			
		||||
			if ((strcmp(name, "*") == 0)
 | 
			
		||||
				|| (strcmp(name, "#default") == 0)
 | 
			
		||||
				|| (strcmp(name, g_mod) == 0))
 | 
			
		||||
			{
 | 
			
		||||
				m_ParseState = PSTATE_GAMEDEFS;
 | 
			
		||||
@ -95,9 +119,24 @@ SMCParseResult CGameConfig::ReadSMC_NewSection(const char *name, bool opt_quotes
 | 
			
		||||
			if (strcmp(name, "Offsets") == 0)
 | 
			
		||||
			{
 | 
			
		||||
				m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
 | 
			
		||||
			} else if (strcmp(name, "Keys") == 0) {
 | 
			
		||||
			}
 | 
			
		||||
			else if (strcmp(name, "Keys") == 0)
 | 
			
		||||
			{
 | 
			
		||||
				m_ParseState = PSTATE_GAMEDEFS_KEYS;
 | 
			
		||||
			} else {
 | 
			
		||||
			}
 | 
			
		||||
			else if ((strcmp(name, "#supported") == 0)
 | 
			
		||||
					 && (strcmp(m_mod, "#default") == 0))
 | 
			
		||||
			{
 | 
			
		||||
				m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
 | 
			
		||||
				/* Ignore this section unless we get a game. */
 | 
			
		||||
				bShouldBeReadingDefault = false;
 | 
			
		||||
			}
 | 
			
		||||
			else if (strcmp(name, "Signatures") == 0)
 | 
			
		||||
			{
 | 
			
		||||
				m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				m_IgnoreLevel++;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
@ -110,9 +149,18 @@ SMCParseResult CGameConfig::ReadSMC_NewSection(const char *name, bool opt_quotes
 | 
			
		||||
			m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	case PSTATE_GAMEDEFS_SIGNATURES:
 | 
			
		||||
		{
 | 
			
		||||
			strncopy(m_offset, name, sizeof(m_offset));
 | 
			
		||||
			s_TempSig.Reset();
 | 
			
		||||
			m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	/* No sub-sections allowed:
 | 
			
		||||
	 case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
 | 
			
		||||
	 case PSTATE_GAMEDEFS_KEYS:
 | 
			
		||||
	 case PSTATE_GAMEDEFS_SUPPORTED:
 | 
			
		||||
	 case PSTATE_GAMEDEFS_SIGNATURES_SIG:
 | 
			
		||||
	 */
 | 
			
		||||
	default:
 | 
			
		||||
		{
 | 
			
		||||
@ -146,6 +194,19 @@ SMCParseResult CGameConfig::ReadSMC_KeyValue(const char *key, const char *value,
 | 
			
		||||
	} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
 | 
			
		||||
		int id = m_pStrings->AddString(value);
 | 
			
		||||
		sm_trie_insert(m_pKeys, key, (void *)id);
 | 
			
		||||
	} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
 | 
			
		||||
		if (strcmp(key, "game") == 0
 | 
			
		||||
			&& strcmp(value, g_mod) == 0)
 | 
			
		||||
		{
 | 
			
		||||
			bShouldBeReadingDefault = true;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
 | 
			
		||||
		if (strcmp(key, PLATFORM_NAME) == 0)
 | 
			
		||||
		{
 | 
			
		||||
			strncopy(s_TempSig.sig, value, sizeof(s_TempSig.sig));
 | 
			
		||||
		} else if (strcmp(key, "library") == 0) {
 | 
			
		||||
			strncopy(s_TempSig.library, value, sizeof(s_TempSig.library));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return SMCParse_Continue;
 | 
			
		||||
@ -191,7 +252,7 @@ SMCParseResult CGameConfig::ReadSMC_LeavingSection()
 | 
			
		||||
					sm_trie_insert(m_pProps, m_offset, pProp);
 | 
			
		||||
				} else {
 | 
			
		||||
					/* Check if it's a non-default game and no offsets exist */
 | 
			
		||||
					if ((strcmp(m_mod, "*") != 0)
 | 
			
		||||
					if (((strcmp(m_mod, "*") != 0) && strcmp(m_mod, "#default") != 0)
 | 
			
		||||
						&& (!sm_trie_retrieve(m_pOffsets, m_offset, NULL)))
 | 
			
		||||
					{
 | 
			
		||||
						g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")", 
 | 
			
		||||
@ -203,6 +264,132 @@ SMCParseResult CGameConfig::ReadSMC_LeavingSection()
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	case PSTATE_GAMEDEFS_SUPPORTED:
 | 
			
		||||
		{
 | 
			
		||||
			if (!bShouldBeReadingDefault)
 | 
			
		||||
			{
 | 
			
		||||
				/* If we shouldn't read the rest of this section, set the ignore level. */
 | 
			
		||||
				m_IgnoreLevel = 1;
 | 
			
		||||
			}
 | 
			
		||||
			m_ParseState = PSTATE_GAMEDEFS;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	case PSTATE_GAMEDEFS_SIGNATURES_SIG:
 | 
			
		||||
		{
 | 
			
		||||
			if (s_TempSig.library[0] == '\0')
 | 
			
		||||
			{
 | 
			
		||||
				/* assume server */
 | 
			
		||||
				strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library));
 | 
			
		||||
			}
 | 
			
		||||
			void *addrInBase = NULL;
 | 
			
		||||
			if (strcmp(s_TempSig.library, "server") == 0)
 | 
			
		||||
			{
 | 
			
		||||
				addrInBase = g_SMAPI->serverFactory(false);
 | 
			
		||||
			} else if (strcmp(s_TempSig.library, "engine") == 0) {
 | 
			
		||||
				addrInBase = g_SMAPI->engineFactory(false);
 | 
			
		||||
			}
 | 
			
		||||
			void *final_addr = NULL;
 | 
			
		||||
			if (addrInBase == NULL)
 | 
			
		||||
			{
 | 
			
		||||
				g_Logger.LogError("[SM] Unrecognized library \"%s\" (gameconf \"%s\")", 
 | 
			
		||||
					s_TempSig.library, 
 | 
			
		||||
					m_pFile);
 | 
			
		||||
			} else {
 | 
			
		||||
#if defined PLATFORM_LINUX
 | 
			
		||||
				if (s_TempSig.sig_lin[0] == '@')
 | 
			
		||||
				{
 | 
			
		||||
					Dl_info info;
 | 
			
		||||
					/* GNU only: returns 0 on error, inconsistent! >:[ */
 | 
			
		||||
					if (dladdr(addrInBase, &info) == 0)
 | 
			
		||||
					{
 | 
			
		||||
						void *handle = dlopen(info.dli_fname, RTLD_NOW);
 | 
			
		||||
						if (handle)
 | 
			
		||||
						{
 | 
			
		||||
							final_addr = dlsym(handle, &s_TempSig.sig_lin[1]);
 | 
			
		||||
							dlclose(handle);
 | 
			
		||||
						} else {
 | 
			
		||||
							g_Logger.LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")",
 | 
			
		||||
								s_TempSig.library,
 | 
			
		||||
								m_pFile);
 | 
			
		||||
						}
 | 
			
		||||
					} else {
 | 
			
		||||
						g_Logger.LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")",
 | 
			
		||||
							s_TempSig.library,
 | 
			
		||||
							m_pFile);
 | 
			
		||||
					}
 | 
			
		||||
					if (!final_addr)
 | 
			
		||||
					{
 | 
			
		||||
						g_Logger.LogError("[SM] Unable to find named symbol (symbol \"%s\") (library \"%s\") (gameconf \"%s\")",
 | 
			
		||||
							&s_TempSig.sig_lin[1],
 | 
			
		||||
							s_TempSig.library,
 | 
			
		||||
							m_pFile);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if (final_addr)
 | 
			
		||||
				{
 | 
			
		||||
					goto skip_find;
 | 
			
		||||
				}
 | 
			
		||||
#endif
 | 
			
		||||
				/* First, preprocess the signature */
 | 
			
		||||
				char real_sig[255];
 | 
			
		||||
				size_t real_bytes;
 | 
			
		||||
				size_t length;
 | 
			
		||||
 | 
			
		||||
				real_bytes = 0;
 | 
			
		||||
				length = strlen(s_TempSig.sig);
 | 
			
		||||
 | 
			
		||||
				for (size_t i=0; i<length; i++)
 | 
			
		||||
				{
 | 
			
		||||
					if (real_bytes >= sizeof(real_sig))
 | 
			
		||||
					{
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
					real_sig[real_bytes++] = s_TempSig.sig[i];
 | 
			
		||||
					if (s_TempSig.sig[i] == '\\'
 | 
			
		||||
						&& s_TempSig.sig[i+1] == 'x')
 | 
			
		||||
					{
 | 
			
		||||
						if (i + 3 >= length)
 | 
			
		||||
						{
 | 
			
		||||
							continue;
 | 
			
		||||
						}
 | 
			
		||||
						/* Get the hex part */
 | 
			
		||||
						char s_byte[3];
 | 
			
		||||
						int r_byte;
 | 
			
		||||
						s_byte[0] = s_TempSig.sig[i+2];
 | 
			
		||||
						s_byte[1] = s_TempSig.sig[i+3];
 | 
			
		||||
						s_byte[2] = '\0';
 | 
			
		||||
						/* Read it as an integer */
 | 
			
		||||
						sscanf(s_byte, "%x", &r_byte);
 | 
			
		||||
						/* Save the value */
 | 
			
		||||
						real_sig[real_bytes-1] = r_byte;
 | 
			
		||||
						/* Adjust index */
 | 
			
		||||
						i += 3;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (real_bytes < 1)
 | 
			
		||||
				{
 | 
			
		||||
					g_Logger.LogError("[SM] Invalid signature length of 1 (name \"%s\") (gameconf \"%s\")",
 | 
			
		||||
						m_offset,
 | 
			
		||||
						m_pFile);
 | 
			
		||||
				} else {
 | 
			
		||||
					final_addr = g_MemUtils.FindPattern(addrInBase, real_sig, real_bytes);
 | 
			
		||||
					if (!final_addr)
 | 
			
		||||
					{
 | 
			
		||||
						g_Logger.LogError("[SM] Unable to find signature (name \"%s\") (gameconf \"%s\")", 
 | 
			
		||||
							m_offset,
 | 
			
		||||
							m_pFile);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
#if defined PLATFORM_LINUX
 | 
			
		||||
skip_find:
 | 
			
		||||
#endif
 | 
			
		||||
			sm_trie_insert(m_pSigs, m_offset, final_addr);
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@ -215,10 +402,16 @@ bool CGameConfig::Reparse(char *error, size_t maxlength)
 | 
			
		||||
	SMCParseError err;
 | 
			
		||||
 | 
			
		||||
	char path[PLATFORM_MAX_PATH];
 | 
			
		||||
	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile);
 | 
			
		||||
	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s.txt", m_pFile);
 | 
			
		||||
	/* Backwards compatibility */
 | 
			
		||||
	if (!g_LibSys.PathExists(path))
 | 
			
		||||
	{
 | 
			
		||||
		g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Initialize parse states */
 | 
			
		||||
	m_IgnoreLevel = 0;
 | 
			
		||||
	bShouldBeReadingDefault = true;
 | 
			
		||||
	m_ParseState = PSTATE_NONE;
 | 
			
		||||
	/* Reset cached data */
 | 
			
		||||
	m_pStrings->Reset();
 | 
			
		||||
@ -276,6 +469,11 @@ SendProp *CGameConfig::GetSendProp(const char *key)
 | 
			
		||||
	return pProp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CGameConfig::GetMemSig(const char *key, void **addr)
 | 
			
		||||
{
 | 
			
		||||
	return sm_trie_retrieve(m_pSigs, key, addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CGameConfig::IncRefCount()
 | 
			
		||||
{
 | 
			
		||||
	m_RefCount++;
 | 
			
		||||
 | 
			
		||||
@ -44,6 +44,7 @@ public: //IGameConfig
 | 
			
		||||
	const char *GetKeyValue(const char *key);
 | 
			
		||||
	bool GetOffset(const char *key, int *value);
 | 
			
		||||
	SendProp *GetSendProp(const char *key);
 | 
			
		||||
	bool GetMemSig(const char *key, void **addr);
 | 
			
		||||
public:
 | 
			
		||||
	void IncRefCount();
 | 
			
		||||
	unsigned int DecRefCount();
 | 
			
		||||
@ -53,6 +54,7 @@ private:
 | 
			
		||||
	Trie *m_pOffsets;
 | 
			
		||||
	Trie *m_pProps;
 | 
			
		||||
	Trie *m_pKeys;
 | 
			
		||||
	Trie *m_pSigs;
 | 
			
		||||
	unsigned int m_RefCount;
 | 
			
		||||
	/* Parse states */
 | 
			
		||||
	int m_ParseState;
 | 
			
		||||
@ -61,6 +63,7 @@ private:
 | 
			
		||||
	char m_prop[64];
 | 
			
		||||
	char m_offset[64];
 | 
			
		||||
	char m_mod[255];
 | 
			
		||||
	bool bShouldBeReadingDefault;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GameConfigManager : 
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define SMINTERFACE_GAMECONFIG_NAME			"IGameConfigManager"
 | 
			
		||||
#define SMINTERFACE_GAMECONFIG_VERSION		1
 | 
			
		||||
#define SMINTERFACE_GAMECONFIG_VERSION		2
 | 
			
		||||
 | 
			
		||||
class SendProp;
 | 
			
		||||
 | 
			
		||||
@ -63,6 +63,16 @@ namespace SourceMod
 | 
			
		||||
		 * @return				String containing the value, or NULL if not found.
 | 
			
		||||
		 */
 | 
			
		||||
		virtual const char *GetKeyValue(const char *key) =0;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Retrieves a cached memory signature.
 | 
			
		||||
		 *
 | 
			
		||||
		 * @param key			Name of the signature.
 | 
			
		||||
		 * @param addr			Pointer to store the memory address in.
 | 
			
		||||
		 * @return				A MemorySignature pointer on success, or NULL 
 | 
			
		||||
		 *						if the key was not found.
 | 
			
		||||
		 */
 | 
			
		||||
		virtual bool GetMemSig(const char *key, void **addr) =0;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user