Updated gdc-psyfork with latest (NPOTB).

This commit is contained in:
Nicholas Hastings 2012-07-03 10:27:27 -04:00
parent 3479e452de
commit 542c515bc1
8 changed files with 272 additions and 125 deletions

View File

@ -45,6 +45,7 @@
#define PSTATE_GAMEDEFS_CRC 9
#define PSTATE_GAMEDEFS_CRC_BINARY 10
#define PSTATE_GAMEDEFS_CUSTOM 11
#define PSTATE_GAMEDEFS_OPTIONS 12
#define WIN 0
#define LIN 1
@ -134,6 +135,10 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
{
m_ParseState = PSTATE_GAMEDEFS_KEYS;
}
else if (strcmp(name, "Options") == 0)
{
m_ParseState = PSTATE_GAMEDEFS_OPTIONS;
}
else if ((strcmp(name, "#supported") == 0) && (strcmp(m_Game, "#default") == 0))
{
m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
@ -206,6 +211,8 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
}
} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
m_Keys.replace(key, m_pStrings->AddString(value));
} else if (m_ParseState == PSTATE_GAMEDEFS_OPTIONS) {
m_Options.replace(key, m_pStrings->AddString(value));
} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
if (strcmp(key, "game") == 0)
{
@ -289,6 +296,7 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
}
case PSTATE_GAMEDEFS_KEYS:
case PSTATE_GAMEDEFS_OFFSETS:
case PSTATE_GAMEDEFS_OPTIONS:
{
m_ParseState = PSTATE_GAMEDEFS;
break;
@ -471,6 +479,7 @@ bool CGameConfig::Reparse(char *error, size_t maxlength)
m_Offsets.clear();
m_Sigs.clear();
m_Keys.clear();
m_Options.clear();
char path[PLATFORM_MAX_PATH];
@ -557,6 +566,14 @@ const char *CGameConfig::GetKeyValue(const char *key)
return m_pStrings->GetString(*pkey);
}
const char *CGameConfig::GetOptionValue(const char *key)
{
int *pkey;
if ((pkey = m_Options.retrieve(key)) == NULL)
return NULL;
return m_pStrings->GetString(*pkey);
}
list<Offset> CGameConfig::GetOffsets() { return m_Offsets; }
list<Sig> CGameConfig::GetSigs() { return m_Sigs; }

View File

@ -201,6 +201,7 @@ public: //ITextListener_SMC
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
public: //IGameConfig
const char *GetKeyValue(const char *key);
const char *GetOptionValue(const char *key);
bool GetOffset(const char *key, int *value);
SendProp *GetSendProp(const char *key);
bool GetMemSig(const char *key, void **addr);
@ -218,6 +219,7 @@ public:
list<Sig> m_Sigs;
// map<const char*,const char*,cmp_str> m_Keys;
KTrie<int> m_Keys;
KTrie<int> m_Options;
unsigned int m_RefCount;
/* Parse states */
int m_ParseState;

View File

@ -67,20 +67,27 @@ MemoryUtils::~MemoryUtils()
#endif
}
void *MemoryUtils::FindPatternInFile(int fd, const char *pattern, size_t len)
void *MemoryUtils::FindPatternInFile(int fd, const char *pattern, size_t len, int &matches, bool &atFuncStart)
{
size_t size;
size = lseek (fd , 0 , SEEK_END);
matches = 0;
// TODO: fix this
atFuncStart = true;
lseek(fd, 0, SEEK_SET);
void *map;
char *ptr, *end;
char *ptr, *start, *end;
bool found = true;
map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
ptr = (char *)map;
start = ptr;
end = ptr + size;
void *firstMatch = NULL;
while (ptr < end)
{
@ -95,19 +102,49 @@ void *MemoryUtils::FindPatternInFile(int fd, const char *pattern, size_t len)
}
if (found)
return ptr;
{
if( !firstMatch )
{
firstMatch = ptr;
if( ptr - start >= 1 )
{
unsigned char oneBack = *(unsigned char*)((intptr_t)ptr - 1);
if( oneBack != 0xC3 && oneBack != 0xCB && oneBack != 0xCC )
{
if( ptr - start >= 3 )
{
unsigned char threeBack = *(unsigned char*)((intptr_t)ptr - 3);
if( threeBack != 0xCA && threeBack != 0xC2 )
{
atFuncStart = false;
}
}
else
{
atFuncStart = false;
}
}
}
}
++matches;
}
ptr++;
++ptr;
}
return NULL;
return firstMatch;
}
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len, int &matches, bool &atFuncStart)
{
DynLibInfo lib;
bool found;
char *ptr, *end;
matches = 0;
// TODO: fix this
atFuncStart = true;
memset(&lib, 0, sizeof(DynLibInfo));
@ -115,7 +152,8 @@ void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t l
{
return NULL;
}
void *firstMatch = NULL;
ptr = reinterpret_cast<char *>(lib.baseAddress);
end = ptr + lib.memorySize - 1;
@ -132,12 +170,17 @@ void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t l
}
if (found)
return ptr;
{
if( !firstMatch )
firstMatch = ptr;
++matches;
}
ptr++;
++ptr;
}
return NULL;
return firstMatch;
}
void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)

