From 0728fee7069780a775d7fe7be489cee723f27ec8 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Fri, 4 Jul 2014 00:17:55 +0200 Subject: [PATCH] Cstrike: Make CS_OnBuy forward more reliable - part 4 Added support for shield , which is a special case. Moved hashmap creation to OnPluginsLoaded. --- dlls/cstrike/cstrike/CstrikeDatas.h | 3 + dlls/cstrike/cstrike/CstrikeHacks.cpp | 93 ++++++++++++++++++--------- 2 files changed, 66 insertions(+), 30 deletions(-) diff --git a/dlls/cstrike/cstrike/CstrikeDatas.h b/dlls/cstrike/cstrike/CstrikeDatas.h index 84488ef0..c1d138f1 100644 --- a/dlls/cstrike/cstrike/CstrikeDatas.h +++ b/dlls/cstrike/cstrike/CstrikeDatas.h @@ -163,14 +163,17 @@ * CS_OnBuy forward */ #if defined(__linux__) + #define CS_IDENT_GIVENSHIELD "_ZN11CBasePlayer10GiveShieldEb" #define CS_IDENT_GIVENAMEDITEM "_ZN11CBasePlayer13GiveNamedItemEPKc" #define CS_IDENT_ADDACCOUNT "_ZN11CBasePlayer10AddAccountEib" #define CS_IDENT_HIDDEN_STATE false #elif defined(__APPLE__) + #define CS_IDENT_GIVENSHIELD "_ZN11CBasePlayer10GiveShieldEb" #define CS_IDENT_GIVENAMEDITEM "_ZN11CBasePlayer13GiveNamedItemEPKc" #define CS_IDENT_ADDACCOUNT "_ZN11CBasePlayer10AddAccountEib" #define CS_IDENT_HIDDEN_STATE true #elif defined(WIN32) + #define CS_IDENT_GIVENSHIELD "\\x56\\x8B\\x2A\\x57\\x33\\x2A\\x8B\\x2A\\x2A\\x2A\\x2A\\x2A\\xB0" #define CS_IDENT_GIVENAMEDITEM "\\x8B\\x2A\\x2A\\x2A\\x56\\x57\\x8B\\x2A\\x8B\\x2A\\x2A\\x2A\\x2A\\x2A\\x2B" #define CS_IDENT_ADDACCOUNT "\\x8B\\x2A\\x2A\\x2A\\x56\\x8B\\x2A\\x8B\\x2A\\x2A\\x2A\\x2A\\x2A\\x03" #define CS_IDENT_HIDDEN_STATE false diff --git a/dlls/cstrike/cstrike/CstrikeHacks.cpp b/dlls/cstrike/cstrike/CstrikeHacks.cpp index 83ec0e1d..342c9bc6 100644 --- a/dlls/cstrike/cstrike/CstrikeHacks.cpp +++ b/dlls/cstrike/cstrike/CstrikeHacks.cpp @@ -43,15 +43,13 @@ void CtrlDetours_BuyCommands(bool set); int g_CSCliCmdFwd = -1; int g_CSBuyCmdFwd = -1; -int *g_UseBotArgs = NULL; +int *g_UseBotArgs = NULL; const char **g_BotArgs = NULL; CDetour *g_ClientCommandDetour = NULL; -CDetour *g_CanBuyThisDetour = NULL; -CDetour *g_BuyItemDetour = NULL; -CDetour *g_BuyGunAmmoDetour = NULL; +CDetour *g_GiveShieldDetour = NULL; CDetour *g_GiveNamedItemDetour = NULL; -CDetour *g_AddAccountDetour = NULL; +CDetour *g_AddAccountDetour = NULL; int g_CurrentItemId = 0; StringHashMap g_ItemAliasList; @@ -93,7 +91,7 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma { const char *command = CMD_ARGV(0); - // A new command is triggered, reset current item. + // A new command is triggered, reset variable, always. g_CurrentItemId = 0; // Purpose is to retrieve an item id based on alias name or selected item from menu, @@ -102,7 +100,7 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma { int itemId = 0; - // Handling via menu. + // Handling buy via menu. if (!strcmp(command, "menuselect")) { int slot = atoi(CMD_ARGV(1)); @@ -148,8 +146,7 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma } } } - // Handling via alias - else + else // Handling buy via alias { if (g_ItemAliasList.retrieve(command, &itemId)) { @@ -174,26 +171,47 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma DETOUR_DECL_MEMBER1(GiveNamedItem, void, const char*, pszName) // void CBasePlayer::GiveNamedItem(const char *pszName) { + // If the current item id is not null, this means player has triggers a buy command. if (g_CurrentItemId && MF_ExecuteForward(g_CSBuyCmdFwd, static_cast(PrivateToIndex(this)), static_cast(g_CurrentItemId)) > 0) { return; } + // From here, forward is not blocked, resetting this + // to ignore code in AddAccount which is called right after. g_CurrentItemId = 0; + // Give me my item! DETOUR_MEMBER_CALL(GiveNamedItem)(pszName); } - -DETOUR_DECL_MEMBER2(AddAccount, void, int, amount, bool, bTrackChange) // void CBasePlayer::AddAccount(int amount, bool bTrackChange) +DETOUR_DECL_MEMBER1(GiveShield, void, bool, bRetire) // void CBasePlayer::GiveShield(bool bRetire) { - if (g_CurrentItemId) + // Special case for shield. Game doesn't use GiveNamedItem() to give a shield. + if (g_CurrentItemId == CSI_SHIELDGUN && MF_ExecuteForward(g_CSBuyCmdFwd, static_cast(PrivateToIndex(this)), CSI_SHIELDGUN) > 0) { - g_CurrentItemId = 0; return; } - DETOUR_MEMBER_CALL(AddAccount)(amount, bTrackChange); + // From here, forward is not blocked, resetting this + // to ignore code in AddAccount which is called right after. + g_CurrentItemId = 0; + + // Give me my shield! + DETOUR_MEMBER_CALL(GiveShield)(bRetire); +} + +DETOUR_DECL_MEMBER2(AddAccount, void, int, amount, bool, bTrackChange) // void CBasePlayer::AddAccount(int amount, bool bTrackChange) +{ + // No buy command or forward not blocked. + // Resuming game flow. + if (!g_CurrentItemId) + { + DETOUR_MEMBER_CALL(AddAccount)(amount, bTrackChange); + } + + // Let's reset this right away to avoid issues. + g_CurrentItemId = 0; } @@ -239,9 +257,11 @@ void CtrlDetours_BuyCommands(bool set) { if (set) { + void *giveShieldAddress = UTIL_FindAddressFromEntry(CS_IDENT_GIVENSHIELD , CS_IDENT_HIDDEN_STATE); void *giveNamedItemAddress = UTIL_FindAddressFromEntry(CS_IDENT_GIVENAMEDITEM, CS_IDENT_HIDDEN_STATE); void *addAccountAddress = UTIL_FindAddressFromEntry(CS_IDENT_ADDACCOUNT , CS_IDENT_HIDDEN_STATE); + g_GiveShieldDetour = DETOUR_CREATE_MEMBER_FIXED(GiveShield, giveShieldAddress); g_GiveNamedItemDetour = DETOUR_CREATE_MEMBER_FIXED(GiveNamedItem, giveNamedItemAddress); g_AddAccountDetour = DETOUR_CREATE_MEMBER_FIXED(AddAccount, addAccountAddress); @@ -249,9 +269,37 @@ void CtrlDetours_BuyCommands(bool set) { MF_Log("No Buy Commands detours could be initialized - Disabled Buy forward."); } + } + else + { + if (g_GiveShieldDetour) + g_GiveShieldDetour->Destroy(); + if (g_GiveNamedItemDetour) + g_GiveNamedItemDetour->Destroy(); + + if (g_AddAccountDetour) + g_AddAccountDetour->Destroy(); + + g_ItemAliasList.clear(); + } +} + +void ToggleDetour_BuyCommands(bool enable) +{ + if (g_GiveShieldDetour) + (enable) ? g_GiveShieldDetour->EnableDetour() : g_GiveShieldDetour->DisableDetour(); + + if (g_GiveNamedItemDetour) + (enable) ? g_GiveNamedItemDetour->EnableDetour() : g_GiveNamedItemDetour->DisableDetour(); + + if (g_AddAccountDetour) + (enable) ? g_AddAccountDetour->EnableDetour() : g_AddAccountDetour->DisableDetour(); + + if (enable) + { // Build the item alias list. - // Used in ClientCommand to check and get fastly item id from aiias name. + // Used in ClientCommand to check and get fastly item id from alias name. typedef struct { char *alias; @@ -298,21 +346,6 @@ void CtrlDetours_BuyCommands(bool set) } else { - if (g_GiveNamedItemDetour) - g_GiveNamedItemDetour->Destroy(); - - if (g_AddAccountDetour) - g_AddAccountDetour->Destroy(); - g_ItemAliasList.clear(); } -} - -void ToggleDetour_BuyCommands(bool enable) -{ - if (g_GiveNamedItemDetour) - (enable) ? g_GiveNamedItemDetour->EnableDetour() : g_GiveNamedItemDetour->DisableDetour(); - - if (g_AddAccountDetour) - (enable) ? g_AddAccountDetour->EnableDetour() : g_AddAccountDetour->DisableDetour(); } \ No newline at end of file