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 #if SOURCE_ENGINE == SE_CSGO
static ICallWrapper *pWrapper = NULL; static ICallWrapper *pWrapper = NULL;
#if defined(WIN32)
if(!pWrapper) if(!pWrapper)
{ {
void *pGetWeaponPrice = GetWeaponPriceFunction(); 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"); 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; PassInfo ret;
pass[0].flags = PASSFLAG_BYVAL; pass[0].flags = PASSFLAG_BYVAL;
pass[0].type = PassType_Basic; 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].flags = PASSFLAG_BYVAL;
pass[1].type = PassType_Basic; pass[1].type = PassType_Basic;
pass[1].size = sizeof(int); 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.flags = PASSFLAG_BYVAL;
ret.type = PassType_Basic; ret.type = PassType_Basic;
ret.size = sizeof(int); 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 // Get a CEconItemView for the m4
// Found in CCSPlayer::HandleCommand_Buy_Internal // Found in CCSPlayer::HandleCommand_Buy_Internal
// Linux a1 - CCSPlayer *pEntity, v5 - Player Team, a3 - ItemLoadoutSlot -1 use default loadoutslot: // 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; return alias;
} }
#if SOURCE_ENGINE == SE_CSGO && defined(WIN32) #if SOURCE_ENGINE == SE_CSGO
void *GetWeaponPriceFunction() void *GetWeaponPriceFunction()
{ {
static void *pGetWeaponPriceAddress = NULL; static void *pGetWeaponPriceAddress = nullptr;
if (pGetWeaponPriceAddress)
if(pGetWeaponPriceAddress == NULL)
{ {
void *pAddress = NULL; return pGetWeaponPriceAddress;
}
void *pAddress = nullptr;
int offset = 0; int offset = 0;
int callOffset = 0; int callOffset = 0;
const char* byteCheck = NULL; const char* byteCheck = nullptr;
if(!g_pGameConf->GetMemSig("GetWeaponPrice", &pAddress) || pAddress == NULL) if (!g_pGameConf->GetMemSig("GetWeaponPrice", &pAddress) || !pAddress)
{ {
g_pSM->LogError(myself, "Failed to get GetWeaponPrice address."); g_pSM->LogError(myself, "Failed to get GetWeaponPrice address.");
return NULL; return nullptr;
} }
if (!g_pGameConf->GetOffset("GetWeaponPriceFunc", &offset)) if (!g_pGameConf->GetOffset("GetWeaponPriceFunc", &offset))
{ {
g_pSM->LogError(myself, "Failed to get GetWeaponPriceFunc offset."); // If no offset specified, assume that GetWeaponPrice is the func we want, and not just our
return NULL; // helper to find the real one.
pGetWeaponPriceAddress = pAddress;
return pGetWeaponPriceAddress;
} }
#if defined( _WIN32 )
byteCheck = g_pGameConf->GetKeyValue("GetWeaponPriceByteCheck"); byteCheck = g_pGameConf->GetKeyValue("GetWeaponPriceByteCheck");
#elif defined( _LINUX )
if(byteCheck == NULL) 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."); g_pSM->LogError(myself, "Failed to get GetWeaponPriceByteCheck keyvalue.");
return NULL; 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))) if (iByte != *(uint8_t *)((intptr_t)pAddress + (offset-1)))
{ {
g_pSM->LogError(myself, "GetWeaponPrice Byte check failed."); g_pSM->LogError(myself, "GetWeaponPrice Byte check failed.");
return NULL; return nullptr;
} }
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; return pGetWeaponPriceAddress;
} }

View File

@ -16,6 +16,7 @@
"Keys" "Keys"
{ {
"GetWeaponPriceByteCheck" "E9" "GetWeaponPriceByteCheck" "E9"
"GetWeaponPriceByteCheck_Linux" "E8"
} }
"Offsets" "Offsets"
{ {
@ -69,11 +70,13 @@
"GetWeaponPriceFunc" "GetWeaponPriceFunc"
{ {
"windows" "98" "windows" "98"
"linux" "139"
} }
//This is GetWeaponPriceFunc offset -1 (only used by GDC) //This is GetWeaponPriceFunc offset -1 (only used by GDC)
"GetWeaponPriceFuncGDC" "GetWeaponPriceFuncGDC"
{ {
"windows" "97" "windows" "97"
"windows" "138"
} }
} }
"Signatures" "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" "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" "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" "GetWeaponPrice"
{ {
"library" "server" "library" "server"