Skip to content

Commit

Permalink
Semi-tested fix for CS:GO GetWeaponPrice on Linux.
Browse files Browse the repository at this point in the history
  • Loading branch information
psychonic committed Nov 29, 2016
1 parent 6b24e92 commit 5642e4b
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 59 deletions.
38 changes: 14 additions & 24 deletions extensions/cstrike/natives.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -475,40 +474,31 @@ 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;
pass[0].size = sizeof(CEconItemView *); pass[0].size = sizeof(CEconItemView *);
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:
Expand Down
76 changes: 42 additions & 34 deletions extensions/cstrike/util_cstrike.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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;
int offset = 0; }
int callOffset = 0;
const char* byteCheck = NULL;

if(!g_pGameConf->GetMemSig("GetWeaponPrice", &pAddress) || pAddress == NULL)
{
g_pSM->LogError(myself, "Failed to get GetWeaponPrice address.");
return NULL;
}


if(!g_pGameConf->GetOffset("GetWeaponPriceFunc", &offset)) void *pAddress = nullptr;
{ int offset = 0;
g_pSM->LogError(myself, "Failed to get GetWeaponPriceFunc offset."); int callOffset = 0;
return NULL; const char* byteCheck = nullptr;
}


byteCheck = g_pGameConf->GetKeyValue("GetWeaponPriceByteCheck"); if (!g_pGameConf->GetMemSig("GetWeaponPrice", &pAddress) || !pAddress)
{
g_pSM->LogError(myself, "Failed to get GetWeaponPrice address.");
return nullptr;
}


if(byteCheck == NULL) if (!g_pGameConf->GetOffset("GetWeaponPriceFunc", &offset))
{ {
g_pSM->LogError(myself, "Failed to get GetWeaponPriceByteCheck keyvalue."); // 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;
}


uint8_t iByte = strtoul(byteCheck, NULL, 16); #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;
}


if(iByte != *(uint8_t *)((intptr_t)pAddress + (offset-1))) 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 NULL; g_pSM->LogError(myself, "GetWeaponPrice Byte check failed.");
} 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;
} }
Expand Down
6 changes: 5 additions & 1 deletion gamedata/sm-cstrike.games/game.csgo.txt
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"Keys" "Keys"
{ {
"GetWeaponPriceByteCheck" "E9" "GetWeaponPriceByteCheck" "E9"
"GetWeaponPriceByteCheck_Linux" "E8"
} }
"Offsets" "Offsets"
{ {
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down

0 comments on commit 5642e4b

Please sign in to comment.