Semi-tested fix for CS:GO GetWeaponPrice on Linux.

This commit is contained in:
Nicholas Hastings 2016-11-29 10:42:05 -05:00
parent 90cefa9daf
commit c4487b74ee
3 changed files with 61 additions and 59 deletions

View File

@ -466,7 +466,6 @@ static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
#if SOURCE_ENGINE == SE_CSGO
static ICallWrapper *pWrapper = NULL;
#if defined(WIN32)
if(!pWrapper)
{
void *pGetWeaponPrice = GetWeaponPriceFunction();
@ -475,7 +474,13 @@ static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Failed to locate function");
}
PassInfo pass[2];
#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;
@ -483,32 +488,17 @@ static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
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, 2);
pWrapper = g_pBinTools->CreateCall(pGetWeaponPrice, CallConv_ThisCall, &ret, pass, GWP_ARGC);
}
#else
if (!pWrapper)
{
REGISTER_NATIVE_ADDR("GetWeaponPrice",
PassInfo pass[3]; \
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); \
pass[2].flags = PASSFLAG_BYVAL; \
pass[2].type = PassType_Float; \
pass[2].size = sizeof(float); \
ret.flags = PASSFLAG_BYVAL; \
ret.type = PassType_Basic; \
ret.size = sizeof(int); \
pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, &ret, pass, 3))
}
#endif
// 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:

View File

@ -230,50 +230,58 @@ const char *WeaponIDToAlias(int weaponID)
return alias;
}
#if SOURCE_ENGINE == SE_CSGO && defined(WIN32)
#if SOURCE_ENGINE == SE_CSGO
void *GetWeaponPriceFunction()
{
static void *pGetWeaponPriceAddress = NULL;
if(pGetWeaponPriceAddress == NULL)
static void *pGetWeaponPriceAddress = nullptr;
if (pGetWeaponPriceAddress)
{
void *pAddress = NULL;
int offset = 0;
int callOffset = 0;
const char* byteCheck = NULL;
return pGetWeaponPriceAddress;
}
if(!g_pGameConf->GetMemSig("GetWeaponPrice", &pAddress) || pAddress == NULL)
{
g_pSM->LogError(myself, "Failed to get GetWeaponPrice address.");
return NULL;
}
void *pAddress = nullptr;
int offset = 0;
int callOffset = 0;
const char* byteCheck = nullptr;
if(!g_pGameConf->GetOffset("GetWeaponPriceFunc", &offset))
{
g_pSM->LogError(myself, "Failed to get GetWeaponPriceFunc offset.");
return NULL;
}
if (!g_pGameConf->GetMemSig("GetWeaponPrice", &pAddress) || !pAddress)
{
g_pSM->LogError(myself, "Failed to get GetWeaponPrice address.");
return nullptr;
}
byteCheck = g_pGameConf->GetKeyValue("GetWeaponPriceByteCheck");
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(byteCheck == NULL)
{
g_pSM->LogError(myself, "Failed to get GetWeaponPriceByteCheck keyvalue.");
return NULL;
}
#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
#endif
if (byteCheck == nullptr)
{
g_pSM->LogError(myself, "Failed to get GetWeaponPriceByteCheck keyvalue.");
return nullptr;
}
uint8_t iByte = strtoul(byteCheck, NULL, 16);
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;
}
if(iByte != *(uint8_t *)((intptr_t)pAddress + (offset-1)))
{
g_pSM->LogError(myself, "GetWeaponPrice Byte check failed.");
return NULL;
}
callOffset = *(uint32_t *)((intptr_t)pAddress + offset);
callOffset = *(uint32_t *)((intptr_t)pAddress + offset);
pGetWeaponPriceAddress = (void *)((intptr_t)pAddress + offset + callOffset + sizeof(int));
}
pGetWeaponPriceAddress = (void *)((intptr_t)pAddress + offset + callOffset + sizeof(int));
return pGetWeaponPriceAddress;
}

View File

@ -16,6 +16,7 @@
"Keys"
{
"GetWeaponPriceByteCheck" "E9"
"GetWeaponPriceByteCheck_Linux" "E8"
}
"Offsets"
{
@ -69,11 +70,13 @@
"GetWeaponPriceFunc"
{
"windows" "98"
"linux" "139"
}
//This is GetWeaponPriceFunc offset -1 (only used by GDC)
"GetWeaponPriceFuncGDC"
{
"windows" "97"
"windows" "138"
}
}
"Signatures"
@ -145,7 +148,8 @@
"windows" "\x55\x8B\xEC\x8B\x55\x08\x85\xD2\x74\x28\x8D\x81\x2A\x2A\x2A\x2A\x56\x8D\x70\x0F\x3B\xC6\x73\x16\x2B\xD0\x8D"
"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"
}
//In windows this is CCSPlayer::GetWeaponPrice NOT CCSWeaponInfo::GetWeaponPrice
// 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"