extensions/sdktools/vglobals.cpp
author Scott Ehlert <ds@alliedmods.net>
Mon Mar 03 05:20:40 2014 -0600 (2014-03-03)
changeset 4272 8b39aa02b05b
parent 3823 a15fe74da328
permissions -rw-r--r--
Add gamedata for EntityFactoryDictionary and IServer for Dota 2 on Linux (bug 6068, r=psychonic).
teame06@1245
     1
/**
teame06@1245
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
teame06@1245
     4
 * SourceMod SDKTools Extension
ds@1947
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
teame06@1245
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
teame06@1245
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
teame06@1245
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
teame06@1245
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
faluco@1247
    28
 *
faluco@1247
    29
 * Version: $Id$
faluco@1247
    30
 */
faluco@1247
    31
faluco@1247
    32
#include "extension.h"
skamonkey@3816
    33
#include "vhelpers.h"
faluco@1247
    34
faluco@1247
    35
void **g_pGameRules = NULL;
faluco@1247
    36
void *g_EntList = NULL;
skamonkey@3816
    37
CBaseHandle g_ResourceEntity;
faluco@1247
    38
pred@2746
    39
faluco@1247
    40
void InitializeValveGlobals()
faluco@1247
    41
{
pred@2746
    42
	g_EntList = gamehelpers->GetGlobalEntityList();
faluco@1247
    43
skamonkey@3221
    44
	/*
skamonkey@3221
    45
	 * g_pGameRules
skamonkey@3221
    46
	 *
skamonkey@3221
    47
	 * First try to lookup pointer directly for platforms with symbols.
skamonkey@3221
    48
	 * If symbols aren't present (Windows or stripped Linux/Mac), 
skamonkey@3221
    49
	 * attempt find via CreateGameRulesObject + offset
skamonkey@3221
    50
	 */
faluco@1718
    51
skamonkey@3221
    52
	char *addr;
skamonkey@3221
    53
	if (g_pGameConf->GetMemSig("g_pGameRules", (void **)&addr) && addr)
faluco@1718
    54
	{
skamonkey@3221
    55
		g_pGameRules = reinterpret_cast<void **>(addr);
faluco@1718
    56
	}
skamonkey@3221
    57
	else if (g_pGameConf->GetMemSig("CreateGameRulesObject", (void **)&addr) && addr)
faluco@1247
    58
	{
skamonkey@3221
    59
		int offset;
skamonkey@3221
    60
		if (!g_pGameConf->GetOffset("g_pGameRules", &offset) || !offset)
skamonkey@3221
    61
		{
skamonkey@3221
    62
			return;
skamonkey@3221
    63
		}
skamonkey@3221
    64
		g_pGameRules = *reinterpret_cast<void ***>(addr + offset);
faluco@1247
    65
	}
faluco@1247
    66
}
faluco@1769
    67
ds@2535
    68
size_t UTIL_StringToSignature(const char *str, char buffer[], size_t maxlength)
ds@1952
    69
{
ds@2535
    70
	size_t real_bytes = 0;
ds@2535
    71
	size_t length = strlen(str);
ds@1952
    72
ds@2535
    73
	for (size_t i=0; i<length; i++)
ds@2535
    74
	{
ds@2535
    75
		if (real_bytes >= maxlength)
ds@2535
    76
		{
ds@2535
    77
			break;
ds@2535
    78
		}
ds@2535
    79
		buffer[real_bytes++] = (unsigned char)str[i];
ds@2535
    80
		if (str[i] == '\\'
ds@2535
    81
			&& str[i+1] == 'x')
ds@2535
    82
		{
ds@2535
    83
			if (i + 3 >= length)
ds@2535
    84
			{
ds@2535
    85
				continue;
ds@2535
    86
			}
ds@2535
    87
			/* Get the hex part */
ds@2535
    88
			char s_byte[3];
ds@2535
    89
			int r_byte;
ds@2535
    90
			s_byte[0] = str[i+2];
ds@2535
    91
			s_byte[1] = str[i+3];
ds@2535
    92
			s_byte[2] = '\n';
ds@2535
    93
			/* Read it as an integer */
ds@2535
    94
			sscanf(s_byte, "%x", &r_byte);
ds@2535
    95
			/* Save the value */
ds@2535
    96
			buffer[real_bytes-1] = (unsigned char)r_byte;
ds@2535
    97
			/* Adjust index */
ds@2535
    98
			i += 3;
ds@2535
    99
		}
ds@2535
   100
	}
ds@2535
   101
ds@2535
   102
	return real_bytes;
ds@2535
   103
}
ds@2535
   104
ds@2535
   105
