Permalink
Browse files

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

  • Loading branch information...
1 parent 6b24e92 commit 5642e4b9eef0528c85b63c3ffd6087d1da24805b @psychonic psychonic committed Nov 29, 2016
Showing with 61 additions and 59 deletions.
  1. +14 −24 extensions/cstrike/natives.cpp
  2. +42 −34 extensions/cstrike/util_cstrike.cpp
  3. +5 −1 gamedata/sm-cstrike.games/game.csgo.txt
@@ -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,40 +474,31 @@ 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;
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, 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:
@@ -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;
-
- if(!g_pGameConf->GetMemSig("GetWeaponPrice", &pAddress) || pAddress == NULL)
- {
- g_pSM->LogError(myself, "Failed to get GetWeaponPrice address.");
- return NULL;
- }
+ return pGetWeaponPriceAddress;
+ }
- if(!g_pGameConf->GetOffset("GetWeaponPriceFunc", &offset))
- {
- g_pSM->LogError(myself, "Failed to get GetWeaponPriceFunc offset.");
- return NULL;
- }
+ void *pAddress = nullptr;
+ int offset = 0;
+ int callOffset = 0;
+ 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)
- {
- g_pSM->LogError(myself, "Failed to get GetWeaponPriceByteCheck keyvalue.");
- return NULL;
- }
+ 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;
+ }
- 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)))
- {
- g_pSM->LogError(myself, "GetWeaponPrice Byte check failed.");
- return NULL;
- }
+ 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);
+ 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;
}
@@ -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"

0 comments on commit 5642e4b

Please sign in to comment.