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
 | 
			
		||||
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)
 | 
			
		||||
		return price;
 | 
			
		||||
 | 
			
		||||
@ -71,19 +83,6 @@ DETOUR_DECL_MEMBER0(DetourWeaponPrice, int)
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
DETOUR_DECL_MEMBER2(DetourTerminateRound, void, float, delay, int, reason)
 | 
			
		||||
@ -201,8 +200,15 @@ bool CreateWeaponPriceDetour()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	DWeaponPrice = DETOUR_CREATE_MEMBER(DetourWeaponPrice, "GetAttributeInt");
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO && defined(WIN32)
 | 
			
		||||
	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
 | 
			
		||||
	DWeaponPrice = DETOUR_CREATE_MEMBER(DetourWeaponPrice, "GetWeaponPrice");
 | 
			
		||||
#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)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	if (!IsValidWeaponID(params[2]))
 | 
			
		||||
		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.
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
 | 
			
		||||
	if (id == WEAPON_C4 || id == WEAPON_KNIFE || id == WEAPON_KNIFE_GG)
 | 
			
		||||
		return 0;
 | 
			
		||||
#else
 | 
			
		||||
@ -458,23 +460,49 @@ 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();
 | 
			
		||||
		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)
 | 
			
		||||
	{
 | 
			
		||||
		REGISTER_NATIVE_ADDR("GetAttributeInt",
 | 
			
		||||
		PassInfo pass[2]; \
 | 
			
		||||
		REGISTER_NATIVE_ADDR("GetWeaponPrice",
 | 
			
		||||
		PassInfo pass[3]; \
 | 
			
		||||
		PassInfo ret; \
 | 
			
		||||
		pass[0].flags = PASSFLAG_BYVAL; \
 | 
			
		||||
		pass[0].type = PassType_Basic; \
 | 
			
		||||
		pass[0].size = sizeof(char *); \
 | 
			
		||||
		pass[0].size = sizeof(CEconItemView *); \
 | 
			
		||||
		pass[1].flags = PASSFLAG_BYVAL; \
 | 
			
		||||
		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.type = PassType_Basic; \
 | 
			
		||||
		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
 | 
			
		||||
	// Found in CCSPlayer::HandleCommand_Buy_Internal
 | 
			
		||||
	// 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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
	*(void **)vptr = info;
 | 
			
		||||
	vptr += sizeof(void *);
 | 
			
		||||
	*(const char **)vptr = "in game price";
 | 
			
		||||
	vptr += sizeof(const char *);
 | 
			
		||||
	*(CEconItemView **)vptr = view;
 | 
			
		||||
	vptr += sizeof(CEconItemView *);
 | 
			
		||||
	*(int *)vptr = 0;
 | 
			
		||||
#if !defined(WIN32)
 | 
			
		||||
	vptr += sizeof(int);
 | 
			
		||||
	*(float *)vptr = 1.0;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	int price = 0;
 | 
			
		||||
 	pWrapper->Execute(vstk, &price);
 | 
			
		||||
 | 
			
		||||
@ -229,6 +229,56 @@ const char *WeaponIDToAlias(int weaponID)
 | 
			
		||||
#endif
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
 | 
			
		||||
@ -165,4 +165,6 @@ int GetFakeWeaponID(int weaponId);
 | 
			
		||||
 | 
			
		||||
bool IsValidWeaponID(int weaponId);
 | 
			
		||||
 | 
			
		||||
void *GetWeaponPriceFunction();
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,10 @@
 | 
			
		||||
{
 | 
			
		||||
	"csgo"
 | 
			
		||||
	{
 | 
			
		||||
		"Keys"
 | 
			
		||||
		{
 | 
			
		||||
			"GetWeaponPriceByteCheck"	"E9"
 | 
			
		||||
		}
 | 
			
		||||
		"Offsets"
 | 
			
		||||
		{
 | 
			
		||||
			//Offset of szClassName in CCSWeaponInfo 
 | 
			
		||||
@ -62,6 +66,15 @@
 | 
			
		||||
				"linux"		"9"
 | 
			
		||||
				"mac"		"9"
 | 
			
		||||
			}
 | 
			
		||||
			"GetWeaponPriceFunc"
 | 
			
		||||
			{
 | 
			
		||||
				"windows"	"84"
 | 
			
		||||
			}
 | 
			
		||||
			//This is GetWeaponPriceFunc offset -1 (only used by GDC)
 | 
			
		||||
			"GetWeaponPriceFuncGDC"
 | 
			
		||||
			{
 | 
			
		||||
				"windows"	"83"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		"Signatures"
 | 
			
		||||
		{
 | 
			
		||||
@ -143,13 +156,13 @@
 | 
			
		||||
				"linux"		"@_ZN9CCSPlayer10SetClanTagEPKc"
 | 
			
		||||
				"mac"		"@_ZN9CCSPlayer10SetClanTagEPKc"
 | 
			
		||||
			}
 | 
			
		||||
			//Wild card first 6 bytes since we call it and detour it.
 | 
			
		||||
			"GetAttributeInt"
 | 
			
		||||
			//In windows this is CCSPlayer::GetWeaponPrice NOT CCSWeaponInfo::GetWeaponPrice
 | 
			
		||||
			"GetWeaponPrice"
 | 
			
		||||
			{
 | 
			
		||||
				"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"
 | 
			
		||||
				"linux"		"@_ZNK16FileWeaponInfo_t15GetAttributeIntEPKcPK13CEconItemView"
 | 
			
		||||
				"mac"		"@_ZNK16FileWeaponInfo_t15GetAttributeIntEPKcPK13CEconItemView"
 | 
			
		||||
				"windows"	"\x55\x8B\xEC\x8B\xD1\x8B\x4D\x08\x83\xF9\x33\x75\x2A\x83\xBA"
 | 
			
		||||
				"linux"		"@_ZNK13CCSWeaponInfo14GetWeaponPriceEPK13CEconItemViewif"
 | 
			
		||||
				"mac"		"@_ZNK13CCSWeaponInfo14GetWeaponPriceEPK13CEconItemViewif"
 | 
			
		||||
			}
 | 
			
		||||
			"SetModelFromClass"
 | 
			
		||||
			{
 | 
			
		||||
 | 
			
		||||
@ -58,6 +58,23 @@ CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline,
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
	enabled = false;
 | 
			
		||||
@ -71,6 +88,19 @@ CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame)
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
	this->spengine = spengine;
 | 
			
		||||
@ -100,11 +130,16 @@ bool CDetour::IsEnabled()
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	else if(!detour_address)
 | 
			
		||||
	{
 | 
			
		||||
		g_pSM->LogError(myself, "Invalid detour address passed - Disabling detour to prevent crashes");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!detour_address)
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
@ -167,6 +167,7 @@ public:
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	CDetour(void *callbackfunction, void **trampoline, const char *signame);
 | 
			
		||||
	CDetour(void*callbackfunction, void **trampoline, void *pAddress);
 | 
			
		||||
 | 
			
		||||
	bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
 | 
			
		||||
private:
 | 
			
		||||
@ -239,6 +240,7 @@ public:
 | 
			
		||||
	 * 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, void *pAddress);
 | 
			
		||||
 | 
			
		||||
	friend class CBlocker;
 | 
			
		||||
	friend class CDetour;
 | 
			
		||||
 | 
			
		||||
@ -324,6 +324,8 @@
 | 
			
		||||
			"CalcDominationAndRevenge_Offset"		"CalcDomRevPatch"
 | 
			
		||||
			"CalcDominationAndRevenge_Byte_Win"		"0F"
 | 
			
		||||
			"CalcDominationAndRevenge_Byte_Lin"		"74"
 | 
			
		||||
			"GetWeaponPrice_Offset"					"GetWeaponPriceFuncGDC"
 | 
			
		||||
			"GetWeaponPrice_Byte_Win"				"E9"	
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user