diff --git a/src/detours.cpp b/src/detours.cpp index 72c270c3..c75488ed 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -52,7 +52,6 @@ #include "tier0/memdbgon.h" - extern CGlobalVars *gpGlobals; extern CGameEntitySystem *g_pEntitySystem; extern IGameEventManager2 *g_gameEventManager; @@ -685,14 +684,6 @@ bool InitDetours(CGameConfig *gameConfig) FOR_EACH_VEC(g_vecDetours, i) { - if (!V_strcmp(g_vecDetours[i]->GetName(), "CEntityIOOutput_FireOutputInternal")) - { - // Check if features needing this detour are actually enabled. - // If not, leave this detour disabled for CS# compatibility - if (!IsButtonWatchEnabled()) - continue; - } - if (!g_vecDetours[i]->CreateDetour(gameConfig)) success = false; diff --git a/src/detours.h b/src/detours.h index 206eaf46..d85983db 100644 --- a/src/detours.h +++ b/src/detours.h @@ -21,6 +21,7 @@ #include "cdetour.h" #include + class CCheckTransmitInfo; class IRecipientFilter; class ISoundEmitterSystemBase; @@ -49,7 +50,6 @@ class CCSPlayer_UseServices; class CTraceFilter; class Vector; class QAngle; -class CEntityIOOutput; bool InitDetours(CGameConfig *gameConfig); void FlushAllDetours(); diff --git a/src/entities.cpp b/src/entities.cpp index 659b1943..25552590 100644 --- a/src/entities.cpp +++ b/src/entities.cpp @@ -34,6 +34,8 @@ // #define ENTITY_HANDLER_ASSERTION +extern CCSGameRules* g_pGameRules; + class InputData_t { public: @@ -724,15 +726,60 @@ void EntityHandler_OnEntitySpawned(CBaseEntity* pEntity) CPointViewControlHandler::OnCreated(pEntity); } -std::map mapRecentEnts; CDetour* CEntityIOOutput_FireOutputInternal = nullptr; +using IOCallback = std::function; +// Add callback functions to this map that wish to hook into Detour_CEntityIOOutput_FireOutputInternal +// to make it more modular/cleaner than shoving everything into the detour (buttonwatch, entwatch, etc.) +std::map mapIOFunctions; +void FASTCALL Detour_CEntityIOOutput_FireOutputInternal(const CEntityIOOutput* pThis, CEntityInstance* pActivator, CEntityInstance* pCaller, const CVariant* value, float flDelay) +{ + for (const auto& [name, cb] : mapIOFunctions) + cb(pThis, pActivator, pCaller, value, flDelay); + + (*CEntityIOOutput_FireOutputInternal)(pThis, pActivator, pCaller, value, flDelay); +} + +// Tries to setup Detour_CEntityIOOutput_FireOutputInternal if it is not already setup. +// Returns true if detour is usable, otherwise false. +bool SetupFireOutputInternalDetour() +{ + if (CEntityIOOutput_FireOutputInternal != nullptr) + return true; + + CEntityIOOutput_FireOutputInternal = new CDetour(Detour_CEntityIOOutput_FireOutputInternal, "CEntityIOOutput_FireOutputInternal"); + if (!CEntityIOOutput_FireOutputInternal->CreateDetour(g_GameConfig)) + { + Msg("Failed to detour CEntityIOOutput_FireOutputInternal\n"); + delete CEntityIOOutput_FireOutputInternal; + CEntityIOOutput_FireOutputInternal = nullptr; + return false; + } + CEntityIOOutput_FireOutputInternal->EnableDetour(); + return true; +} + +CON_COMMAND_F(cs2f_enable_button_watch, "CS# BREAKS IF THIS IS EVER ENABLED. Whether to enable button watch or not.", FCVAR_LINKED_CONCOMMAND | FCVAR_SPONLY | FCVAR_PROTECTED) +{ + if (args.ArgC() < 2) + { + Msg("%s %i\n", args[0], IsButtonWatchEnabled()); + return; + } + + if (!V_StringToBool(args[1], false) || !SetupFireOutputInternalDetour()) + mapIOFunctions.erase("buttonwatch"); + else if (!IsButtonWatchEnabled()) + mapIOFunctions["buttonwatch"] = ButtonWatch; +} + bool IsButtonWatchEnabled() { - return std::any_of(vecIOFunctions.begin(), vecIOFunctions.end(), [](IOCallback& cb) { - return cb.target() == &ButtonWatch; + return std::any_of(mapIOFunctions.begin(), mapIOFunctions.end(), [](const auto& p) { + return p.first == "buttonwatch"; }); } +std::map mapRecentEnts; void ButtonWatch(const CEntityIOOutput* pThis, CEntityInstance* pActivator, CEntityInstance* pCaller, const CVariant* value, float flDelay) { if (!IsButtonWatchEnabled() || V_stricmp(pThis->m_pDesc->m_pName, "OnPressed") || @@ -783,64 +830,4 @@ void ButtonWatch(const CEntityIOOutput* pThis, CEntityInstance* pActivator, CEnt mapRecentEnts.erase(iIndex); return -1.0f; }); -} - -extern CCSGameRules* g_pGameRules; -// Tries to setup Detour_CEntityIOOutput_FireOutputInternal if it is not already setup. -// Returns true if detour is usable, otherwise false. -bool SetupFireOutputInternalDetour() -{ - if (CEntityIOOutput_FireOutputInternal != nullptr) - return true; - - CEntityIOOutput_FireOutputInternal = new CDetour(Detour_CEntityIOOutput_FireOutputInternal, "CEntityIOOutput_FireOutputInternal"); - if (!CEntityIOOutput_FireOutputInternal->CreateDetour(g_GameConfig)) - { - Msg("Failed to detour CEntityIOOutput_FireOutputInternal\n"); - delete CEntityIOOutput_FireOutputInternal; - CEntityIOOutput_FireOutputInternal = nullptr; - return false; - } - CEntityIOOutput_FireOutputInternal->EnableDetour(); - return true; -} - -CON_COMMAND_F(cs2f_enable_button_watch, "CS# BREAKS IF THIS IS EVER ENABLED. Whether to enable button watch or not.", FCVAR_LINKED_CONCOMMAND | FCVAR_SPONLY | FCVAR_PROTECTED) -{ - if (args.ArgC() < 2) - { - Msg("%s %b\n", args[0], IsButtonWatchEnabled()); - return; - } - - if (!V_StringToBool(args[1], false) || !SetupFireOutputInternalDetour()) - { - vecIOFunctions.erase(std::remove_if(vecIOFunctions.begin(), vecIOFunctions.end(), [](const IOCallback& cb) { - return cb.target() == &ButtonWatch; - }), vecIOFunctions.end()); - } - else if (!IsButtonWatchEnabled()) - { - vecIOFunctions.push_back(ButtonWatch); - } -} - -using IOCallback = std::function; -// Add callback functions to this vector that wish to hook into Detour_CEntityIOOutput_FireOutputInternal -// to make it more modular/cleaner than shoving everything into the detour -std::vector vecIOFunctions; -void FASTCALL Detour_CEntityIOOutput_FireOutputInternal(const CEntityIOOutput* pThis, CEntityInstance* pActivator, CEntityInstance* pCaller, const CVariant* value, float flDelay) -{ -#ifdef DEBUG - // pCaller can absolutely be null. Needs to be checked - if(pCaller) - ConMsg("Output %s fired on %s\n", pThis->m_pDesc->m_pName, pCaller->GetClassname()); - else - ConMsg("Output %s fired with no caller\n", pThis->m_pDesc->m_pName); -#endif - - for (const auto& cb : vecIOFunctions) - cb(pThis, pActivator, pCaller, value, flDelay); - - (*CEntityIOOutput_FireOutputInternal)(pThis, pActivator, pCaller, value, flDelay); } \ No newline at end of file