From d08e1357dd8dab5d8cba2e3cbab5dbaee005f972 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Wed, 9 Sep 2015 01:06:54 +0200 Subject: [PATCH] Cstrike: Fix defuser/nvgs not being called with CS_OnBuy and fix wrong shield CSI constants --- modules/cstrike/cstrike/CstrikeHacks.cpp | 136 +++++++++++++++--- modules/cstrike/cstrike/CstrikeHacks.h | 1 + modules/cstrike/cstrike/CstrikeMain.cpp | 6 + modules/cstrike/cstrike/CstrikeNatives.cpp | 10 +- .../cstrike/cstrike/CstrikeUserMessages.cpp | 71 +++++++-- modules/cstrike/cstrike/CstrikeUserMessages.h | 2 +- modules/cstrike/cstrike/moduleconfig.h | 2 +- 7 files changed, 200 insertions(+), 28 deletions(-) diff --git a/modules/cstrike/cstrike/CstrikeHacks.cpp b/modules/cstrike/cstrike/CstrikeHacks.cpp index 78867578..f62813b7 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.cpp +++ b/modules/cstrike/cstrike/CstrikeHacks.cpp @@ -40,10 +40,11 @@ GetWeaponInfoFunc GetWeaponInfo; int CurrentItemId; bool TriggeredFromCommand; -StringHashMap ItemAliasList; +// m_iTeam and m_iMenu from CBasePlayer. TypeDescription TeamDesc; TypeDescription MenuDesc; +// Engine global variables. server_static_t *ServerStatic; server_t *Server; @@ -80,16 +81,6 @@ const char *CMD_ARGV(int i) return g_engfuncs.pfnCmd_Argv(i); } -void OnEmitSound(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch) -{ - // If shield is blocked with CS_OnBuy, we need to block the pickup sound ("items/gunpickup2.wav") - // as well played right after. Why this sound is not contained in GiveShield()? - - g_pengfuncsTable->pfnEmitSound = nullptr; - - RETURN_META(MRES_SUPERCEDE); -} - DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientCommand(edict_t *pEntity) { const char *command = CMD_ARGV(0); @@ -97,7 +88,7 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma CurrentItemId = CSI_NONE; // Purpose is to retrieve an item id based on alias name or selected item from menu, - // to be used in OnBuy* forwards. + // to be used in CS_OnBuy* forwards. if ((ForwardOnBuyAttempt != -1 || ForwardOnBuy != -1) && command && *command) { int itemId = CSI_NONE; @@ -179,8 +170,41 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma return; } + // CS_OnBuy() + // - + // This forward should be called right before game gives the item. + // All items except shield, defuser and nvgs, games executes in the following order: + // GiveNamedItem -> AddAccount + // Forward is fired on GiveNamedItem. + // Shield only: + // GiveShield -> AddAccount -> EmitSound + // Forward is fired on GiveShield. + // Defusal kit only: + // m_bHasDefuser(true) -> StatusIcon -> pev_body(1) -> AddAccount -> EmitSound -> ItemStatus + // Forward is fired on StatusIcon. + // Nightvision only: + // EmitSound -> m_bHasNightVision(true) -> AddAccount -> ItemStatus + // Forward is fired on EmitSound. + TriggeredFromCommand = CurrentItemId != CSI_NONE; + if (TriggeredFromCommand) + { + if (CurrentItemId == CSI_NVGS) + { + g_pengfuncsTable->pfnEmitSound = OnEmitSound; + } + else if (CurrentItemId == CSI_DEFUSER) + { + GET_OFFSET_NO_ERROR("CBasePlayer", m_bHasDefuser); + + if (!get_pdata(pEdict, m_bHasDefuser)) + { + EnableMessageHooks(); + } + } + } + DETOUR_STATIC_CALL(C_ClientCommand)(pEdict); TriggeredFromCommand = false; @@ -203,6 +227,69 @@ edict_s* OnCreateNamedEntity(int classname) RETURN_META_VALUE(MRES_IGNORED, 0); } +void OnEmitSound(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch) +{ + if (TriggeredFromCommand) + { + switch (CurrentItemId) + { + case CSI_NVGS: + { + auto client = ENTINDEX(entity); + + if (!MF_IsPlayerAlive(client) || MF_ExecuteForward(ForwardOnBuy, static_cast(client), CSI_NVGS) <= 0) + { + g_pengfuncsTable->pfnEmitSound = nullptr; + RETURN_META(MRES_IGNORED); + } + } + case CSI_DEFUSER: + case CSI_SHIELD: + { + g_pengfuncsTable->pfnEmitSound = nullptr; + RETURN_META(MRES_SUPERCEDE); + } + } + } + + RETURN_META(MRES_IGNORED); +} + +bool OnMessageItemStatus(edict_t *pPlayer) +{ + if (TriggeredFromCommand && (CurrentItemId == CSI_DEFUSER || CurrentItemId == CSI_NVGS)) + { + if (!g_pengfuncsTable->pfnEmitSound) + { + return true; // Block message + } + + DisableMessageHooks(); + } + + return false; +} + +bool OnMessageStatusIcon(edict_t *pPlayer) +{ + if (TriggeredFromCommand && CurrentItemId == CSI_DEFUSER) + { + auto client = ENTINDEX(pPlayer); + + if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast(client), CSI_DEFUSER) > 0) + { + GET_OFFSET_NO_ERROR_RET("CBasePlayer", m_bHasDefuser); + set_pdata(pPlayer, m_bHasDefuser, false); + + return true; // Block message + } + + DisableMessageHooks(); + } + + return false; +} + DETOUR_DECL_MEMBER0(GiveDefaultItems, void) // void CBasePlayer::GiveDefaultItems(void) { if (NoKifesMode) @@ -234,11 +321,11 @@ DETOUR_DECL_MEMBER1(GiveNamedItem, void, const char*, pszName) // void CBasePlay DETOUR_DECL_MEMBER1(GiveShield, void, bool, bRetire) // void CBasePlayer::GiveShield(bool bRetire) { - if (TriggeredFromCommand && CurrentItemId == CSI_SHIELDGUN) + if (TriggeredFromCommand && CurrentItemId == CSI_SHIELD) { int client = TypeConversion.cbase_to_id(this); - if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast(client), CSI_SHIELDGUN) > 0) + if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast(client), CSI_SHIELD) > 0) { // If shield blocked, we need to hook EmitSound to block pickup sound played right after. g_pengfuncsTable->pfnEmitSound = OnEmitSound; @@ -256,9 +343,26 @@ DETOUR_DECL_MEMBER2(AddAccount, void, int, amount, bool, bTrackChange) // void C { if (TriggeredFromCommand) { - if (CurrentItemId == CSI_NONE) + switch (CurrentItemId) { - return; + case CSI_DEFUSER: + { + G_HL_TypeConversion.cbase_to_entvar(this)->body = 0; + g_pengfuncsTable->pfnEmitSound = OnEmitSound; // To block pickup sound. + EnableMessageHooks(); // To block ItemStatus + break; + } + case CSI_NVGS: + { + GET_OFFSET_NO_ERROR("CBasePlayer", m_bHasNightVision); + set_pdata(G_HL_TypeConversion.cbase_to_edict(this), m_bHasNightVision, false); + EnableMessageHooks(); // To block ItemStatus + break; + } + case CSI_NONE: + { + return; + } } } diff --git a/modules/cstrike/cstrike/CstrikeHacks.h b/modules/cstrike/cstrike/CstrikeHacks.h index 52068f91..7ba53900 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.h +++ b/modules/cstrike/cstrike/CstrikeHacks.h @@ -25,6 +25,7 @@ void InitGlobalVars(); void ShutdownHacks(); void ToggleDetour_ClientCommands(bool enable); void ToggleDetour_BuyCommands(bool enable); +void OnEmitSound(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch); extern AMX_NATIVE_INFO CstrikeNatives[]; diff --git a/modules/cstrike/cstrike/CstrikeMain.cpp b/modules/cstrike/cstrike/CstrikeMain.cpp index f7148473..71648615 100644 --- a/modules/cstrike/cstrike/CstrikeMain.cpp +++ b/modules/cstrike/cstrike/CstrikeMain.cpp @@ -93,6 +93,12 @@ void OnServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax) DisableMessageHooks(); } +void OnPluginsUnloaded() +{ + // Force to disable all hooks at map change. + DisableMessageHooks(true); +} + void OnAmxxDetach() { ConfigManager->RemoveUserConfigHook("CommandsAliases", &ItemsManager); diff --git a/modules/cstrike/cstrike/CstrikeNatives.cpp b/modules/cstrike/cstrike/CstrikeNatives.cpp index 84dccfe5..d9f5abfe 100644 --- a/modules/cstrike/cstrike/CstrikeNatives.cpp +++ b/modules/cstrike/cstrike/CstrikeNatives.cpp @@ -1358,7 +1358,13 @@ static cell AMX_NATIVE_CALL cs_set_user_zoom(AMX *amx, cell *params) int mode = params[3]; int weapon = *static_cast(MF_PlayerPropAddr(index, Player_CurrentWeapon)); - Players[index].ResetZoom(); + CPlayer& player = Players[index]; + + if (player.GetZoom()) + { + DisableMessageHooks(); + player.ResetZoom(); + } if (type == CS_RESET_ZOOM) { @@ -1406,7 +1412,7 @@ static cell AMX_NATIVE_CALL cs_set_user_zoom(AMX *amx, cell *params) if (!mode) { - Players[index].SetZoom(value); + player.SetZoom(value); EnableMessageHooks(); } diff --git a/modules/cstrike/cstrike/CstrikeUserMessages.cpp b/modules/cstrike/cstrike/CstrikeUserMessages.cpp index b290713e..ee51a21d 100644 --- a/modules/cstrike/cstrike/CstrikeUserMessages.cpp +++ b/modules/cstrike/cstrike/CstrikeUserMessages.cpp @@ -21,11 +21,13 @@ bool ShouldBlock; bool ShouldBlockHLTV; +bool ShouldDisableHooks; bool RetrieveWeaponName; ke::AString CurrentWeaponName; int ArgPosition; int MessageIdArmorType; +int MessageIdItemStatus; int MessageIdHLTV; int MessageIdMoney; int MessageIdResetHUD; @@ -37,6 +39,9 @@ int MessageIdTeamInfo; int MessageIdTextMsg; int MessageIdWeaponList; +extern bool OnMessageStatusIcon(edict_t *pPlayer); +extern bool OnMessageItemStatus(edict_t *pPlayer); + struct UserMsg { const char* name; @@ -46,6 +51,7 @@ struct UserMsg UserMsg MessagesList[] = { { "ArmorType" , &MessageIdArmorType }, + { "ItemStatus" , &MessageIdItemStatus }, { "HLTV" , &MessageIdHLTV }, { "Money" , &MessageIdMoney }, { "ResetHUD" , &MessageIdResetHUD }, @@ -105,7 +111,30 @@ void OnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *p int index = ENTINDEX(pEntity); if (Players[index].GetZoom()) + { Players[index].ResetZoom(); + DisableMessageHooks(); + } + } + else if (msg_type == MessageIdStatusIcon) + { + if (OnMessageStatusIcon(pEntity)) + { + ShouldBlock = true; + ShouldDisableHooks = true; + + RETURN_META(MRES_SUPERCEDE); + } + } + else if (msg_type == MessageIdItemStatus) + { + if (OnMessageItemStatus(pEntity)) + { + ShouldBlock = true; + ShouldDisableHooks = true; + + RETURN_META(MRES_SUPERCEDE); + } } break; } @@ -139,11 +168,12 @@ void OnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *p void OnWriteByte(int value) { - if (ShouldBlock) + if (ShouldBlock) { RETURN_META(MRES_SUPERCEDE); } - else if (RetrieveWeaponName && ++ArgPosition == 7 && value >= 0 && value < MAX_WEAPONS) + + if (RetrieveWeaponName && ++ArgPosition == 7 && value >= 0 && value < MAX_WEAPONS) { strncopy(WeaponNameList[value], CurrentWeaponName.chars(), sizeof(WeaponNameList[value])); } @@ -153,6 +183,11 @@ void OnWriteByte(int value) void OnWriteString(const char *value) { + if (ShouldBlock) + { + RETURN_META(MRES_SUPERCEDE); + } + if (RetrieveWeaponName) { CurrentWeaponName = value; @@ -166,9 +201,17 @@ void OnMessageEnd(void) if (ShouldBlock) { ShouldBlock = false; + + if (ShouldDisableHooks) + { + ShouldDisableHooks = false; + DisableMessageHooks(); + } + RETURN_META(MRES_SUPERCEDE); } - else if (RetrieveWeaponName) + + if (RetrieveWeaponName) { RetrieveWeaponName = false; ArgPosition = 0; @@ -177,8 +220,12 @@ void OnMessageEnd(void) RETURN_META(MRES_IGNORED); } +size_t RefCount; + void EnableMessageHooks() { + ++RefCount; + if (!g_pengfuncsTable->pfnMessageBegin) { g_pengfuncsTable->pfnMessageBegin = OnMessageBegin; @@ -188,10 +235,18 @@ void EnableMessageHooks() } } -void DisableMessageHooks() +void DisableMessageHooks(bool force) { - g_pengfuncsTable->pfnMessageBegin = nullptr; - g_pengfuncsTable->pfnWriteByte = nullptr; - g_pengfuncsTable->pfnWriteString = nullptr; - g_pengfuncsTable->pfnMessageEnd = nullptr; + if (force) + { + RefCount = 1; + } + + if (--RefCount == 0) + { + g_pengfuncsTable->pfnMessageBegin = nullptr; + g_pengfuncsTable->pfnWriteByte = nullptr; + g_pengfuncsTable->pfnWriteString = nullptr; + g_pengfuncsTable->pfnMessageEnd = nullptr; + } } diff --git a/modules/cstrike/cstrike/CstrikeUserMessages.h b/modules/cstrike/cstrike/CstrikeUserMessages.h index 7541ad1a..eae0ed15 100644 --- a/modules/cstrike/cstrike/CstrikeUserMessages.h +++ b/modules/cstrike/cstrike/CstrikeUserMessages.h @@ -26,6 +26,6 @@ extern int MessageIdTeamInfo; extern int MessageIdTextMsg; void EnableMessageHooks(); -void DisableMessageHooks(); +void DisableMessageHooks(bool force = false); #endif // CSTRIKE_USER_MESSAGES_H diff --git a/modules/cstrike/cstrike/moduleconfig.h b/modules/cstrike/cstrike/moduleconfig.h index 6438f750..adeeea39 100644 --- a/modules/cstrike/cstrike/moduleconfig.h +++ b/modules/cstrike/cstrike/moduleconfig.h @@ -80,7 +80,7 @@ //#define FN_AMXX_PLUGINSUNLOADING OnPluginsUnloading /** All plugins are now unloaded */ -//#define FN_AMXX_PLUGINSUNLOADED OnPluginsUnloaded +#define FN_AMXX_PLUGINSUNLOADED OnPluginsUnloaded /**** METAMOD ****/