View File

@ -64,11 +64,11 @@ public:
MemoryUtils();
~MemoryUtils();
public: // IMemoryUtils
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
void *FindPattern(const void *libPtr, const char *pattern, size_t len, int &matches, bool &atFuncStart);
void *ResolveSymbol(void *handle, const char *symbol);
const char *ResolveAddr(void *handle, void *addr);
public:
void *FindPatternInFile(int fd, const char *pattern, size_t len);
void *FindPatternInFile(int fd, const char *pattern, size_t len, int &matches, bool &atFuncStart);
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
private:

View File

@ -22,7 +22,7 @@ ENGINE_NAME=orangebox_valve
gamedata_files=(
"sdktools.games/game.cstrike.txt"
"sdktools.games/engine.ep2valve.txt"
"sm-cstrike.games.txt"
"sm-cstrike.games/game.css.txt"
)
# Is game a 2006/2007 "mod" ?

View File

@ -3,6 +3,7 @@
#include <dlfcn.h>
#include <fcntl.h>
#include <math.h>
#include <iostream>
#include "gdc.h"
#include "GameConfigs.h"
#include "MemoryUtils.h"
@ -16,6 +17,11 @@ char *engine_binary = NULL;
char *wgame_binary = NULL;
char *wengine_binary = NULL;
inline bool IsDigit( char c )
{
return c < 58 && c > 47;
}
int main(int argc, char **argv)
{
char *gamedata = NULL;
@ -125,26 +131,6 @@ int main(int argc, char **argv)
return 0;
}
const char *vtsym = symbols.GetKeyValue("vtsym");
if (!vtsym)
{
printf("Couldn't find vtsym\n");
return 0;
}
void **vt = (void**) mu.ResolveSymbol(ghandle, vtsym);
if (!vt)
{
printf("Couldn't find vtable %s\n", vtsym);
dlclose(ghandle);
dlclose(ehandle);
close(wgfile);
close(wefile);
return 0;
}
for (list<Offset>::iterator it = gc.m_Offsets.begin(); it != gc.m_Offsets.end(); it++)
{
if (debug)
@ -155,34 +141,60 @@ int main(int argc, char **argv)
const char *symbol = symbols.GetKeyValue(it->name);
if (symbol)
{
int newOffset;
char symvt[128];
strcpy(symvt, it->name);
strcat(symvt, "_vt");
const char *newvtsym = symbols.GetKeyValue(symvt);
if (newvtsym && newvtsym[0])
char symvt[128] = "_ZTV";
bool bGotFirstNumbers = false;
bool bLastNumberDigit = false;
unsigned int symlen = strlen(symbol);
unsigned int pos = strlen(symvt);
for ( unsigned int i = 0; i < symlen && pos < (sizeof(symvt)-1); ++i )
{
void **newvt = (void**) mu.ResolveSymbol(ghandle, newvtsym);
bool isDigit = IsDigit( symbol[i] );
if( !isDigit && bLastNumberDigit )
{
bGotFirstNumbers = true;
}
// we're before the class len
if( !bGotFirstNumbers && !isDigit )
continue;
// we're at the function name len
if( bGotFirstNumbers && isDigit )
{
symvt[pos] = 0;
break;
}
// we're at the class len or class name. we want these
symvt[pos++] = symbol[i];
if( isDigit )
{
bLastNumberDigit = isDigit;
}
}
symvt[pos] = 0;
int newOffset;
if (symvt[0])
{
void **newvt = (void**) mu.ResolveSymbol(ghandle, symvt);
if (!newvt)
{
printf("O: %-22s - can't find, skipping\n", symvt);
printf("? O: %-22s - can't find, skipping\n", symvt);
continue;
}
newOffset = findVFunc(ghandle, newvt, symbol);
}
else
{
newOffset = findVFunc(ghandle, vt, symbol);
}
if (newOffset == it->lin)
{
printf("O: %-22s - GOOD. current [ w: %3d, l: %3d ].\n", it->name, it->win, it->lin);
printf(" O: %-22s - GOOD. current [ w: %3d, l: %3d ].\n", it->name, it->win, it->lin);
}
else
{
printf("O: %-22s - CHANGED. old [ w: %3d, l: %3d ]. new [ w: %3d, l: %3d ].\n",
printf("! O: %-22s - CHANGED. old [ w: %3d, l: %3d ]. new [ w: %3d, l: %3d ].\n",
it->name,
it->win, it->lin,
newOffset - (it->lin - it->win), newOffset
@ -191,7 +203,7 @@ int main(int argc, char **argv)
}
else // !symbol
{
printf("O: %-22s - no Linux symbol, skipping\n", it->name);
printf(" O: %-22s - no Linux symbol, skipping\n", it->name);
}
}
@ -210,7 +222,7 @@ int main(int argc, char **argv)
bool hasWindows = (winSymbol && winSymbol[0]);
if (!hasLinux && !hasWindows)
{
printf("S: %-22s - hasn't linux nor windows data, skipping\n", it->name);
printf(" S: %-22s - hasn't linux nor windows data, skipping\n", it->name);
continue;
}
@ -228,16 +240,17 @@ int main(int argc, char **argv)
}
else
{
printf("S: %-22s - isn't from server nor engine, skipping\n", it->name);
printf(" S: %-22s - isn't from server nor engine, skipping\n", it->name);
continue;
}
bool foundLinux = (!hasLinux || checkSigStringL(linHandle, linSymbol));
bool foundWindows = (!hasWindows || checkSigStringW(winFile, winSymbol));
int linuxMatches = 0, windowsMatches = 0;
if( hasLinux )
linuxMatches = checkSigStringL(linHandle, linSymbol);
if( hasWindows )
windowsMatches = checkSigStringW(winFile, winSymbol);
// Prepare for ternery ABUSE
if (foundLinux && foundWindows)
if (linuxMatches == 1 && windowsMatches == 1)
{
// too much clutter to print current data if it matches anyway, unlike with offsets
/*
@ -248,42 +261,86 @@ int main(int argc, char **argv)
linSymbol ? linSymbol : ""
);
*/
printf("S: %-22s (%s) - GOOD.\n",
printf(" S: %-22s (%s) - w: GOOD - l: GOOD \n",
it->name,
(it->lib == Server) ? "server" : "engine"
);
}
else
{
// extra \n at end is intentional to add buffer after possibly long sigs
printf("S: %-22s (%s) - w: %s - l: %s\n%s%s%s%s%s%s%s%s\n",
it->name,
(it->lib == Server) ? "server" : "engine",
hasWindows ? (foundWindows ? "GOOD" : "CHANGED") : "UNKNOWN",
hasLinux ? (foundLinux ? "GOOD" : "CHANGED") : "UNKNOWN",
hasWindows ? "\tcurrent - w: " : "",
(hasWindows && foundWindows) ? " (found) \"" : (hasWindows ? "(NOT found) \"" : ""),
(hasWindows && winSymbol) ? winSymbol : "",
hasWindows ? "\"\n" : "",
hasLinux ? "\tcurrent - l: " : "",
(hasLinux && foundLinux) ? " (found) \"" : (hasLinux ? "(NOT found) \"" : ""),
(hasLinux && linSymbol) ? linSymbol : "",
hasLinux ? "\"\n" : ""
);
char winStatus[16];
// right now the only option is to ignore
const char *options = symbols.GetOptionValue(it->name);
bool allowMulti = ( options && strstr(options, "allowmultiple") != NULL );
bool allowMidfunc = ( options && strstr(options, "allowmidfunc") != NULL );
bool bWinGood = false;
if( !hasWindows ) {
snprintf( winStatus, sizeof(winStatus), "UNKNOWN" );
}
else if( windowsMatches == -1 && !allowMidfunc) {
snprintf( winStatus, sizeof(winStatus), "MIDFUNC" );
}
else if( windowsMatches == 0 ) {
snprintf( winStatus, sizeof(winStatus), "NOTFOUND" );
}
else if( windowsMatches > 1 && !allowMulti) {
snprintf( winStatus, sizeof(winStatus), "MULTIPLE" );
}
else {
bWinGood = true;
snprintf( winStatus, sizeof(winStatus), "GOOD" );
}
char linStatus[16];
bool bLinGood = false;
if( !hasLinux ) {
snprintf( linStatus, sizeof(linStatus), "UNKNOWN" );
}
else if( linuxMatches == 0 ) {
snprintf( linStatus, sizeof(linStatus), "NOTFOUND" );
}
else if( linuxMatches == 1 ) {
bLinGood = true;
snprintf( linStatus, sizeof(linStatus), "GOOD" );
}
else {
snprintf( linStatus, sizeof(linStatus), "CHECK" );
}
bool showWinExtra = (hasWindows && !bWinGood);
bool showLinExtra = ( ( hasLinux && !bLinGood ) || showWinExtra );
printf("%s S: %-22s (%s)", (showWinExtra || showLinExtra) ? "!" : " ", it->name, (it->lib == Server) ? "server" : "engine" );
printf(" - w: %-8s - l: %-8s\n", winStatus, linStatus );
if( showWinExtra || showLinExtra )
printf( "! current:\n" );
if( showWinExtra )
{
printf("! w: \"%s\"\n",
winSymbol ? winSymbol : ""
);
}
if( showLinExtra )
{
// extra \n at end is intentional to add buffer after possibly long sigs
printf("! l: \"%s\"\n\n",
linSymbol ? linSymbol : ""
);
}
}
// j/k, no way that anyone could have been prepared for that
}
return 0;
}
bool checkSigStringW(int file, const char* symbol)
int checkSigStringW(int file, const char* symbol)
{
void *addr = NULL;
int matches = 0;
bool atFuncStart = true;
bool isAt = (symbol[0] == '@');
// we can't support this on windows from here
if (isAt)
@ -294,23 +351,25 @@ bool checkSigStringW(int file, const char* symbol)
if (real_bytes >= 1)
{
addr = mu.FindPatternInFile(file, (char*)real_sig, real_bytes);
mu.FindPatternInFile(file, (char*)real_sig, real_bytes, matches, atFuncStart);
}
if (addr)
return true;
if( !atFuncStart )
return -1;
return false;
return matches;
}
bool checkSigStringL(void *handle, const char* symbol)
int checkSigStringL(void *handle, const char* symbol)
{
void *addr = NULL;
bool isAt = (symbol[0] == '@');
int matches = 0;
bool dummy;
if (isAt)
{
addr = mu.ResolveSymbol(handle, symbol + 1);
if( mu.ResolveSymbol(handle, symbol + 1) )
matches = 1;
}
else
{
@ -319,14 +378,11 @@ bool checkSigStringL(void *handle, const char* symbol)
if (real_bytes >= 1)
{
addr = mu.FindPattern(handle, (char*)real_sig, real_bytes);
mu.FindPattern(handle, (char*)real_sig, real_bytes, matches, dummy);
}
}
if (addr)
return true;
return false;
return matches;
}
/*

View File

@ -12,8 +12,8 @@ using namespace SourceMod;
int findFuncPos(const char* sym);
int findVFunc(void *handle, void **vt, const char *symbol);
bool checkSigStringW(int file, const char* symbol);
bool checkSigStringL(void* handle, const char* symbol);
int checkSigStringW(int file, const char* symbol);
int checkSigStringL(void* handle, const char* symbol);
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
size_t UTIL_DecodeHexString(unsigned char *buffer, size_t maxlength, const char *hexstr);

View File

@ -1,30 +1,28 @@
"Games"
{
/*
* "Keys" are used to map gamedata offset names to linux symbol.
* "Options" are used to mark validation options for windows signatures.
* Current valid options are:
* allowmultiple - don't warn if multiple matches are found
* allowmidfunc - don't warn if signature does not match the
* start of a function.
* Multiple options can be specified, separating them with a comma.
* ie. "allowmultiple,allowmidfunc"
*/
"#default"
{
"Keys"
{
"vtsym" "_ZTV11CBaseEntity"
// SDKTools
"GiveNamedItem" "_ZN11CBasePlayer13GiveNamedItemEPKci"
"GiveNamedItem_vt" "_ZTV11CBasePlayer"
"RemovePlayerItem" "_ZN11CBasePlayer16RemovePlayerItemEP17CBaseCombatWeapon"
"RemovePlayerItem_vt" "_ZTV11CBasePlayer"
"Weapon_GetSlot" "_ZNK20CBaseCombatCharacter14Weapon_GetSlotEi"
"Weapon_GetSlot_vt" "_ZTV20CBaseCombatCharacter"
"Ignite" "_ZN14CBaseAnimating6IgniteEfbfb"
"Ignite_vt" "_ZTV14CBaseAnimating"
"Extinguish" "_ZN14CBaseAnimating10ExtinguishEv"
"Extinguish_vt" "_ZTV14CBaseAnimating"
"Teleport" "_ZN11CBaseEntity8TeleportEPK6VectorPK6QAngleS2_"
"CommitSuicide" "_ZN11CBasePlayer13CommitSuicideEbb"
"CommitSuicide_vt" "_ZTV11CBasePlayer"
"GetVelocity" "_ZN11CBaseEntity11GetVelocityEP6VectorS1_"
"EyeAngles" "_ZN11CBasePlayer9EyeAnglesEv"
"DispatchKeyValue" "_ZN11CBaseEntity8KeyValueEPKcS1_"
@ -32,14 +30,9 @@
"DispatchKeyValueVector" "_ZN11CBaseEntity8KeyValueEPKcRK6Vector"
"SetEntityModel" "_ZN11CBaseEntity8SetModelEPKc"
"AcceptInput" "_ZN11CBaseEntity11AcceptInputEPKcPS_S2_9variant_ti"
"WeaponEquip" "_ZN11CBasePlayer12Weapon_EquipEP17CBaseCombatWeapon"
"WeaponEquip_vt" "_ZTV20CBaseCombatCharacter"
"Activate" "_ZN11CBaseEntity8ActivateEv"
"PlayerRunCmd" "_ZN11CBasePlayer16PlayerRunCommandEP8CUserCmdP11IMoveHelper"
"PlayerRunCmd_vt" "_ZTV11CBasePlayer"
// SDKHooks
"EndTouch" "_ZN11CBaseEntity8EndTouchEPS_"
@ -47,11 +40,8 @@
"GroundEntChanged" "_ZN11CBaseEntity35NetworkStateChanged_m_hGroundEntityEv"
"OnTakeDamage" "_ZN11CBaseEntity12OnTakeDamageERK15CTakeDamageInfo"
"PreThink" "_ZN11CBasePlayer8PreThinkEv"
"PreThink_vt" "_ZTV11CBasePlayer"
"PostThink" "_ZN11CBasePlayer9PostThinkEv"
"PostThink_vt" "_ZTV11CBasePlayer"
"Reload" "_ZN17CBaseCombatWeapon6ReloadEv"
"Reload_vt" "_ZTV17CBaseCombatWeapon"
"SetTransmit" "_ZN11CBaseEntity11SetTransmitEP18CCheckTransmitInfob"
"ShouldCollide" "_ZNK11CBaseEntity13ShouldCollideEii"
"Spawn" "_ZN11CBaseEntity5SpawnEv"
@ -63,15 +53,33 @@
"Use" "_ZN11CBaseEntity3UseEPS_S0_8USE_TYPEf"
"VPhysicsUpdate" "_ZN11CBaseEntity14VPhysicsUpdateEP14IPhysicsObject"
"Weapon_CanSwitchTo" "_ZN20CBaseCombatCharacter18Weapon_CanSwitchToEP17CBaseCombatWeapon"
"Weapon_CanSwitchTo_vt" "_ZTV20CBaseCombatCharacter"
"Weapon_CanUse" "_ZN20CBaseCombatCharacter13Weapon_CanUseEP17CBaseCombatWeapon"
"Weapon_CanUse_vt" "_ZTV20CBaseCombatCharacter"
"Weapon_Drop" "_ZN20CBaseCombatCharacter11Weapon_DropEP17CBaseCombatWeaponPK6VectorS4_"
"Weapon_Drop_vt" "_ZTV20CBaseCombatCharacter"
"Weapon_Equip" "_ZN11CBasePlayer12Weapon_EquipEP17CBaseCombatWeapon"
"Weapon_Equip_vt" "_ZTV20CBaseCombatCharacter"
"Weapon_Switch" "_ZN20CBaseCombatCharacter13Weapon_SwitchEP17CBaseCombatWeaponi"
"Weapon_Switch_vt" "_ZTV20CBaseCombatCharacter"
// CEntity extras
"FVisible" "_ZN20CBaseCombatCharacter8FVisibleEP11CBaseEntityiPS1_"
"VPhysicsTakeDamage" "_ZN11CBaseEntity18VPhysicsTakeDamageERK15CTakeDamageInfo"
"VPhysicsGetObjectList" "_ZN11CBaseEntity21VPhysicsGetObjectListEPP14IPhysicsObjecti"
"GetClientEyeAngles" "_ZN11CBaseEntity9EyeAnglesEv"
"WeaponSwitch" "_ZN20CBaseCombatCharacter13Weapon_SwitchEP17CBaseCombatWeaponi"
"CanSpeakVoiceCommand" "_ZN22CBaseMultiplayerPlayer20CanSpeakVoiceCommandEv"
"IsReadyToSpawn" "_ZN11CBasePlayer14IsReadyToSpawnEv"
"OnTakeDamage_Alive" "_ZN20CBaseCombatCharacter18OnTakeDamage_AliveERK15CTakeDamageInfo"
"Jump" "_ZN11CBasePlayer4JumpEv"
"ProcessUserCmds" "_ZN11CBasePlayer15ProcessUsercmdsEP8CUserCmdiiib"
"GetSoundEmissionOrigin" "_ZNK11CBaseEntity22GetSoundEmissionOriginEv"
"GetServerClass" "_ZN11CBaseEntity14GetServerClassEv"
"StudioFrameAdvance" "_ZN14CBaseAnimating18StudioFrameAdvanceEv"
"ShouldGib" "_ZN20CBaseCombatCharacter9ShouldGibERK15CTakeDamageInfo"
"GetRadius" "_ZN13CTFBaseRocket9GetRadiusEv"
"DeflectPlayer" "_ZN13CTFWeaponBase13DeflectPlayerEP9CTFPlayerS1_R6VectorS3_S3_"
}
"Options"
{
"CreateGameRulesObject" "allowmultiple,allowmidfunc"
}
}
@ -82,6 +90,7 @@
"engine" "orangebox_valve"
"engine" "left4dead2"
"engine" "alienswarm"
"engine" "csgo"
}
"Keys"
@ -100,15 +109,10 @@
"Keys"
{
"ForceRespawn" "_ZN9CTFPlayer12ForceRespawnEv"
"ForceRespawn_vt" "_ZTV9CTFPlayer"
"GiveNamedItemTF" "_ZN9CTFPlayer13GiveNamedItemEPKciP13CEconItemViewb"
"GiveNamedItemTF_vt" "_ZTV9CTFPlayer"
"EquipWearable" "_ZN11CBasePlayer13EquipWearableEP13CEconWearable"
"EquipWearable_vt" "_ZTV11CBasePlayer"
"RemoveWearable" "_ZN11CBasePlayer14RemoveWearableEP13CEconWearable"
"RemoveWearable_vt" "_ZTV11CBasePlayer"
"GrenadeDetonate" "_ZN12CBaseGrenade8DetonateEv"
"GrenadeDetonate_vt" "_ZTV12CBaseGrenade"
}
}
@ -117,13 +121,38 @@
"#supported"
{
"engine" "left4dead"
"engine" "left4dead2"
"game" "left4dead2"
}
"Keys"
{
"GiveNamedItem" "_ZN9CCSPlayer13GiveNamedItemEPKci"
"GiveNamedItem_vt" "_ZTV9CCSPlayer"
}
}
"#default"
{
"#supported"
{
"game" "nucleardawn"
}
"Keys"
{
"GiveNamedItem" "_ZN9CNDPlayer13GiveNamedItemEPKcib"
}
}
"#default"
{
"#supported"
{
"engine" "csgo"
}
"Keys"
{
"Teleport" "_ZN11CBaseEntity8TeleportEPK6VectorPK6QAngleS2_b"
"GiveNamedItem" "_ZN11CBasePlayer13GiveNamedItemEPKcib"
}
}
}