Merge pull request #258 from alliedmodders/weaponprice-fix-wip
Fix GetWeaponPrice for CS:GO
This commit is contained in:
commit
cf9dd08c45
@ -61,9 +61,21 @@ DETOUR_DECL_MEMBER1(DetourHandleBuy, int, const char *, weapon)
|
|||||||
|
|
||||||
#if SOURCE_ENGINE != SE_CSGO
|
#if SOURCE_ENGINE != SE_CSGO
|
||||||
DETOUR_DECL_MEMBER0(DetourWeaponPrice, int)
|
DETOUR_DECL_MEMBER0(DetourWeaponPrice, int)
|
||||||
|
#elif defined(WIN32)
|
||||||
|
DETOUR_DECL_MEMBER2(DetourWeaponPrice, int, CEconItemView *, pEconItem, int, iUnknown)
|
||||||
|
#else
|
||||||
|
DETOUR_DECL_MEMBER3(DetourWeaponPrice, int, CEconItemView *, pEconItem, int, iUnknown, float, fUnknown)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
int price = DETOUR_MEMBER_CALL(DetourWeaponPrice)();
|
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE != SE_CSGO
|
||||||
|
int price = DETOUR_MEMBER_CALL(DetourWeaponPrice)();
|
||||||
|
#elif defined(WIN32)
|
||||||
|
int price = DETOUR_MEMBER_CALL(DetourWeaponPrice)(pEconItem, iUnknown);
|
||||||
|
#else
|
||||||
|
int price = DETOUR_MEMBER_CALL(DetourWeaponPrice)(pEconItem, iUnknown, fUnknown);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (lastclient == -1)
|
if (lastclient == -1)
|
||||||
return price;
|
return price;
|
||||||
|
|
||||||
@ -71,19 +83,6 @@ DETOUR_DECL_MEMBER0(DetourWeaponPrice, int)
|
|||||||
|
|
||||||
return CallPriceForward(lastclient, weapon_name, price);
|
return CallPriceForward(lastclient, weapon_name, price);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
DETOUR_DECL_MEMBER2(DetourWeaponPrice, int, const char *, szAttribute, CEconItemView *, pEconItem)
|
|
||||||
{
|
|
||||||
int price = DETOUR_MEMBER_CALL(DetourWeaponPrice)(szAttribute, pEconItem);
|
|
||||||
|
|
||||||
if(lastclient == -1 || strcmp(szAttribute, "in game price") != 0)
|
|
||||||
return price;
|
|
||||||
|
|
||||||
const char *weapon_name = reinterpret_cast<char *>(this+weaponNameOffset);
|
|
||||||
|
|
||||||
return CallPriceForward(lastclient, weapon_name, price);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if SOURCE_ENGINE != SE_CSGO || !defined(WIN32)
|
#if SOURCE_ENGINE != SE_CSGO || !defined(WIN32)
|
||||||
DETOUR_DECL_MEMBER2(DetourTerminateRound, void, float, delay, int, reason)
|
DETOUR_DECL_MEMBER2(DetourTerminateRound, void, float, delay, int, reason)
|
||||||
@ -201,8 +200,15 @@ bool CreateWeaponPriceDetour()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO && defined(WIN32)
|
||||||
DWeaponPrice = DETOUR_CREATE_MEMBER(DetourWeaponPrice, "GetAttributeInt");
|
void *pGetWeaponPriceAddress = GetWeaponPriceFunction();
|
||||||
|
|
||||||
|
if(!pGetWeaponPriceAddress)
|
||||||
|
{
|
||||||
|
g_pSM->LogError(myself, "GetWeaponPrice detour could not be initialized - Disabled OnGetWeaponPrice forward.");
|
||||||
|
}
|
||||||
|
|
||||||
|
DWeaponPrice = DETOUR_CREATE_MEMBER(DetourWeaponPrice, pGetWeaponPriceAddress);
|
||||||
#else
|
#else
|
||||||
DWeaponPrice = DETOUR_CREATE_MEMBER(DetourWeaponPrice, "GetWeaponPrice");
|
DWeaponPrice = DETOUR_CREATE_MEMBER(DetourWeaponPrice, "GetWeaponPrice");
|
||||||
#endif
|
#endif
|
||||||
|
@ -419,6 +419,7 @@ static cell_t CS_GetTranslatedWeaponAlias(IPluginContext *pContext, const cell_t
|
|||||||
|
|
||||||
static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
|
static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!IsValidWeaponID(params[2]))
|
if (!IsValidWeaponID(params[2]))
|
||||||
return pContext->ThrowNativeError("Invalid WeaponID passed for this game");
|
return pContext->ThrowNativeError("Invalid WeaponID passed for this game");
|
||||||
|
|
||||||
@ -426,6 +427,7 @@ static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
|
|||||||
|
|
||||||
//Hard code return values for weapons that dont call GetWeaponPrice and always use default value.
|
//Hard code return values for weapons that dont call GetWeaponPrice and always use default value.
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
|
|
||||||
if (id == WEAPON_C4 || id == WEAPON_KNIFE || id == WEAPON_KNIFE_GG)
|
if (id == WEAPON_C4 || id == WEAPON_KNIFE || id == WEAPON_KNIFE_GG)
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
@ -458,23 +460,49 @@ 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)
|
||||||
|
{
|
||||||
|
void *pGetWeaponPrice = GetWeaponPriceFunction();
|
||||||
|
if(!pGetWeaponPrice)
|
||||||
|
{
|
||||||
|
return pContext->ThrowNativeError("Failed to locate function");
|
||||||
|
}
|
||||||
|
|
||||||
|
PassInfo pass[2];
|
||||||
|
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);
|
||||||
|
ret.flags = PASSFLAG_BYVAL;
|
||||||
|
ret.type = PassType_Basic;
|
||||||
|
ret.size = sizeof(int);
|
||||||
|
pWrapper = g_pBinTools->CreateCall(pGetWeaponPrice, CallConv_ThisCall, &ret, pass, 2);
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (!pWrapper)
|
if (!pWrapper)
|
||||||
{
|
{
|
||||||
REGISTER_NATIVE_ADDR("GetAttributeInt",
|
REGISTER_NATIVE_ADDR("GetWeaponPrice",
|
||||||
PassInfo pass[2]; \
|
PassInfo pass[3]; \
|
||||||
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(char *); \
|
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(CEconItemView *); \
|
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.flags = PASSFLAG_BYVAL; \
|
||||||
ret.type = PassType_Basic; \
|
ret.type = PassType_Basic; \
|
||||||
ret.size = sizeof(int); \
|
ret.size = sizeof(int); \
|
||||||
pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, &ret, pass, 2))
|
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:
|
||||||
@ -552,14 +580,22 @@ static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
|
|||||||
pGetView->Execute(vstk_view, &view);
|
pGetView->Execute(vstk_view, &view);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char vstk[sizeof(void *) * 2 + sizeof(char *)];
|
#if defined(WIN32)
|
||||||
|
unsigned char vstk[sizeof(void *) * 2 + sizeof(int)];
|
||||||
|
#else
|
||||||
|
unsigned char vstk[sizeof(void *) * 2 + sizeof(int) + sizeof(float)];
|
||||||
|
#endif
|
||||||
unsigned char *vptr = vstk;
|
unsigned char *vptr = vstk;
|
||||||
|
|
||||||
*(void **)vptr = info;
|
*(void **)vptr = info;
|
||||||
vptr += sizeof(void *);
|
vptr += sizeof(void *);
|
||||||
*(const char **)vptr = "in game price";
|
|
||||||
vptr += sizeof(const char *);
|
|
||||||
*(CEconItemView **)vptr = view;
|
*(CEconItemView **)vptr = view;
|
||||||
|
vptr += sizeof(CEconItemView *);
|
||||||
|
*(int *)vptr = 0;
|
||||||
|
#if !defined(WIN32)
|
||||||
|
vptr += sizeof(int);
|
||||||
|
*(float *)vptr = 1.0;
|
||||||
|
#endif
|
||||||
|
|
||||||
int price = 0;
|
int price = 0;
|
||||||
pWrapper->Execute(vstk, &price);
|
pWrapper->Execute(vstk, &price);
|
||||||
|
@ -229,6 +229,56 @@ const char *WeaponIDToAlias(int weaponID)
|
|||||||
#endif
|
#endif
|
||||||
return alias;
|
return alias;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SOURCE_ENGINE == SE_CSGO && defined(WIN32)
|
||||||
|
void *GetWeaponPriceFunction()
|
||||||
|
{
|
||||||
|
static void *pGetWeaponPriceAddress = NULL;
|
||||||
|
|
||||||
|
if(pGetWeaponPriceAddress == NULL)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!g_pGameConf->GetOffset("GetWeaponPriceFunc", &offset))
|
||||||
|
{
|
||||||
|
g_pSM->LogError(myself, "Failed to get GetWeaponPriceFunc offset.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
byteCheck = g_pGameConf->GetKeyValue("GetWeaponPriceByteCheck");
|
||||||
|
|
||||||
|
if(byteCheck == NULL)
|
||||||
|
{
|
||||||
|
g_pSM->LogError(myself, "Failed to get GetWeaponPriceByteCheck keyvalue.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t iByte = strtoul(byteCheck, NULL, 16);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
pGetWeaponPriceAddress = (void *)((intptr_t)pAddress + offset + callOffset + sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pGetWeaponPriceAddress;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int GetRealWeaponID(int weaponId)
|
int GetRealWeaponID(int weaponId)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
|
@ -165,4 +165,6 @@ int GetFakeWeaponID(int weaponId);
|
|||||||
|
|
||||||
bool IsValidWeaponID(int weaponId);
|
bool IsValidWeaponID(int weaponId);
|
||||||
|
|
||||||
|
void *GetWeaponPriceFunction();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -13,6 +13,10 @@
|
|||||||
{
|
{
|
||||||
"csgo"
|
"csgo"
|
||||||
{
|
{
|
||||||
|
"Keys"
|
||||||
|
{
|
||||||
|
"GetWeaponPriceByteCheck" "E9"
|
||||||
|
}
|
||||||
"Offsets"
|
"Offsets"
|
||||||
{
|
{
|
||||||
//Offset of szClassName in CCSWeaponInfo
|
//Offset of szClassName in CCSWeaponInfo
|
||||||
@ -62,6 +66,15 @@
|
|||||||
"linux" "9"
|
"linux" "9"
|
||||||
"mac" "9"
|
"mac" "9"
|
||||||
}
|
}
|
||||||
|
"GetWeaponPriceFunc"
|
||||||
|
{
|
||||||
|
"windows" "84"
|
||||||
|
}
|
||||||
|
//This is GetWeaponPriceFunc offset -1 (only used by GDC)
|
||||||
|
"GetWeaponPriceFuncGDC"
|
||||||
|
{
|
||||||
|
"windows" "83"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"Signatures"
|
"Signatures"
|
||||||
{
|
{
|
||||||
@ -143,13 +156,13 @@
|
|||||||
"linux" "@_ZN9CCSPlayer10SetClanTagEPKc"
|
"linux" "@_ZN9CCSPlayer10SetClanTagEPKc"
|
||||||
"mac" "@_ZN9CCSPlayer10SetClanTagEPKc"
|
"mac" "@_ZN9CCSPlayer10SetClanTagEPKc"
|
||||||
}
|
}
|
||||||
//Wild card first 6 bytes since we call it and detour it.
|
//In windows this is CCSPlayer::GetWeaponPrice NOT CCSWeaponInfo::GetWeaponPrice
|
||||||
"GetAttributeInt"
|
"GetWeaponPrice"
|
||||||
{
|
{
|
||||||
"library" "server"
|
"library" "server"
|
||||||
"windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x83\xEC\x1C\x53\x8B\x5D\x0C\xC7\x44\x24\x04\x00\x00\x00\x00\x56\x8B\xF1\x89\x74\x24\x0C\x57\x8B\x7D\x08\x85\xDB\x74\x2A\x80\x7B\x2A\x2A\x74\x2A\xE8\x2A\x2A\x2A\x2A\x57"
|
"windows" "\x55\x8B\xEC\x8B\xD1\x8B\x4D\x08\x83\xF9\x33\x75\x2A\x83\xBA"
|
||||||
"linux" "@_ZNK16FileWeaponInfo_t15GetAttributeIntEPKcPK13CEconItemView"
|
"linux" "@_ZNK13CCSWeaponInfo14GetWeaponPriceEPK13CEconItemViewif"
|
||||||
"mac" "@_ZNK16FileWeaponInfo_t15GetAttributeIntEPKcPK13CEconItemView"
|
"mac" "@_ZNK13CCSWeaponInfo14GetWeaponPriceEPK13CEconItemViewif"
|
||||||
}
|
}
|
||||||
"SetModelFromClass"
|
"SetModelFromClass"
|
||||||
{
|
{
|
||||||
|
@ -58,6 +58,23 @@ CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, void *pAddress)
|
||||||
|
{
|
||||||
|
CDetour *detour = new CDetour(callbackfunction, trampoline, pAddress);
|
||||||
|
if (detour)
|
||||||
|
{
|
||||||
|
if (!detour->Init(spengine, gameconf))
|
||||||
|
{
|
||||||
|
delete detour;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return detour;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame)
|
CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame)
|
||||||
{
|
{
|
||||||
enabled = false;
|
enabled = false;
|
||||||
@ -71,6 +88,19 @@ CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame)
|
|||||||
this->trampoline = trampoline;
|
this->trampoline = trampoline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CDetour::CDetour(void*callbackfunction, void **trampoline, void *pAddress)
|
||||||
|
{
|
||||||
|
enabled = false;
|
||||||
|
detoured = false;
|
||||||
|
detour_address = pAddress;
|
||||||
|
detour_trampoline = NULL;
|
||||||
|
this->signame = NULL;
|
||||||
|
this->detour_callback = callbackfunction;
|
||||||
|
spengine = NULL;
|
||||||
|
gameconf = NULL;
|
||||||
|
this->trampoline = trampoline;
|
||||||
|
}
|
||||||
|
|
||||||
bool CDetour::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
|
bool CDetour::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
|
||||||
{
|
{
|
||||||
this->spengine = spengine;
|
this->spengine = spengine;
|
||||||
@ -100,11 +130,16 @@ bool CDetour::IsEnabled()
|
|||||||
|
|
||||||
bool CDetour::CreateDetour()
|
bool CDetour::CreateDetour()
|
||||||
{
|
{
|
||||||
if (!gameconf->GetMemSig(signame, &detour_address))
|
if (signame && !gameconf->GetMemSig(signame, &detour_address))
|
||||||
{
|
{
|
||||||
g_pSM->LogError(myself, "Could not locate %s - Disabling detour", signame);
|
g_pSM->LogError(myself, "Could not locate %s - Disabling detour", signame);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else if(!detour_address)
|
||||||
|
{
|
||||||
|
g_pSM->LogError(myself, "Invalid detour address passed - Disabling detour to prevent crashes");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!detour_address)
|
if (!detour_address)
|
||||||
{
|
{
|
||||||
|
@ -167,6 +167,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
CDetour(void *callbackfunction, void **trampoline, const char *signame);
|
CDetour(void *callbackfunction, void **trampoline, const char *signame);
|
||||||
|
CDetour(void*callbackfunction, void **trampoline, void *pAddress);
|
||||||
|
|
||||||
bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
|
bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
|
||||||
private:
|
private:
|
||||||
@ -239,6 +240,7 @@ public:
|
|||||||
* Note we changed the netadr_s reference into a void* to avoid needing to define the type
|
* Note we changed the netadr_s reference into a void* to avoid needing to define the type
|
||||||
*/
|
*/
|
||||||
static CDetour *CreateDetour(void *callbackfunction, void **trampoline, const char *signame);
|
static CDetour *CreateDetour(void *callbackfunction, void **trampoline, const char *signame);
|
||||||
|
static CDetour *CreateDetour(void *callbackfunction, void **trampoline, void *pAddress);
|
||||||
|
|
||||||
friend class CBlocker;
|
friend class CBlocker;
|
||||||
friend class CDetour;
|
friend class CDetour;
|
||||||
|
@ -324,6 +324,8 @@
|
|||||||
"CalcDominationAndRevenge_Offset" "CalcDomRevPatch"
|
"CalcDominationAndRevenge_Offset" "CalcDomRevPatch"
|
||||||
"CalcDominationAndRevenge_Byte_Win" "0F"
|
"CalcDominationAndRevenge_Byte_Win" "0F"
|
||||||
"CalcDominationAndRevenge_Byte_Lin" "74"
|
"CalcDominationAndRevenge_Byte_Lin" "74"
|
||||||
|
"GetWeaponPrice_Offset" "GetWeaponPriceFuncGDC"
|
||||||
|
"GetWeaponPrice_Byte_Win" "E9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user