bool UTIL_VerifySignature(const void *addr, const char *sig, size_t len)
ds@2535
   106
{
ds@2535
   107
	unsigned char *addr1 = (unsigned char *) addr;
ds@2535
   108
	unsigned char *addr2 = (unsigned char *) sig;
ds@2535
   109
ds@2535
   110
	for (size_t i = 0; i < len; i++)
ds@1952
   111
	{
ds@1952
   112
		if (addr2[i] == '*')
ds@1952
   113
			continue;
ds@1952
   114
		if (addr1[i] != addr2[i])
ds@1952
   115
			return false;
ds@1952
   116
	}
ds@1952
   117
ds@1952
   118
	return true;
faluco@1773
   119
}
faluco@1773
   120
faluco@1769
   121
#if defined PLATFORM_WINDOWS
ds@4272
   122
#define FAKECLIENT_KEY "CreateFakeClient_Windows"
ds@4272
   123
#elif defined PLATFORM_LINUX
ds@4272
   124
#define FAKECLIENT_KEY "CreateFakeClient_Linux"
ds@4272
   125
#elif defined PLATFORM_APPLE
ds@4272
   126
#define FAKECLIENT_KEY "CreateFakeClient_Mac"
ds@4272
   127
#else
ds@4272
   128
#error "Unsupported platform"
ds@4272
   129
#endif
ds@4272
   130
faluco@1769
   131
void GetIServer()
faluco@1769
   132
{
ds@4272
   133
	void *addr;
ds@2535
   134
	const char *sigstr;
ds@2535
   135
	char sig[32];
ds@2535
   136
	size_t siglen;
faluco@1769
   137
	int offset;
faluco@1769
   138
	void *vfunc = NULL;
faluco@1769
   139
ds@4272
   140
	/* Use the symbol if it exists */
ds@4272
   141
	if (g_pGameConf->GetMemSig("sv", &addr) && addr)
ds@4272
   142
	{
ds@4272
   143
		iserver = reinterpret_cast<IServer *>(addr);
ds@4272
   144
		return;
ds@4272
   145
	}
ds@4272
   146
ds@2858
   147
#if defined METAMOD_PLAPI_VERSION || PLAPI_VERSION >= 11
faluco@1769
   148
	/* Get the CreateFakeClient function pointer */
faluco@1769
   149
	if (!(vfunc=SH_GET_ORIG_VFNPTR_ENTRY(engine, &IVEngineServer::CreateFakeClient)))
faluco@1769
   150
	{
faluco@1769
   151
		return;
faluco@1769
   152
	}
faluco@1769
   153
#else
faluco@1769
   154
	/* Get the interface manually */
faluco@1769
   155
	SourceHook::MemFuncInfo info = {true, -1, 0, 0};
faluco@1769
   156
	SourceHook::GetFuncInfo(&IVEngineServer::CreateFakeClient, info);
faluco@1769
   157
faluco@1769
   158
	vfunc = enginePatch->GetOrigFunc(info.vtbloffs, info.vtblindex);
faluco@1769
   159
	if (!vfunc)
faluco@1769
   160
	{
faluco@1769
   161
		void **vtable = *reinterpret_cast<void ***>(enginePatch->GetThisPtr() + info.thisptroffs + info.vtbloffs);
faluco@1769
   162
		vfunc = vtable[info.vtblindex];
faluco@1769
   163
	}
ds@2535
   164
#endif
ds@2535
   165
ds@2535
   166
	/* Get signature string for IVEngineServer::CreateFakeClient() */
ds@4272
   167
	sigstr = g_pGameConf->GetKeyValue(FAKECLIENT_KEY);
ds@2535
   168
ds@2535
   169
	if (!sigstr)
faluco@1773
   170
	{
faluco@1773
   171
		return;
faluco@1773
   172
	}
faluco@1769
   173
ds@2535
   174
	/* Convert signature string to signature bytes */
ds@2535
   175
	siglen = UTIL_StringToSignature(sigstr, sig, sizeof(sig));
ds@2535
   176
ds@2535
   177
	/* Check if we're on the expected function */
ds@2535
   178
	if (!UTIL_VerifySignature(vfunc, sig, siglen))
ds@2535
   179
	{
ds@2535
   180
		return;
ds@2535
   181
	}
ds@2535
   182
ds@2535
   183
	/* Get the offset into CreateFakeClient */
ds@2535
   184
	if (!g_pGameConf->GetOffset("sv", &offset))
ds@2535
   185
	{
ds@2535
   186
		return;
ds@2535
   187
	}
ds@2535
   188
ds@2535
   189
	/* Finally we have the interface we were looking for */
faluco@1769
   190
	iserver = *reinterpret_cast<IServer **>(reinterpret_cast<unsigned char *>(vfunc) + offset);
faluco@1769
   191
}
skamonkey@3333
   192
skamonkey@3816
   193
