Fix CS_GetWeaponPrice returning incorrect value for M4A1 in CS:GO

--HG--
extra : amend_source : b4fa218795b59a82f98c0c8142e3bf36161f88d6
This commit is contained in:
Ruben Gonzalez 2014-02-12 19:03:14 -05:00
parent c5f496670d
commit 162c69bfda
3 changed files with 101 additions and 10 deletions

View File

@ -52,6 +52,7 @@ int CallPriceForward(int client, const char *weapon_name, int price);
#define WEAPON_ASSAULTSUIT 51
#define WEAPON_NIGHTVISION 52
#define WEAPON_DEFUSER 53
#define WEAPON_M4 16
#else
#define WEAPON_C4 6
#define WEAPON_KNIFE 28

View File

@ -34,6 +34,7 @@
#include "forwards.h"
#include "util_cstrike.h"
#include <server_class.h>
#include <iplayerinfo.h>
int g_iPriceOffset = -1;
@ -426,6 +427,11 @@ static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Failed to get weaponinfo");
}
CBaseEntity *pEntity;
if (!(pEntity = GetCBaseEntity(params[1], true)))
{
return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
}
#if SOURCE_ENGINE == SE_CSGO
static ICallWrapper *pWrapper = NULL;
@ -446,14 +452,91 @@ static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, &ret, pass, 2))
}
// 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 *);
g_RegNatives.Register(pGetView);
pGetView = g_pBinTools->CreateVCall(offset, 0, 0, &ret, pass, 2);
}
}
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);
}
unsigned char vstk[sizeof(void *) * 2 + sizeof(char *)];
unsigned char *vptr = vstk;
*(void **)vptr = info;
vptr += sizeof(void *);
*(const char **)vptr = "in game price";
vptr += sizeof(const char **);
*(CEconItemView **)vptr = NULL;
vptr += sizeof(const char *);
*(CEconItemView **)vptr = view;
int price = 0;
pWrapper->Execute(vstk, &price);
@ -470,12 +553,6 @@ static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
int price = *(int *)((intptr_t)info + g_iPriceOffset);
#endif
CBaseEntity *pEntity;
if (!(pEntity = GetCBaseEntity(params[1], true)))
{
return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
}
if (params[3] || weaponNameOffset == -1)
return price;

View File

@ -49,6 +49,19 @@
"linux" "41"
"mac" "22"
}
//Offset into HandleCommand_Buy_Internal
"CCSPlayerInventoryOffset"
{
"windows" "285"
"linux" "87"
"mac" "109"
}
"GetItemInLoadout"
{
"windows" "8"
"linux" "9"
"mac" "9"
}
}
"Signatures"
{
@ -66,10 +79,10 @@
"linux" "@_ZN9CCSPlayer10SwitchTeamEi"
"mac" "@_ZN9CCSPlayer10SwitchTeamEi"
}
"HandleCommand_Buy_Internal"
"HandleCommand_Buy_Internal"//Wildcard first 6 bytes for getting address for weapon price.
{
"library" "server"
"windows" "\x55\x8B\xEC\x83\xE4\x2A\x81\xEC\x2A\x2A\x2A\x2A\x83\x3D\x2A\x2A\x2A\x2A\x00\x53\x56\x57\x8B\xF9"
"windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x81\xEC\x2A\x2A\x2A\x2A\x83\x3D\x2A\x2A\x2A\x2A\x00\x53\x56\x57\x8B\xF9"
"linux" "@_ZN9CCSPlayer26HandleCommand_Buy_InternalEPKcib"
"mac" "@_ZN9CCSPlayer26HandleCommand_Buy_InternalEPKcib"
}