Fix cstrike extension natives/forwards due to update
This commit is contained in:
parent
8627c0cbfc
commit
3eb297bee1
@ -8,7 +8,9 @@ bool g_pIgnoreTerminateDetour = false;
|
||||
bool g_pIgnoreCSWeaponDropDetour = false;
|
||||
bool g_PriceDetoured = false;
|
||||
bool g_HandleBuyDetoured = false;
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
int lastclient = -1;
|
||||
#endif
|
||||
|
||||
IForward *g_pHandleBuyForward = NULL;
|
||||
IForward *g_pPriceForward = NULL;
|
||||
@ -22,10 +24,77 @@ CDetour *DCSWeaponDrop = NULL;
|
||||
int weaponNameOffset = -1;
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
DETOUR_DECL_MEMBER3(DetourHandleBuy, int, int, iUnknown, const char *, weapon, bool, bRebuy)
|
||||
DETOUR_DECL_MEMBER3(DetourHandleBuy, int, int, iLoadoutSlot, void *, pWpnDataRef, bool, bRebuy)
|
||||
{
|
||||
int client = gamehelpers->EntityToBCompatRef(reinterpret_cast<CBaseEntity *>(this));
|
||||
|
||||
CEconItemView *pView = GetEconItemView(this, iLoadoutSlot);
|
||||
|
||||
if (!pView)
|
||||
{
|
||||
return DETOUR_MEMBER_CALL(DetourHandleBuy)(iLoadoutSlot, pWpnDataRef, bRebuy);
|
||||
}
|
||||
|
||||
void *pWpnData = GetCCSWeaponData(pView);
|
||||
|
||||
if (!pWpnData)
|
||||
{
|
||||
return DETOUR_MEMBER_CALL(DetourHandleBuy)(iLoadoutSlot, pWpnDataRef, bRebuy);
|
||||
}
|
||||
|
||||
const char *szClassname = *(const char **)((intptr_t)pWpnData + weaponNameOffset);
|
||||
|
||||
char weaponName[128];
|
||||
|
||||
if (strstr(szClassname, "knife"))
|
||||
{
|
||||
Q_strcpy(weaponName, "knife");
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *underscore = strstr(szClassname, "_");
|
||||
if (underscore)
|
||||
{
|
||||
Q_strncpy(weaponName, (const char *)((intptr_t)underscore + 1), sizeof(weaponName));
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strcpy(weaponName, szClassname);
|
||||
}
|
||||
}
|
||||
|
||||
cell_t result = Pl_Continue;
|
||||
|
||||
g_pHandleBuyForward->PushCell(client);
|
||||
g_pHandleBuyForward->PushString(weaponName);
|
||||
g_pHandleBuyForward->Execute(&result);
|
||||
|
||||
if (result != Pl_Continue)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int originalPrice = 0;
|
||||
|
||||
if (g_iPriceOffset != -1)
|
||||
{
|
||||
originalPrice = *(int *)((intptr_t)pWpnData + g_iPriceOffset);
|
||||
|
||||
int changedPrice = CallPriceForward(client, weaponName, originalPrice);
|
||||
|
||||
if (originalPrice != changedPrice)
|
||||
*(int *)((intptr_t)pWpnData + g_iPriceOffset) = changedPrice;
|
||||
}
|
||||
|
||||
int ret = DETOUR_MEMBER_CALL(DetourHandleBuy)(iLoadoutSlot, pWpnDataRef, bRebuy);
|
||||
|
||||
if (g_iPriceOffset != -1)
|
||||
*(int *)((intptr_t)pWpnData + g_iPriceOffset) = originalPrice;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
DETOUR_DECL_MEMBER1(DetourHandleBuy, int, const char *, weapon)
|
||||
#endif
|
||||
{
|
||||
int client = gamehelpers->EntityToBCompatRef(reinterpret_cast<CBaseEntity *>(this));
|
||||
|
||||
@ -43,31 +112,17 @@ DETOUR_DECL_MEMBER1(DetourHandleBuy, int, const char *, weapon)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
int val = DETOUR_MEMBER_CALL(DetourHandleBuy)(iUnknown, weapon, bRebuy);
|
||||
#else
|
||||
int val = DETOUR_MEMBER_CALL(DetourHandleBuy)(weapon);
|
||||
#endif
|
||||
|
||||
lastclient = -1;
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
DETOUR_DECL_MEMBER0(DetourWeaponPrice, int)
|
||||
#elif defined(WIN32)
|
||||
DETOUR_DECL_MEMBER2(DetourWeaponPrice, int, CEconItemView *, pEconItem, int, iUnknown)
|
||||
#else
|
||||
DETOUR_DECL_MEMBER3(DetourWeaponPrice, int, CEconItemView *, pEconItem, int, iUnknown, float, fUnknown)
|
||||
#endif
|
||||
{
|
||||
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
int price = DETOUR_MEMBER_CALL(DetourWeaponPrice)();
|
||||
#elif defined(WIN32)
|
||||
int price = DETOUR_MEMBER_CALL(DetourWeaponPrice)(pEconItem, iUnknown);
|
||||
#else
|
||||
int price = DETOUR_MEMBER_CALL(DetourWeaponPrice)(pEconItem, iUnknown, fUnknown);
|
||||
#endif
|
||||
|
||||
if (lastclient == -1)
|
||||
return price;
|
||||
@ -76,6 +131,7 @@ DETOUR_DECL_MEMBER3(DetourWeaponPrice, int, CEconItemView *, pEconItem, int, iUn
|
||||
|
||||
return CallPriceForward(lastclient, weapon_name, price);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE != SE_CSGO || !defined(WIN32)
|
||||
DETOUR_DECL_MEMBER2(DetourTerminateRound, void, float, delay, int, reason)
|
||||
@ -179,6 +235,7 @@ DETOUR_DECL_MEMBER3(DetourCSWeaponDrop, void, CBaseEntity *, weapon, bool, bDrop
|
||||
|
||||
bool CreateWeaponPriceDetour()
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
if (weaponNameOffset == -1)
|
||||
{
|
||||
if (!g_pGameConf->GetOffset("WeaponName", &weaponNameOffset))
|
||||
@ -188,18 +245,7 @@ bool CreateWeaponPriceDetour()
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
void *pGetWeaponPriceAddress = GetWeaponPriceFunction();
|
||||
|
||||
if(!pGetWeaponPriceAddress)
|
||||
{
|
||||
g_pSM->LogError(myself, "GetWeaponPrice detour could not be initialized - Disabled OnGetWeaponPrice forward.");
|
||||
}
|
||||
|
||||
DWeaponPrice = DETOUR_CREATE_MEMBER(DetourWeaponPrice, pGetWeaponPriceAddress);
|
||||
#else
|
||||
DWeaponPrice = DETOUR_CREATE_MEMBER(DetourWeaponPrice, "GetWeaponPrice");
|
||||
#endif
|
||||
if (DWeaponPrice != NULL)
|
||||
{
|
||||
if (!CreateHandleBuyDetour())
|
||||
@ -211,7 +257,27 @@ bool CreateWeaponPriceDetour()
|
||||
g_PriceDetoured = true;
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
if (g_iPriceOffset == -1)
|
||||
{
|
||||
if (!g_pGameConf->GetOffset("WeaponPrice", &g_iPriceOffset))
|
||||
{
|
||||
smutils->LogError(myself, "Could not find WeaponPrice offset - Disabled OnGetWeaponPrice forward");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CreateHandleBuyDetour())
|
||||
{
|
||||
g_pSM->LogError(myself, "GetWeaponPrice detour could not be initialized - HandleCommand_Buy_Internal failed to detour, disabled OnGetWeaponPrice forward.");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_PriceDetoured = true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
g_pSM->LogError(myself, "GetWeaponPrice detour could not be initialized - Disabled OnGetWeaponPrice forward.");
|
||||
|
||||
return false;
|
||||
@ -236,6 +302,16 @@ bool CreateHandleBuyDetour()
|
||||
if (g_HandleBuyDetoured)
|
||||
return true;
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
if (weaponNameOffset == -1)
|
||||
{
|
||||
if (!g_pGameConf->GetOffset("WeaponName", &weaponNameOffset))
|
||||
{
|
||||
smutils->LogError(myself, "Could not find WeaponName offset - Disabled OnBuyCommand forward");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DHandleBuy = DETOUR_CREATE_MEMBER(DetourHandleBuy, "HandleCommand_Buy_Internal");
|
||||
|
||||
if (DHandleBuy != NULL)
|
||||
@ -305,6 +381,7 @@ void RemoveCSWeaponDropDetour()
|
||||
}
|
||||
g_pCSWeaponDropDetoured = false;
|
||||
}
|
||||
|
||||
int CallPriceForward(int client, const char *weapon_name, int price)
|
||||
{
|
||||
int changedprice = price;
|
||||
|
@ -14,4 +14,7 @@ extern IForward *g_pHandleBuyForward;
|
||||
extern IForward *g_pPriceForward;
|
||||
extern IForward *g_pTerminateRoundForward;
|
||||
extern IForward *g_pCSWeaponDropForward;
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
extern int g_iPriceOffset;
|
||||
#endif
|
||||
#endif //_INCLUDE_CSTRIKE_FORWARDS_H_
|
||||
|
@ -398,8 +398,14 @@ static cell_t CS_GetTranslatedWeaponAlias(IPluginContext *pContext, const cell_t
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CBaseEntity *pEntity;
|
||||
if (!(pEntity = GetCBaseEntity(params[1], true)))
|
||||
{
|
||||
return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
|
||||
}
|
||||
|
||||
if (!IsValidWeaponID(params[2]))
|
||||
return pContext->ThrowNativeError("Invalid WeaponID passed for this game");
|
||||
@ -407,24 +413,14 @@ static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
|
||||
int id = GetRealWeaponID(params[2]);
|
||||
|
||||
//Hard code return values for weapons that dont call GetWeaponPrice and always use default value.
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
|
||||
if (id == WEAPON_C4 || id == WEAPON_KNIFE || id == WEAPON_KNIFE_GG)
|
||||
return 0;
|
||||
#else
|
||||
if (id == WEAPON_C4 || id == WEAPON_KNIFE || id == WEAPON_SHIELD)
|
||||
return 0;
|
||||
else if (id == WEAPON_KEVLAR)
|
||||
return 650;
|
||||
else if (id == WEAPON_ASSAULTSUIT)
|
||||
return 1000;
|
||||
#endif
|
||||
else if (id == WEAPON_NIGHTVISION)
|
||||
return 1250;
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
else if (id == WEAPON_DEFUSER)
|
||||
return 400;
|
||||
#endif
|
||||
|
||||
void *info = GetWeaponInfo(id);
|
||||
|
||||
@ -438,139 +434,7 @@ static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
|
||||
}
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
static ICallWrapper *pWrapper = NULL;
|
||||
|
||||
if(!pWrapper)
|
||||
{
|
||||
void *pGetWeaponPrice = GetWeaponPriceFunction();
|
||||
if(!pGetWeaponPrice)
|
||||
{
|
||||
return pContext->ThrowNativeError("Failed to locate function");
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
const size_t GWP_ARGC = 2;
|
||||
#else
|
||||
const size_t GWP_ARGC = 3;
|
||||
#endif
|
||||
PassInfo pass[GWP_ARGC];
|
||||
PassInfo ret;
|
||||
pass[0].flags = PASSFLAG_BYVAL;
|
||||
pass[0].type = PassType_Basic;
|
||||
pass[0].size = sizeof(CEconItemView *);
|
||||
pass[1].flags = PASSFLAG_BYVAL;
|
||||
pass[1].type = PassType_Basic;
|
||||
pass[1].size = sizeof(int);
|
||||
#ifndef _WIN32
|
||||
pass[2].flags = PASSFLAG_BYVAL;
|
||||
pass[2].type = PassType_Float;
|
||||
pass[2].size = sizeof(float);
|
||||
#endif
|
||||
ret.flags = PASSFLAG_BYVAL;
|
||||
ret.type = PassType_Basic;
|
||||
ret.size = sizeof(int);
|
||||
pWrapper = g_pBinTools->CreateCall(pGetWeaponPrice, CallConv_ThisCall, &ret, pass, GWP_ARGC);
|
||||
}
|
||||
|
||||
// Get a CEconItemView for the m4
|
||||
// Found in CCSPlayer::HandleCommand_Buy_Internal
|
||||
// Linux a1 - CCSPlayer *pEntity, v5 - Player Team, a3 - ItemLoadoutSlot -1 use default loadoutslot:
|
||||
// v4 = *(int (__cdecl **)(_DWORD, _DWORD, _DWORD))(*(_DWORD *)(a1 + 9492) + 36); // offset 9
|
||||
// v6 = v4(a1 + 9492, v5, a3);
|
||||
// Windows v5 - CCSPlayer *pEntity a4 - ItemLoadoutSlot -1 use default loadoutslot:
|
||||
// v8 = (*(int (__stdcall **)(_DWORD, int))(*(_DWORD *)(v5 + 9472) + 32))(*(_DWORD *)(v5 + 760), a4); // offset 8
|
||||
// The function is CCSPlayerInventory::GetItemInLoadout(int, int)
|
||||
// We can pass NULL view to the GetAttribute to use default loadoutslot.
|
||||
// We only really care about m4a1/m4a4 as price differs between them
|
||||
// thisPtrOffset = 9472/9492
|
||||
|
||||
static ICallWrapper *pGetView = NULL;
|
||||
static int thisPtrOffset = -1;
|
||||
CEconItemView *view = NULL;
|
||||
|
||||
if(!pGetView)
|
||||
{
|
||||
int offset = -1;
|
||||
int byteOffset = -1;
|
||||
void *pHandleCommandBuy = NULL;
|
||||
if (!g_pGameConf->GetOffset("GetItemInLoadout", &offset) || offset == -1)
|
||||
{
|
||||
smutils->LogError(myself, "Failed to get GetItemInLoadout offset. Reverting to NULL ItemView");
|
||||
}
|
||||
else if (!g_pGameConf->GetOffset("CCSPlayerInventoryOffset", &byteOffset) || byteOffset == -1)
|
||||
{
|
||||
smutils->LogError(myself, "Failed to get CCSPlayerInventoryOffset offset. Reverting to NULL ItemView");
|
||||
}
|
||||
else if (!g_pGameConf->GetMemSig("HandleCommand_Buy_Internal", &pHandleCommandBuy) || !pHandleCommandBuy)
|
||||
{
|
||||
smutils->LogError(myself, "Failed to get HandleCommand_Buy_Internal function. Reverting to NULL ItemView");
|
||||
}
|
||||
else
|
||||
{
|
||||
thisPtrOffset = *(int *)((intptr_t)pHandleCommandBuy + byteOffset);
|
||||
|
||||
PassInfo pass[2];
|
||||
PassInfo ret;
|
||||
pass[0].flags = PASSFLAG_BYVAL;
|
||||
pass[0].type = PassType_Basic;
|
||||
pass[0].size = sizeof(int);
|
||||
pass[1].flags = PASSFLAG_BYVAL;
|
||||
pass[1].type = PassType_Basic;
|
||||
pass[1].size = sizeof(int);
|
||||
|
||||
ret.flags = PASSFLAG_BYVAL;
|
||||
ret.type = PassType_Basic;
|
||||
ret.size = sizeof(void *);
|
||||
|
||||
pGetView = g_pBinTools->CreateVCall(offset, 0, 0, &ret, pass, 2);
|
||||
g_RegNatives.Register(pGetView);
|
||||
}
|
||||
}
|
||||
|
||||
IPlayerInfo *playerinfo = playerhelpers->GetGamePlayer(params[1])->GetPlayerInfo();
|
||||
if(pGetView && thisPtrOffset != -1 && playerinfo)
|
||||
{
|
||||
//If the gun isnt an M4 we ignore this as M4 is the only one that differs in price based on Loadout item.
|
||||
int iLoadoutSlot = -1;
|
||||
if(id == WEAPON_M4)
|
||||
{
|
||||
iLoadoutSlot = 15;
|
||||
}
|
||||
|
||||
unsigned char vstk_view[sizeof(void *) + sizeof(int) * 2];
|
||||
unsigned char *vptr_view = vstk_view;
|
||||
|
||||
*(void **)vptr_view = (void *)((intptr_t)pEntity + thisPtrOffset);
|
||||
vptr_view += sizeof(void *);
|
||||
*(int *)vptr_view = playerinfo->GetTeamIndex();
|
||||
vptr_view += sizeof(int);
|
||||
*(int *)vptr_view = iLoadoutSlot;
|
||||
|
||||
pGetView->Execute(vstk_view, &view);
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
unsigned char vstk[sizeof(void *) * 2 + sizeof(int)];
|
||||
#else
|
||||
unsigned char vstk[sizeof(void *) * 2 + sizeof(int) + sizeof(float)];
|
||||
#endif
|
||||
unsigned char *vptr = vstk;
|
||||
|
||||
*(void **)vptr = info;
|
||||
vptr += sizeof(void *);
|
||||
*(CEconItemView **)vptr = view;
|
||||
vptr += sizeof(CEconItemView *);
|
||||
*(int *)vptr = 0;
|
||||
#if !defined(WIN32)
|
||||
vptr += sizeof(int);
|
||||
*(float *)vptr = 1.0;
|
||||
#endif
|
||||
|
||||
int price = 0;
|
||||
pWrapper->Execute(vstk, &price);
|
||||
#else
|
||||
if (g_iPriceOffset == -1)
|
||||
{
|
||||
if (!g_pGameConf->GetOffset("WeaponPrice", &g_iPriceOffset))
|
||||
@ -581,7 +445,6 @@ static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
|
||||
}
|
||||
|
||||
int price = *(int *)((intptr_t)info + g_iPriceOffset);
|
||||
#endif
|
||||
|
||||
if (params[3] || weaponNameOffset == -1)
|
||||
return price;
|
||||
@ -590,6 +453,80 @@ static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
return CallPriceForward(params[1], weapon_name, price);
|
||||
}
|
||||
#else
|
||||
static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CBaseEntity *pEntity;
|
||||
if (!(pEntity = GetCBaseEntity(params[1], true)))
|
||||
{
|
||||
return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
|
||||
}
|
||||
|
||||
if (!IsValidWeaponID(params[2]))
|
||||
return pContext->ThrowNativeError("Invalid WeaponID passed for this game");
|
||||
|
||||
static int iLoadoutSlotOffset = -1;
|
||||
|
||||
if (iLoadoutSlotOffset == -1)
|
||||
{
|
||||
if (!g_pGameConf->GetOffset("LoadoutSlotOffset", &iLoadoutSlotOffset) || iLoadoutSlotOffset == -1)
|
||||
{
|
||||
iLoadoutSlotOffset = -1;
|
||||
return pContext->ThrowNativeError("Failed to get LoadoutSlotOffset offset.");
|
||||
}
|
||||
}
|
||||
|
||||
if (g_iPriceOffset == -1)
|
||||
{
|
||||
if (!g_pGameConf->GetOffset("WeaponPrice", &g_iPriceOffset) || g_iPriceOffset == -1)
|
||||
{
|
||||
g_iPriceOffset = -1;
|
||||
return pContext->ThrowNativeError("Failed to get WeaponPrice offset");
|
||||
}
|
||||
}
|
||||
|
||||
int id = GetRealWeaponID(params[2]);
|
||||
|
||||
if (id == WEAPON_C4 || id == WEAPON_KNIFE || id == WEAPON_KNIFE_GG)
|
||||
return 0;
|
||||
else if (id == WEAPON_NIGHTVISION)
|
||||
return 1250;
|
||||
else if (id == WEAPON_DEFUSER)
|
||||
return 400;
|
||||
|
||||
char classname[128];
|
||||
|
||||
if (id < CSGOWeapon_KEVLAR)
|
||||
Q_snprintf(classname, sizeof(classname), "weapon_%s", WeaponIDToAlias(params[2]));
|
||||
else
|
||||
Q_snprintf(classname, sizeof(classname), "item_%s", WeaponIDToAlias(params[2]));
|
||||
|
||||
void *pDef = GetItemDefintionByName(classname);
|
||||
|
||||
int iLoadoutSlot = *(int *)((intptr_t)pDef + iLoadoutSlotOffset);
|
||||
|
||||
CEconItemView *pView = GetEconItemView(pEntity, iLoadoutSlot);
|
||||
|
||||
if (!pView)
|
||||
{
|
||||
return pContext->ThrowNativeError("Failed to get CEconItemVIiew for %s", classname);
|
||||
}
|
||||
|
||||
void *pWpnData = GetCCSWeaponData(pView);
|
||||
|
||||
if (!pWpnData)
|
||||
{
|
||||
return pContext->ThrowNativeError("Failed to get CCSWeaponData for %s", classname);
|
||||
}
|
||||
|
||||
int price = *(int *)((intptr_t)pWpnData + g_iPriceOffset);
|
||||
|
||||
if (params[3] || weaponNameOffset == -1)
|
||||
return price;
|
||||
|
||||
return CallPriceForward(params[1], WeaponIDToAlias(params[2]), price);
|
||||
}
|
||||
#endif
|
||||
|
||||
static cell_t CS_GetClientClanTag(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
@ -683,6 +620,10 @@ static cell_t CS_AliasToWeaponID(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
return SMCSWeapon_P250;
|
||||
}
|
||||
else if (strstr(weapon, "m4a1_silencer") != NULL)
|
||||
{
|
||||
return SMCSWeapon_M4A1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int id = GetFakeWeaponID(AliasToWeaponID(weapon));
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include "extension.h"
|
||||
#include "RegNatives.h"
|
||||
#include <iplayerinfo.h>
|
||||
|
||||
#define REGISTER_ADDR(name, defaultret, code) \
|
||||
void *addr; \
|
||||
@ -51,10 +52,205 @@
|
||||
return defaultret;\
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
|
||||
// Get a CEconItemView for the m4
|
||||
// Found in CCSPlayer::HandleCommand_Buy_Internal
|
||||
// Linux a1 - CCSPlayer *pEntity, v5 - Player Team, a3 - ItemLoadoutSlot -1 use default loadoutslot:
|
||||
// v4 = *(int (__cdecl **)(_DWORD, _DWORD, _DWORD))(*(_DWORD *)(a1 + 9492) + 36); // offset 9
|
||||
// v6 = v4(a1 + 9492, v5, a3);
|
||||
// Windows v5 - CCSPlayer *pEntity a4 - ItemLoadoutSlot -1 use default loadoutslot:
|
||||
// v8 = (*(int (__stdcall **)(_DWORD, int))(*(_DWORD *)(v5 + 9472) + 32))(*(_DWORD *)(v5 + 760), a4); // offset 8
|
||||
// The function is CCSPlayerInventory::GetItemInLoadout(int, int)
|
||||
// We can pass NULL view to the GetAttribute to use default loadoutslot.
|
||||
// We only really care about m4a1/m4a4 as price differs between them
|
||||
// thisPtrOffset = 9472/9492
|
||||
|
||||
CEconItemView *GetEconItemView(void *pEntity, int iSlot)
|
||||
{
|
||||
if (!pEntity)
|
||||
return NULL;
|
||||
|
||||
static ICallWrapper *pWrapper = NULL;
|
||||
static int thisPtrOffset = -1;
|
||||
|
||||
if (!pWrapper)
|
||||
{
|
||||
int offset = -1;
|
||||
int byteOffset = -1;
|
||||
void *pHandleCommandBuy = NULL;
|
||||
if (!g_pGameConf->GetOffset("GetItemInLoadout", &offset) || offset == -1)
|
||||
{
|
||||
smutils->LogError(myself, "Failed to get GetItemInLoadout offset.");
|
||||
return NULL;
|
||||
}
|
||||
else if (!g_pGameConf->GetOffset("CCSPlayerInventoryOffset", &byteOffset) || byteOffset == -1)
|
||||
{
|
||||
smutils->LogError(myself, "Failed to get CCSPlayerInventoryOffset offset.");
|
||||
return NULL;
|
||||
}
|
||||
else if (!g_pGameConf->GetMemSig("HandleCommand_Buy_Internal", &pHandleCommandBuy) || !pHandleCommandBuy)
|
||||
{
|
||||
smutils->LogError(myself, "Failed to get HandleCommand_Buy_Internal function.");
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
thisPtrOffset = *(int *)((intptr_t)pHandleCommandBuy + byteOffset);
|
||||
|
||||
PassInfo pass[2];
|
||||
PassInfo ret;
|
||||
pass[0].flags = PASSFLAG_BYVAL;
|
||||
pass[0].type = PassType_Basic;
|
||||
pass[0].size = sizeof(int);
|
||||
pass[1].flags = PASSFLAG_BYVAL;
|
||||
pass[1].type = PassType_Basic;
|
||||
pass[1].size = sizeof(int);
|
||||
|
||||
ret.flags = PASSFLAG_BYVAL;
|
||||
ret.type = PassType_Basic;
|
||||
ret.size = sizeof(CEconItemView *);
|
||||
|
||||
pWrapper = g_pBinTools->CreateVCall(offset, 0, 0, &ret, pass, 2);
|
||||
g_RegNatives.Register(pWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
int client = gamehelpers->EntityToBCompatRef(reinterpret_cast<CBaseEntity *>(pEntity));
|
||||
|
||||
IPlayerInfo *playerinfo = playerhelpers->GetGamePlayer(client)->GetPlayerInfo();
|
||||
|
||||
if (!playerinfo)
|
||||
return NULL;
|
||||
|
||||
int team = playerinfo->GetTeamIndex();
|
||||
|
||||
if (team != 2 && team != 3)
|
||||
return NULL;
|
||||
|
||||
CEconItemView *ret;
|
||||
unsigned char vstk[sizeof(void *) + sizeof(int) * 2];
|
||||
unsigned char *vptr = vstk;
|
||||
|
||||
*(void **)vptr = (void *)((intptr_t)pEntity + thisPtrOffset);
|
||||
vptr += sizeof(void *);
|
||||
*(int *)vptr = team;
|
||||
vptr += sizeof(int);
|
||||
*(int *)vptr = iSlot;
|
||||
|
||||
pWrapper->Execute(vstk, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *GetCCSWeaponData(CEconItemView *view)
|
||||
{
|
||||
static ICallWrapper *pWrapper = NULL;
|
||||
|
||||
if (!pWrapper)
|
||||
{
|
||||
REGISTER_ADDR("GetCCSWeaponData", NULL,
|
||||
PassInfo pass[1]; \
|
||||
PassInfo retpass; \
|
||||
pass[0].flags = PASSFLAG_BYVAL; \
|
||||
pass[0].type = PassType_Basic; \
|
||||
pass[0].size = sizeof(CEconItemView *); \
|
||||
retpass.flags = PASSFLAG_BYVAL; \
|
||||
retpass.type = PassType_Basic; \
|
||||
retpass.size = sizeof(void *); \
|
||||
pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, &retpass, pass, 1))
|
||||
}
|
||||
|
||||
unsigned char vstk[sizeof(const char *)];
|
||||
unsigned char *vptr = vstk;
|
||||
|
||||
*(CEconItemView **)vptr = view;
|
||||
|
||||
void *pDef = NULL;
|
||||
|
||||
pWrapper->Execute(vstk, &pDef);
|
||||
|
||||
return pDef;
|
||||
}
|
||||
|
||||
void *GetItemSchema()
|
||||
{
|
||||
static ICallWrapper *pWrapper = NULL;
|
||||
|
||||
if (!pWrapper)
|
||||
{
|
||||
REGISTER_ADDR("GetItemSchema", NULL,
|
||||
PassInfo retpass; \
|
||||
retpass.flags = PASSFLAG_BYVAL; \
|
||||
retpass.type = PassType_Basic; \
|
||||
retpass.size = sizeof(void *); \
|
||||
pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retpass, NULL, 0))
|
||||
}
|
||||
|
||||
void *pSchema = NULL;
|
||||
pWrapper->Execute(NULL, &pSchema);
|
||||
|
||||
//In windows this is actually ItemSystem() + 4 is ItemSchema
|
||||
#ifdef WIN32
|
||||
return (void *)((intptr_t)pSchema + 4);
|
||||
#else
|
||||
return pSchema;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *GetItemDefintionByName(const char *classname)
|
||||
{
|
||||
void *pSchema = GetItemSchema();
|
||||
|
||||
if (!pSchema)
|
||||
return NULL;
|
||||
|
||||
static ICallWrapper *pWrapper = NULL;
|
||||
|
||||
if (!pWrapper)
|
||||
{
|
||||
int offset = -1;
|
||||
|
||||
if (!g_pGameConf->GetOffset("GetItemDefintionByName", &offset) || offset == -1)
|
||||
{
|
||||
smutils->LogError(myself, "Failed to get GetItemDefintionByName offset.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PassInfo pass[1];
|
||||
PassInfo ret;
|
||||
pass[0].flags = PASSFLAG_BYVAL;
|
||||
pass[0].type = PassType_Basic;
|
||||
pass[0].size = sizeof(const char *);
|
||||
|
||||
ret.flags = PASSFLAG_BYVAL;
|
||||
ret.type = PassType_Basic;
|
||||
ret.size = sizeof(void *);
|
||||
|
||||
pWrapper = g_pBinTools->CreateVCall(offset, 0, 0, &ret, pass, 1);
|
||||
|
||||
g_RegNatives.Register(pWrapper);
|
||||
}
|
||||
|
||||
unsigned char vstk[sizeof(void *) + sizeof(const char *)];
|
||||
unsigned char *vptr = vstk;
|
||||
|
||||
*(void **)vptr = pSchema;
|
||||
vptr += sizeof(void *);
|
||||
*(const char **)vptr = classname;
|
||||
|
||||
void *pItemDef = NULL;
|
||||
pWrapper->Execute(vstk, &pItemDef);
|
||||
|
||||
return pItemDef;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
void *GetWeaponInfo(int weaponID)
|
||||
{
|
||||
void *info;
|
||||
#if SOURCE_ENGINE != SE_CSGO || !defined(WIN32)
|
||||
|
||||
static ICallWrapper *pWrapper = NULL;
|
||||
if (!pWrapper)
|
||||
{
|
||||
@ -77,30 +273,15 @@ void *GetWeaponInfo(int weaponID)
|
||||
|
||||
pWrapper->Execute(vstk, &info);
|
||||
|
||||
|
||||
#else
|
||||
static void *addr = NULL;
|
||||
|
||||
if(!addr)
|
||||
{
|
||||
GET_MEMSIG("GetWeaponInfo", 0);
|
||||
}
|
||||
|
||||
__asm
|
||||
{
|
||||
mov ecx, weaponID
|
||||
call addr
|
||||
mov info, eax
|
||||
}
|
||||
#endif
|
||||
return info;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *GetTranslatedWeaponAlias(const char *weapon)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
const char *alias = NULL;
|
||||
|
||||
#if SOURCE_ENGINE != SE_CSGO || !defined(WIN32)
|
||||
static ICallWrapper *pWrapper = NULL;
|
||||
|
||||
if (!pWrapper)
|
||||
@ -123,28 +304,42 @@ const char *GetTranslatedWeaponAlias(const char *weapon)
|
||||
*(const char **)vptr = weapon;
|
||||
|
||||
pWrapper->Execute(vstk, &alias);
|
||||
#else
|
||||
static void *addr = NULL;
|
||||
|
||||
if(!addr)
|
||||
{
|
||||
GET_MEMSIG("GetTranslatedWeaponAlias", weapon);
|
||||
}
|
||||
|
||||
__asm
|
||||
{
|
||||
mov ecx, weapon
|
||||
call addr
|
||||
mov alias, eax
|
||||
}
|
||||
#endif
|
||||
return alias;
|
||||
#else //this should work for both games maybe replace both?
|
||||
|
||||
static const char *szAliases[] =
|
||||
{
|
||||
"cv47", "ak47",
|
||||
"magnum", "awp",
|
||||
"d3au1", "g3sg1",
|
||||
"clarion", "famas",
|
||||
"bullpup", "aug",
|
||||
"9x19mm", "glock",
|
||||
"nighthawk", "deagle",
|
||||
"elites", "elite",
|
||||
"fn57", "fiveseven",
|
||||
"autoshotgun", "xm1014",
|
||||
"c90", "p90",
|
||||
"vest", "kevlar",
|
||||
"vesthelm", "assaultsuit",
|
||||
"nvgs", "nightvision"
|
||||
};
|
||||
|
||||
for (int i = 0; i < SM_ARRAYSIZE(szAliases)/2; i++)
|
||||
{
|
||||
if (stricmp(weapon, szAliases[i * 2]) == 0)
|
||||
return szAliases[i * 2 + 1];
|
||||
}
|
||||
|
||||
return weapon;
|
||||
#endif
|
||||
}
|
||||
|
||||
int AliasToWeaponID(const char *weapon)
|
||||
{
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
int weaponID = 0;
|
||||
#if SOURCE_ENGINE != SE_CSGO || !defined(WIN32)
|
||||
|
||||
static ICallWrapper *pWrapper = NULL;
|
||||
|
||||
if (!pWrapper)
|
||||
@ -167,28 +362,23 @@ int AliasToWeaponID(const char *weapon)
|
||||
*(const char **)vptr = weapon;
|
||||
|
||||
pWrapper->Execute(vstk, &weaponID);
|
||||
#else
|
||||
static void *addr = NULL;
|
||||
|
||||
if(!addr)
|
||||
{
|
||||
GET_MEMSIG("AliasToWeaponID", 0);
|
||||
}
|
||||
|
||||
__asm
|
||||
{
|
||||
mov ecx, weapon
|
||||
call addr
|
||||
mov weaponID, eax
|
||||
}
|
||||
#endif
|
||||
return weaponID;
|
||||
#else //this is horribly broken hackfix for now.
|
||||
for (unsigned int i = 0; i < SM_ARRAYSIZE(szWeaponInfo); i++)
|
||||
{
|
||||
if (stricmp(weapon, szWeaponInfo[i]) == 0)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *WeaponIDToAlias(int weaponID)
|
||||
{
|
||||
const char *alias = NULL;
|
||||
#if SOURCE_ENGINE != SE_CSGO || !defined(WIN32)
|
||||
const char *alias = NULL;
|
||||
|
||||
static ICallWrapper *pWrapper = NULL;
|
||||
|
||||
if (!pWrapper)
|
||||
@ -211,81 +401,19 @@ const char *WeaponIDToAlias(int weaponID)
|
||||
*(int *)vptr = GetRealWeaponID(weaponID);
|
||||
|
||||
pWrapper->Execute(vstk, &alias);
|
||||
#else
|
||||
static void *addr = NULL;
|
||||
|
||||
if(!addr)
|
||||
{
|
||||
GET_MEMSIG("WeaponIDToAlias", 0);
|
||||
}
|
||||
|
||||
int realWeaponID = GetRealWeaponID(weaponID);
|
||||
__asm
|
||||
{
|
||||
mov ecx, realWeaponID
|
||||
call addr
|
||||
mov alias, eax
|
||||
}
|
||||
#endif
|
||||
return alias;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
void *GetWeaponPriceFunction()
|
||||
{
|
||||
static void *pGetWeaponPriceAddress = nullptr;
|
||||
if (pGetWeaponPriceAddress)
|
||||
{
|
||||
return pGetWeaponPriceAddress;
|
||||
}
|
||||
|
||||
void *pAddress = nullptr;
|
||||
int offset = 0;
|
||||
int callOffset = 0;
|
||||
const char* byteCheck = nullptr;
|
||||
|
||||
if (!g_pGameConf->GetMemSig("GetWeaponPrice", &pAddress) || !pAddress)
|
||||
{
|
||||
g_pSM->LogError(myself, "Failed to get GetWeaponPrice address.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!g_pGameConf->GetOffset("GetWeaponPriceFunc", &offset))
|
||||
{
|
||||
// If no offset specified, assume that GetWeaponPrice is the func we want, and not just our
|
||||
// helper to find the real one.
|
||||
pGetWeaponPriceAddress = pAddress;
|
||||
return pGetWeaponPriceAddress;
|
||||
}
|
||||
|
||||
#if defined( _WIN32 )
|
||||
byteCheck = g_pGameConf->GetKeyValue("GetWeaponPriceByteCheck");
|
||||
#elif defined( _LINUX )
|
||||
byteCheck = g_pGameConf->GetKeyValue("GetWeaponPriceByteCheck_Linux");
|
||||
#else
|
||||
// We don't compile for csgo on mac anymore
|
||||
#error Unsupported platform
|
||||
int realID = GetRealWeaponID(weaponID);
|
||||
|
||||
if (realID < SM_ARRAYSIZE(szWeaponInfo) && realID > 0)
|
||||
return szWeaponInfo[realID];
|
||||
|
||||
return NULL;
|
||||
|
||||
#endif
|
||||
if (byteCheck == nullptr)
|
||||
{
|
||||
g_pSM->LogError(myself, "Failed to get GetWeaponPriceByteCheck keyvalue.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t iByte = strtoul(byteCheck, nullptr, 16);
|
||||
if (iByte != *(uint8_t *)((intptr_t)pAddress + (offset-1)))
|
||||
{
|
||||
g_pSM->LogError(myself, "GetWeaponPrice Byte check failed.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
callOffset = *(uint32_t *)((intptr_t)pAddress + offset);
|
||||
|
||||
pGetWeaponPriceAddress = (void *)((intptr_t)pAddress + offset + callOffset + sizeof(int));
|
||||
|
||||
return pGetWeaponPriceAddress;
|
||||
}
|
||||
#endif
|
||||
|
||||
int GetRealWeaponID(int weaponId)
|
||||
{
|
||||
|
@ -35,6 +35,69 @@
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
class CEconItemView;
|
||||
|
||||
CEconItemView *GetEconItemView(void *pEntity, int iSlot);
|
||||
void *GetCCSWeaponData(CEconItemView *view);
|
||||
void *GetItemSchema();
|
||||
void *GetItemDefintionByName(const char *classname);
|
||||
|
||||
static const char *szWeaponInfo[] =
|
||||
{
|
||||
"none",
|
||||
"deagle",
|
||||
"elite",
|
||||
"fiveseven",
|
||||
"glock",
|
||||
"p228",
|
||||
"usp",
|
||||
"ak47",
|
||||
"aug",
|
||||
"awp",
|
||||
"famas",
|
||||
"g3sg1",
|
||||
"galil",
|
||||
"galilar",
|
||||
"m249",
|
||||
"m3",
|
||||
"m4a1",
|
||||
"mac10",
|
||||
"mp5",
|
||||
"p90",
|
||||
"scout",
|
||||
"sg550",
|
||||
"sg552",
|
||||
"tmp",
|
||||
"ump45",
|
||||
"xm1014",
|
||||
"bizon",
|
||||
"mag7",
|
||||
"negev",
|
||||
"sawedoff",
|
||||
"tec9",
|
||||
"taser",
|
||||
"hkp2000",
|
||||
"mp7",
|
||||
"mp9",
|
||||
"nova",
|
||||
"p250",
|
||||
"scar17",
|
||||
"scar20",
|
||||
"sg556",
|
||||
"ssg08",
|
||||
"knifegg",
|
||||
"knife",
|
||||
"flashbang",
|
||||
"hegrenade",
|
||||
"smokegrenade",
|
||||
"molotov",
|
||||
"decoy",
|
||||
"incgrenade",
|
||||
"c4",
|
||||
"kevlar",
|
||||
"assaultsuit",
|
||||
"nvg",
|
||||
"defuser"
|
||||
};
|
||||
|
||||
enum CSGOWeapon
|
||||
{
|
||||
CSGOWeapon_NONE,
|
||||
@ -151,7 +214,10 @@ enum SMCSWeapon
|
||||
SMCSWeapon_INCGRENADE,
|
||||
SMCSWeapon_DEFUSER
|
||||
};
|
||||
|
||||
#if SOURCE_ENGINE != SE_CSGO
|
||||
void *GetWeaponInfo(int weaponID);
|
||||
#endif
|
||||
|
||||
const char *GetTranslatedWeaponAlias(const char *weapon);
|
||||
|
||||
@ -164,7 +230,4 @@ int GetRealWeaponID(int weaponId);
|
||||
int GetFakeWeaponID(int weaponId);
|
||||
|
||||
bool IsValidWeaponID(int weaponId);
|
||||
|
||||
void *GetWeaponPriceFunction();
|
||||
|
||||
#endif
|
||||
|
@ -13,26 +13,22 @@
|
||||
{
|
||||
"#default"
|
||||
{
|
||||
"Keys"
|
||||
{
|
||||
"GetWeaponPriceByteCheck" "E9"
|
||||
"GetWeaponPriceByteCheck_Linux" "E8"
|
||||
}
|
||||
"Offsets"
|
||||
{
|
||||
//Offset of szClassName in CCSWeaponInfo
|
||||
// Offset of szClassName in CCSWeaponData, szDefaultName is @ 140 which returns the default weapon class for the loadoutslot ignoring the users inventory.
|
||||
"WeaponName"
|
||||
{
|
||||
"windows" "6"
|
||||
"linux" "6"
|
||||
"mac" "6"
|
||||
"windows" "4"
|
||||
"linux" "4"
|
||||
"mac" "4"
|
||||
}
|
||||
//Econ update doesnt check this now but for what we use it hopefully its fine.
|
||||
// In HandleCommand_Buy_Internal
|
||||
// -*(_DWORD *)(v34 + 204)
|
||||
"WeaponPrice"
|
||||
{
|
||||
"windows" "2528"
|
||||
"linux" "2528"
|
||||
"mac" "2528"
|
||||
"windows" "204"
|
||||
"linux" "204"
|
||||
"mac" "204"
|
||||
}
|
||||
//Offset into CheckRestartRound
|
||||
"CTTeamScoreOffset"
|
||||
@ -67,20 +63,30 @@
|
||||
"linux" "9"
|
||||
"mac" "9"
|
||||
}
|
||||
"GetWeaponPriceFunc"
|
||||
"GetItemDefintionByName" //_ZN15CEconItemSchema23GetItemDefinitionByNameEPKc
|
||||
{
|
||||
"windows" "105"
|
||||
"linux" "152"
|
||||
"windows" "42"
|
||||
"linux" "41"
|
||||
"mac" "41"
|
||||
}
|
||||
//This is GetWeaponPriceFunc offset -1 (only used by GDC)
|
||||
"GetWeaponPriceFuncGDC"
|
||||
// Search for "%s (ID %llu) at backpack slot %d" (CCSPlayerInventory::DumpInventoryToConsole(bool))
|
||||
// Jump to the vtable 2 functions above calls CCStrike15ItemDefinition::GetLoadoutSlot(CCStrike15ItemDefinition *this, int)
|
||||
// This is an offset into CCStrike15ItemDefinition that contains the loadoutslot IGNORING the team param (the second param in the function)
|
||||
"LoadoutSlotOffset"
|
||||
{
|
||||
"windows" "104"
|
||||
"linux" "151"
|
||||
"windows" "588"
|
||||
"linux" "588"
|
||||
"mac" "588"
|
||||
}
|
||||
}
|
||||
"Signatures"
|
||||
{
|
||||
"GetItemSchema"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "\xA1\x2A\x2A\x2A\x2A\x85\xC0\x75\x2A\xA1\x2A\x2A\x2A\x2A\x56\x68\x2A\x2A\x00\x00\x8B"
|
||||
"linux" "\x55\x89\xE5\x83\xEC\x08\xE8\x2A\x2A\x2A\x2A\xC9\x83\xC0\x04\xC3"
|
||||
}
|
||||
"RoundRespawn"
|
||||
{
|
||||
"library" "server"
|
||||
@ -117,18 +123,6 @@
|
||||
"windows" "\x55\x8B\xEC\x83\xE4\xF8\x83\xEC\x2A\x53\x8B\xD9\xF3\x0F\x2A\x2A\x2A\x2A\x56\x57\x89\x2A\x2A\x2A\x83\xBB"
|
||||
"linux" "\x55\x89\xE5\x57\x56\x53\x81\xEC\xDC\x00\x00\x00\x8B\x75\x08\x8B\x86"
|
||||
}
|
||||
"GetTranslatedWeaponAlias"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "\x56\x57\x8B\xF9\x33\xF6\x66\x66\x0F\x1F\x84\x00\x00\x00\x00\x00\x8B\x0C\xF5\x2A\x2A\x2A\x2A\x8B\xD7\xE8\x2A\x2A\x2A\x2A\x85\xC0\x74\x2A\x46\x83\xFE\x19"
|
||||
"linux" "\x55\x89\xE5\x56\x53\x31\xDB\x83\xEC\x10\x8B\x75\x08\xEB\x2A\x90\x83\xC3\x01\x83\xFB\x19"
|
||||
}
|
||||
"GetWeaponInfo"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x08\x33\xC0\x85\xC9"
|
||||
"linux" "\x55\x89\xE5\x56\x53\x31\xDB\x83\xEC\x10\x8B\x55\x08\x85\xD2"
|
||||
}
|
||||
//In CS:GO this is actually CCSGameRules::CheckRestartRound(void) but to keep same gamedata as cs:s.
|
||||
"CheckWinLimit"
|
||||
{
|
||||
@ -136,38 +130,25 @@
|
||||
"windows" "\x55\x8B\xEC\x83\xE4\xF8\x83\xEC\x2A\x53\x56\x57\x8B\xF9\x8B\x0D\x2A\x2A\x2A\x2A\x81\xF9"
|
||||
"linux" "\x55\x89\xE5\x56\x53\x83\xEC\x70\xA1\x2A\x2A\x2A\x2A\x8B\x35\x2A\x2A\x2A\x2A\x8B"
|
||||
}
|
||||
"AliasToWeaponID"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "\x57\x8B\xF9\x85\xFF\x75\x2A\x33\xC0\x5F\xC3\x56\x33\xF6\x66\x90\x6A\x5F"
|
||||
"linux" "\x55\x31\xC0\x89\xE5\x56\x53\x83\xEC\x10\x8B\x75\x08\x85\xF6\x74\x2A\x31\xDB\xEB\x2A\x8D"
|
||||
}
|
||||
"WeaponIDToAlias"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "\x33\xC0\x39\x0C\xC5\x2A\x2A\x2A\x2A\x74\x2A\x40\x83\xF8\x3E\x72\x2A\x33\xC0\xC3\x6A\x5F"
|
||||
"linux" "\x55\x89\xE5\x83\xEC\x18\x8B\x55\x08\x39\x15\x2A\x2A\x2A\x2A\x74"
|
||||
}
|
||||
"SetClanTag"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "\x55\x8B\xEC\x8B\x55\x08\x85\xD2\x74\x2A\x8D\x81\x34\x25\x00\x00"
|
||||
"linux" "\x55\x89\xE5\x83\xEC\x18\x8B\x45\x0C\x85\xC0\x74\x2A\x89\x44\x24\x04\x8B\x45\x08\xC7\x44\x24\x08\x10\x00\x00\x00"
|
||||
}
|
||||
// Since it's not possible to make a unique signature for CCSWeaponInfo::GetWeaponInfo, this is instead a signature to a
|
||||
// function that calls it. The offset from the signature to the CCSWeaponInfo func offset is the GetWeaponPriceFunc offset.
|
||||
"GetWeaponPrice"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "\x55\x8B\xEC\x8B\xD1\x8B\x4D\x08\x85\xC9\x75\x2A\x83\xC8\xFF"
|
||||
"linux" "\x55\x89\xE5\x83\xEC\x18\x89\x5D\xF8\x8B\x5D\x10\x89\x75\xFC\x8B\x4D\x08"
|
||||
}
|
||||
"SetModelFromClass"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "\x53\x56\x57\x8B\xF9\x8B\x87\x00\x03\x00\x00"
|
||||
"linux" "\x55\x89\xE5\x83\xEC\x28\x89\x5D\xF4\x8B\x5D\x08\x89\x75\xF8\x89\x7D\xFC\x89\x1C\x24\xE8\x2A\x2A\x2A\x2A\x83\xF8\x02"
|
||||
}
|
||||
//GetCCSWeaponData Found in HandleCommand_Buy_Internal
|
||||
"GetCCSWeaponData"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "\x85\xC9\x75\x2A\x33\xC0\xC3\xE8\x2A\x2A\x2A\x2A\x8B"
|
||||
"linux" "\x55\x89\xE5\x83\xEC\x18\x8B\x45\x08\x85\xC0\x74\x2A\x89\x04\x24"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user