void GetResourceEntity()
skamonkey@3816
   194
{
skamonkey@3816
   195
	g_ResourceEntity.Term();
skamonkey@3816
   196
	
skamonkey@3817
   197
#if SOURCE_ENGINE >= SE_ORANGEBOX
skamonkey@3816
   198
	const char *classname = g_pGameConf->GetKeyValue("ResourceEntityClassname");
skamonkey@3816
   199
	if (classname != NULL)
skamonkey@3816
   200
	{
skamonkey@3817
   201
		for (CBaseEntity *pEntity = (CBaseEntity *)servertools->FirstEntity(); pEntity; pEntity = (CBaseEntity *)servertools->NextEntity(pEntity))
skamonkey@3816
   202
		{
skamonkey@3817
   203
			if (!strcmp(gamehelpers->GetEntityClassname(pEntity), classname))
skamonkey@3816
   204
			{
skamonkey@3816
   205
				g_ResourceEntity = ((IHandleEntity *)pEntity)->GetRefEHandle();
skamonkey@3816
   206
				break;
skamonkey@3816
   207
			}
skamonkey@3816
   208
		}
skamonkey@3816
   209
	}
skamonkey@3816
   210
	else
skamonkey@3817
   211
#endif
skamonkey@3816
   212
	{
skamonkey@3816
   213
		int edictCount = gpGlobals->maxEntities;
skamonkey@3816
   214
skamonkey@3816
   215
		for (int i=0; i<edictCount; i++)
skamonkey@3816
   216
		{
skamonkey@3816
   217
			edict_t *pEdict = PEntityOfEntIndex(i);
skamonkey@3816
   218
			if (!pEdict || pEdict->IsFree())
skamonkey@3816
   219
			{
skamonkey@3816
   220
				continue;
skamonkey@3816
   221
			}
skamonkey@3816
   222
			if (!pEdict->GetNetworkable())
skamonkey@3816
   223
			{
skamonkey@3816
   224
				continue;
skamonkey@3816
   225
			}
skamonkey@3816
   226
skamonkey@3816
   227
			IHandleEntity *pHandleEnt = pEdict->GetNetworkable()->GetEntityHandle();
skamonkey@3816
   228
			if (!pHandleEnt)
skamonkey@3816
   229
			{
skamonkey@3816
   230
				continue;
skamonkey@3816
   231
			}
skamonkey@3816
   232
skamonkey@3816
   233
			ServerClass *pClass = pEdict->GetNetworkable()->GetServerClass();
skamonkey@3816
   234
			if (FindNestedDataTable(pClass->m_pTable, "DT_PlayerResource"))
skamonkey@3816
   235
			{
skamonkey@3816
   236
				g_ResourceEntity = pHandleEnt->GetRefEHandle();
skamonkey@3816
   237
				break;
skamonkey@3816
   238
			}
skamonkey@3816
   239
		}
skamonkey@3816
   240
	}
skamonkey@3816
   241
}
skamonkey@3816
   242
skamonkey@3333
   243
const char *GetDTTypeName(int type)
skamonkey@3333
   244
{
skamonkey@3333
   245
	switch (type)
skamonkey@3333
   246
	{
skamonkey@3333
   247
	case DPT_Int:
skamonkey@3333
   248
		{
skamonkey@3333
   249
			return "integer";
skamonkey@3333
   250
		}
skamonkey@3333
   251
	case DPT_Float:
skamonkey@3333
   252
		{
skamonkey@3333
   253
			return "float";
skamonkey@3333
   254
		}
skamonkey@3333
   255
	case DPT_Vector:
skamonkey@3333
   256
		{
skamonkey@3333
   257
			return "vector";
skamonkey@3333
   258
		}
skamonkey@3333
   259
	case DPT_String:
skamonkey@3333
   260
		{
skamonkey@3333
   261
			return "string";
skamonkey@3333
   262
		}
skamonkey@3333
   263
	case DPT_Array:
skamonkey@3333
   264
		{
skamonkey@3333
   265
			return "array";
skamonkey@3333
   266
		}
skamonkey@3333
   267
	case DPT_DataTable:
skamonkey@3333
   268
		{
skamonkey@3333
   269
			return "datatable";
skamonkey@3333
   270
		}
skamonkey@3823
   271
#if SOURCE_ENGINE >= SE_ALIENSWARM
skamonkey@3823
   272
	case DPT_Int64:
skamonkey@3823
   273
		{
skamonkey@3823
   274
			return "int64";
skamonkey@3823
   275
		}
skamonkey@3823
   276
#endif
skamonkey@3333
   277
	default:
skamonkey@3333
   278
		{
skamonkey@3333
   279
			return NULL;
skamonkey@3333
   280
		}
skamonkey@3333
   281
	}
skamonkey@3333
   282
skamonkey@3333
   283
	return NULL;
skamonkey@3333
   284
}