diff --git a/extensions/tf2/criticals.cpp b/extensions/tf2/criticals.cpp index ebf500fb..1c71472f 100644 --- a/extensions/tf2/criticals.cpp +++ b/extensions/tf2/criticals.cpp @@ -32,330 +32,169 @@ #include "criticals.h" #include "util.h" -IServerGameEnts *gameents = NULL; +CritManager g_CritManager; -CDetour *calcIsAttackCriticalDetour = NULL; -CDetour *calcIsAttackCriticalMeleeDetour = NULL; -CDetour *calcIsAttackCriticalBowDetour = NULL; -CDetour *calcIsAttackCriticalKnifeDetour = NULL; -CDetour *calcIsAttackCriticalNoCritsDetour = NULL; -CDetour *calcIsAttackCriticalNoCritsMeleeDetour = NULL; +IForward *g_critForward = nullptr; -int nextMeleeCritOffset = -1; +SH_DECL_MANUALHOOK0(CalcIsAttackCriticalHelper, 0, 0, 0, bool); +SH_DECL_MANUALHOOK0(CalcIsAttackCriticalHelperNoCrits, 0, 0, 0, bool); -IForward *g_critForward = NULL; +const char TF_WEAPON_DATATABLE[] = "DT_TFWeaponBase"; -enum DetourResult +CritManager::CritManager() : + m_enabled(false), + m_hooksSetup(false) { - Result_Ignore, - Result_NoCrit, - Result_Crit, -}; - -int CheckBaseHandle(CBaseHandle &hndl) -{ - if (!hndl.IsValid()) - { - return -1; - } - - int index = hndl.GetEntryIndex(); - - edict_t *pStoredEdict; - - pStoredEdict = engine->PEntityOfEntIndex(index); - - if (pStoredEdict == NULL) - { - return -1; - } - - IServerEntity *pSE = pStoredEdict->GetIServerEntity(); - - if (pSE == NULL) - { - return -1; - } - - if (pSE->GetRefEHandle() != hndl) - { - return -1; - } - - return index; + m_entsHooked.Init(); } -DetourResult DetourCallback(CBaseEntity *pEnt, bool bMeleeNoCrits) +bool CritManager::TryEnable() { - edict_t *pEdict = gameents->BaseEntityToEdict((CBaseEntity *)pEnt); - - if (!pEdict) + if (!m_hooksSetup) { - g_pSM->LogMessage(myself, "Entity Error"); - return Result_Ignore; + int offset; + + if (!g_pGameConf->GetOffset("CalcIsAttackCriticalHelper", &offset)) + { + g_pSM->LogError(myself, "Failed to find CalcIsAttackCriticalHelper offset"); + return false; + } + + SH_MANUALHOOK_RECONFIGURE(CalcIsAttackCriticalHelper, offset, 0, 0); + + if (!g_pGameConf->GetOffset("CalcIsAttackCriticalHelperNoCrits", &offset)) + { + g_pSM->LogError(myself, "Failed to find CalcIsAttackCriticalHelperNoCrits offset"); + return false; + } + + SH_MANUALHOOK_RECONFIGURE(CalcIsAttackCriticalHelperNoCrits, offset, 0, 0); + + m_hooksSetup = true; + } + + for (size_t i = playerhelpers->GetMaxClients() + 1; i < MAX_EDICTS; ++i) + { + CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i); + if (pEntity == nullptr) + continue; + + IServerUnknown *pUnknown = (IServerUnknown *)pEntity; + IServerNetworkable *pNetworkable = pUnknown->GetNetworkable(); + if (!pNetworkable) + continue; + + if (!UTIL_ContainsDataTable(pNetworkable->GetServerClass()->m_pTable, TF_WEAPON_DATATABLE)) + continue; + + SH_ADD_MANUALHOOK(CalcIsAttackCriticalHelper, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false); + SH_ADD_MANUALHOOK(CalcIsAttackCriticalHelperNoCrits, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false); + + m_entsHooked.Set(i); + } + + m_enabled = true; + + return true; +} + +void CritManager::Disable() +{ + int i = m_entsHooked.FindNextSetBit(playerhelpers->GetMaxClients() + 1); + for (i; i != -1; i = m_entsHooked.FindNextSetBit(i)) + { + CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i); + SH_REMOVE_MANUALHOOK(CalcIsAttackCriticalHelper, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false); + SH_REMOVE_MANUALHOOK(CalcIsAttackCriticalHelperNoCrits, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false); + + m_entsHooked.Set(i, false); + } + + m_enabled = false; +} + +void CritManager::OnEntityCreated(CBaseEntity *pEntity, const char *classname) +{ + if (!m_enabled) + return; + + IServerUnknown *pUnknown = (IServerUnknown *)pEntity; + IServerNetworkable *pNetworkable = pUnknown->GetNetworkable(); + if (!pNetworkable) + return; + + if (!UTIL_ContainsDataTable(pNetworkable->GetServerClass()->m_pTable, TF_WEAPON_DATATABLE)) + return; + + SH_ADD_MANUALHOOK(CalcIsAttackCriticalHelper, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false); + SH_ADD_MANUALHOOK(CalcIsAttackCriticalHelperNoCrits, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false); + + m_entsHooked.Set(gamehelpers->EntityToBCompatRef(pEntity)); +} + +void CritManager::OnEntityDestroyed(CBaseEntity *pEntity) +{ + if (!m_enabled) + return; + + int index = gamehelpers->EntityToBCompatRef(pEntity); + if (index < 0 || index >= MAX_EDICTS) + return; + + if (!m_entsHooked.IsBitSet(index)) + return; + + SH_REMOVE_MANUALHOOK(CalcIsAttackCriticalHelper, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false); + SH_REMOVE_MANUALHOOK(CalcIsAttackCriticalHelperNoCrits, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false); + + m_entsHooked.Set(index, false); +} + +bool CritManager::Hook_CalcIsAttackCriticalHelpers() +{ + CBaseEntity *pWeapon = META_IFACEPTR(CBaseEntity); + + // If there's an invalid ent or invalid networkable here, we've got issues elsewhere. + + IServerNetworkable *pNetWeapon = ((IServerUnknown *)pWeapon)->GetNetworkable(); + ServerClass *pServerClass = pNetWeapon->GetServerClass(); + if (!pServerClass) + { + g_pSM->LogError(myself, "Invalid server class on weapon."); + RETURN_META_VALUE(MRES_IGNORED, false); } sm_sendprop_info_t info; - - if (!gamehelpers->FindSendPropInfo(pEdict->GetNetworkable()->GetServerClass()->GetName(), "m_hOwnerEntity", &info)) + if (!gamehelpers->FindSendPropInfo(pServerClass->GetName(), "m_hOwnerEntity", &info)) { - g_pSM->LogMessage(myself, "Offset Error"); - return Result_Ignore; + g_pSM->LogError(myself, "Could not find m_hOwnerEntity on %s", pServerClass->GetName()); + RETURN_META_VALUE(MRES_IGNORED, false); } - if (!g_critForward) + int returnValue = 0; + + int ownerIndex = -1; + CBaseHandle &hndl = *(CBaseHandle *) ((intptr_t)pWeapon + info.actual_offset); + CBaseEntity *pHandleEntity = gamehelpers->ReferenceToEntity(hndl.GetEntryIndex()); + + if (pHandleEntity != nullptr && hndl == reinterpret_cast(pHandleEntity)->GetRefEHandle()) { - g_pSM->LogMessage(myself, "Invalid Forward"); - return Result_Ignore; + ownerIndex = hndl.GetEntryIndex(); } - int returnValue=0; - - CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEnt + info.actual_offset); - int index = CheckBaseHandle(hndl); - - //Skip CTFWeaponBaseMelee::CalcIsAttackCriticalHelperNoCrits if m_iNextMeleeCrit is not 2 - if (bMeleeNoCrits) - { - CBaseEntity *pPlayer = UTIL_GetCBaseEntity(index, true); - if (pPlayer && *(uint32_t *)((intptr_t)pPlayer + nextMeleeCritOffset) != 2) - return Result_Ignore; - } - - g_critForward->PushCell(index); //Client index - g_critForward->PushCell(engine->IndexOfEdict(pEdict)); // Weapon index - g_critForward->PushString(pEdict->GetClassName()); //Weapon classname + g_critForward->PushCell(ownerIndex); //Client index + g_critForward->PushCell(gamehelpers->EntityToBCompatRef(pWeapon)); // Weapon index + g_critForward->PushString(gamehelpers->GetEntityClassname(pWeapon)); //Weapon classname g_critForward->PushCellByRef(&returnValue); //return value cell_t result = 0; g_critForward->Execute(&result); - if (result) + if (result && returnValue) { - if (returnValue) - { - return Result_Crit; - } - else - { - return Result_NoCrit; - } - } - else - { - return Result_Ignore; - } -} - -DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelperMelee, bool) -{ - DetourResult result = DetourCallback((CBaseEntity *)this, false); - - if (result == Result_Ignore) - { - return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelperMelee)(); - } - else if (result == Result_NoCrit) - { - return 0; - } - else - { - return 1; - } -} - -DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelper, bool) -{ - DetourResult result = DetourCallback((CBaseEntity *)this, false); - - if (result == Result_Ignore) - { - return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelper)(); - } - else if (result == Result_NoCrit) - { - return 0; - } - else - { - return 1; - } -} - -DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelperBow, bool) -{ - DetourResult result = DetourCallback((CBaseEntity *)this, false); - - if (result == Result_Ignore) - { - return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelperBow)(); - } - else if (result == Result_NoCrit) - { - return 0; - } - else - { - return 1; - } -} - -DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelperKnife, bool) -{ - DetourResult result = DetourCallback((CBaseEntity *)this, false); - - if (result == Result_Ignore) - { - return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelperKnife)(); - } - else if (result == Result_NoCrit) - { - return 0; - } - else - { - return 1; - } -} - -DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelperNoCrits, bool) -{ - DetourResult result = DetourCallback((CBaseEntity *)this, false); - - if (result == Result_Ignore) - { - return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelperNoCrits)(); - } - else if (result == Result_NoCrit) - { - return 0; - } - else - { - return 1; - } -} - -DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelperNoCritsMelee, bool) -{ - DetourResult result = DetourCallback((CBaseEntity *)this, true); - - if (result == Result_Ignore) - { - return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelperNoCritsMelee)(); - } - else if (result == Result_NoCrit) - { - return 0; - } - else - { - return 1; - } -} - -bool InitialiseCritDetours() -{ - sm_sendprop_info_t prop; - - calcIsAttackCriticalDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelper, "CalcCritical"); - calcIsAttackCriticalMeleeDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelperMelee, "CalcCriticalMelee"); - calcIsAttackCriticalBowDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelperBow, "CalcCriticalBow"); - calcIsAttackCriticalKnifeDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelperKnife, "CalcCriticalKnife"); - calcIsAttackCriticalNoCritsDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelperNoCrits, "CalcCriticalNoCrits"); - calcIsAttackCriticalNoCritsMeleeDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelperNoCritsMelee, "CalcCriticalNoCritsMelee"); - - bool HookCreated = false; - - if (calcIsAttackCriticalDetour != NULL) - { - calcIsAttackCriticalDetour->EnableDetour(); - HookCreated = true; - } - - if (calcIsAttackCriticalMeleeDetour != NULL) - { - calcIsAttackCriticalMeleeDetour->EnableDetour(); - HookCreated = true; - } - - if (calcIsAttackCriticalBowDetour != NULL) - { - calcIsAttackCriticalBowDetour->EnableDetour(); - HookCreated = true; - } - - if (calcIsAttackCriticalKnifeDetour != NULL) - { - calcIsAttackCriticalKnifeDetour->EnableDetour(); - HookCreated = true; - } - - if (calcIsAttackCriticalNoCritsDetour != NULL) - { - calcIsAttackCriticalNoCritsDetour->EnableDetour(); - HookCreated = true; - } - - if (calcIsAttackCriticalNoCritsMeleeDetour != NULL) - { - calcIsAttackCriticalNoCritsMeleeDetour->EnableDetour(); - if (!gamehelpers->FindSendPropInfo("CTFPlayer", "m_iNextMeleeCrit", &prop)) - { - g_pSM->LogError(myself, "Failed to find m_iNextMeleeCrit prop offset"); - return false; - } - nextMeleeCritOffset = prop.actual_offset; - HookCreated = true; - } - - if (HookCreated) - { - return true; - } - - g_pSM->LogError(myself, "No critical hit forwards could be initialized - Disabled critical hit hooks"); - - return false; -} - -void RemoveCritDetours() -{ - if (calcIsAttackCriticalDetour != NULL) - { - calcIsAttackCriticalDetour->Destroy(); - calcIsAttackCriticalDetour = NULL; - } - - if (calcIsAttackCriticalMeleeDetour != NULL) - { - calcIsAttackCriticalMeleeDetour->Destroy(); - calcIsAttackCriticalMeleeDetour = NULL; - } - - if (calcIsAttackCriticalBowDetour != NULL) - { - calcIsAttackCriticalBowDetour->Destroy(); - calcIsAttackCriticalBowDetour = NULL; + RETURN_META_VALUE(MRES_SUPERCEDE, true); } - if (calcIsAttackCriticalKnifeDetour != NULL) - { - calcIsAttackCriticalKnifeDetour->Destroy(); - calcIsAttackCriticalKnifeDetour = NULL; - } - - if (calcIsAttackCriticalNoCritsDetour != NULL) - { - calcIsAttackCriticalNoCritsDetour->Destroy(); - calcIsAttackCriticalNoCritsDetour = NULL; - } - - if (calcIsAttackCriticalNoCritsMeleeDetour != NULL) - { - calcIsAttackCriticalNoCritsMeleeDetour->Destroy(); - calcIsAttackCriticalNoCritsMeleeDetour = NULL; - } + RETURN_META_VALUE(MRES_IGNORED, false); } diff --git a/extensions/tf2/criticals.h b/extensions/tf2/criticals.h index e0f5722d..2b00243c 100644 --- a/extensions/tf2/criticals.h +++ b/extensions/tf2/criticals.h @@ -36,12 +36,38 @@ #include #include #include "CDetour/detours.h" +#include "ISDKHooks.h" -bool InitialiseCritDetours(); -void RemoveCritDetours(); +class CritManager : public ISMEntityListener +{ +public: + CritManager(); + +public: + bool TryEnable(); + void Disable(); + + // ISMEntityListener +public: + virtual void OnEntityCreated(CBaseEntity *pEntity, const char *classname); + virtual void OnEntityDestroyed(CBaseEntity *pEntity); + +private: + void HookEntityIfWeapon(CBaseEntity *pEntity); + void UnhookEntityIfHooked(CBaseEntity *pEntity); + +public: + // CritHook + bool Hook_CalcIsAttackCriticalHelpers(); + +private: + bool m_enabled; + bool m_hooksSetup; + CBitVec m_entsHooked; +}; + +extern CritManager g_CritManager; extern IForward *g_critForward; -extern IServerGameEnts *gameents; - #endif //_INCLUDE_SOURCEMOD_CRITICALS_H_ diff --git a/extensions/tf2/extension.cpp b/extensions/tf2/extension.cpp index 2ee558ec..61bf01fe 100644 --- a/extensions/tf2/extension.cpp +++ b/extensions/tf2/extension.cpp @@ -41,6 +41,7 @@ #include "gameplayrules.h" #include "teleporter.h" #include "CDetour/detours.h" +#include "ISDKHooks.h" /** * @file extension.cpp @@ -52,6 +53,7 @@ TF2Tools g_TF2Tools; IGameConfig *g_pGameConf = NULL; IBinTools *g_pBinTools = NULL; +ISDKHooks *g_pSDKHooks = NULL; SMEXT_LINK(&g_TF2Tools); @@ -91,6 +93,7 @@ bool TF2Tools::SDK_OnLoad(char *error, size_t maxlength, bool late) } sharesys->AddDependency(myself, "bintools.ext", true, true); + sharesys->AddDependency(myself, "sdkhooks.ext", true, true); char conf_error[255] = ""; if (!gameconfs->LoadGameConfigFile("sm-tf2.games", &g_pGameConf, conf_error, sizeof(conf_error))) @@ -151,8 +154,6 @@ bool TF2Tools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION); - GET_V_IFACE_CURRENT(GetServerFactory, gameents, IServerGameEnts, INTERFACEVERSION_SERVERGAMEENTS); - GET_V_IFACE_CURRENT(GetEngineFactory, m_GameEventManager, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2); m_GameEventManager->AddListener(this, "teamplay_restart_round", true); @@ -177,11 +178,22 @@ void TF2Tools::SDK_OnUnload() forwards->ReleaseForward(g_waitingPlayersStartForward); forwards->ReleaseForward(g_waitingPlayersEndForward); forwards->ReleaseForward(g_teleportForward); + + if (g_pSDKHooks != nullptr) + { + g_pSDKHooks->RemoveEntityListener(&g_CritManager); + } } void TF2Tools::SDK_OnAllLoaded() { SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools); + SM_GET_LATE_IFACE(SDKHOOKS, g_pSDKHooks); + + if (g_pSDKHooks != nullptr) + { + g_pSDKHooks->AddEntityListener(&g_CritManager); + } } bool TF2Tools::RegisterConCommandBase(ConCommandBase *pVar) @@ -198,6 +210,7 @@ void TF2Tools::FireGameEvent( IGameEvent *event ) bool TF2Tools::QueryRunning(char *error, size_t maxlength) { SM_CHECK_IFACE(BINTOOLS, g_pBinTools); + SM_GET_LATE_IFACE(SDKHOOKS, g_pSDKHooks); return true; } @@ -209,6 +222,11 @@ bool TF2Tools::QueryInterfaceDrop(SMInterface *pInterface) return false; } + if (pInterface == g_pSDKHooks) + { + return false; + } + return IExtensionInterface::QueryInterfaceDrop(pInterface); } @@ -321,7 +339,7 @@ void TF2Tools::OnPluginLoaded(IPlugin *plugin) { if (!m_CritDetoursEnabled && g_critForward->GetFunctionCount()) { - m_CritDetoursEnabled = InitialiseCritDetours(); + m_CritDetoursEnabled = g_CritManager.TryEnable(); } if (!m_IsHolidayDetourEnabled && g_isHolidayForward->GetFunctionCount()) @@ -353,7 +371,7 @@ void TF2Tools::OnPluginUnloaded(IPlugin *plugin) { if (m_CritDetoursEnabled && !g_critForward->GetFunctionCount()) { - RemoveCritDetours(); + g_CritManager.Disable(); m_CritDetoursEnabled = false; } if (m_IsHolidayDetourEnabled && !g_isHolidayForward->GetFunctionCount()) diff --git a/extensions/tf2/util.cpp b/extensions/tf2/util.cpp index 2ed61f43..1e3a54d9 100644 --- a/extensions/tf2/util.cpp +++ b/extensions/tf2/util.cpp @@ -88,6 +88,38 @@ bool UTIL_FindDataTable(SendTable *pTable, return false; } +bool UTIL_ContainsDataTable(SendTable *pTable, const char *name) +{ + const char *pname = pTable->GetName(); + int props = pTable->GetNumProps(); + SendProp *prop; + SendTable *table; + + if (pname && strcmp(name, pname) == 0) + return true; + + for (int i = 0; i < props; i++) + { + prop = pTable->GetProp(i); + + if ((table = prop->GetDataTable()) != NULL) + { + pname = table->GetName(); + if (pname && strcmp(name, pname) == 0) + { + return true; + } + + if (UTIL_ContainsDataTable(table, name)) + { + return true; + } + } + } + + return false; +} + ServerClass *UTIL_FindServerClass(const char *classname) { ServerClass *sc = gamedll->GetAllServerClasses(); diff --git a/extensions/tf2/util.h b/extensions/tf2/util.h index a79f09d0..a1b48dec 100644 --- a/extensions/tf2/util.h +++ b/extensions/tf2/util.h @@ -49,6 +49,8 @@ bool UTIL_FindDataTable(SendTable *pTable, sm_sendprop_info_t *info, unsigned int offset); +bool UTIL_ContainsDataTable(SendTable *pTable, const char *name); + ServerClass *UTIL_FindServerClass(const char *classname); CBaseEntity *UTIL_GetCBaseEntity(int num, bool onlyPlayers); diff --git a/gamedata/sm-tf2.games.txt b/gamedata/sm-tf2.games.txt index 8c980b33..49fca49e 100644 --- a/gamedata/sm-tf2.games.txt +++ b/gamedata/sm-tf2.games.txt @@ -36,48 +36,6 @@ "linux" "@_ZN15CTFPlayerShared8DisguiseEiiP9CTFPlayerb" "mac" "@_ZN15CTFPlayerShared8DisguiseEiiP9CTFPlayerb" } - "CalcCritical" - { - "library" "server" - "linux" "@_ZN13CTFWeaponBase26CalcIsAttackCriticalHelperEv" - "mac" "@_ZN13CTFWeaponBase26CalcIsAttackCriticalHelperEv" - "windows" "\x55\x8B\xEC\x83\xEC\x2A\x56\x57\x6A\x00\x68\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\x6A\x00\x8B\xF1\xE8\x2A\x2A\x2A\x2A\x50\xE8\x2A\x2A\x2A\x2A\x8B\xF8\x83\xC4\x2A\x85\xFF\x74\x2A\x8B" - } - "CalcCriticalMelee" - { - "library" "server" - "linux" "@_ZN18CTFWeaponBaseMelee26CalcIsAttackCriticalHelperEv" - "mac" "@_ZN18CTFWeaponBaseMelee26CalcIsAttackCriticalHelperEv" - "windows" "\x55\x8B\xEC\x83\xEC\x08\x53\x56\x8B\xF1\xE8\x2A\x2A\x2A\x2A\x8B\xD8\x85\xDB\x74\x10" - } - "CalcCriticalBow" - { - "library" "server" - "linux" "@_ZN14CTFCompoundBow26CalcIsAttackCriticalHelperEv" - "mac" "@_ZN14CTFCompoundBow26CalcIsAttackCriticalHelperEv" - "windows" "\xE8\x2A\x2A\x2A\x2A\x85\xC0\x74\x2A\x8D\x88\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x84\xC0\x74\x2A\xB0" - } - "CalcCriticalKnife" - { - "library" "server" - "linux" "@_ZN8CTFKnife26CalcIsAttackCriticalHelperEv" - "mac" "@_ZN8CTFKnife26CalcIsAttackCriticalHelperEv" - "windows" "\x8B\x81\x54\x07\x00\x00\x83\xF8\xFF\x74\x2A\x8B\x15\x2A\x2A\x2A\x2A\x8B\xC8\x81\xE1\xFF\x0F\x00\x00\x03\xC9\x8D\x4C\xCA\x04\xC1\xE8\x0C\x39\x41\x04\x75\x2A\x8B\x01" - } - "CalcCriticalNoCrits" - { - "library" "server" - "linux" "@_ZN13CTFWeaponBase33CalcIsAttackCriticalHelperNoCritsEv" - "mac" "@_ZN13CTFWeaponBase33CalcIsAttackCriticalHelperNoCritsEv" - "windows" "\x56\x6A\x00\x68\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\x6A\x00\xE8\x2A\x2A\x2A\x2A\x50\xE8\x2A\x2A\x2A\x2A\x8B\xF0\x83\xC4\x14\x85\xF6\x74\x2A" - } - "CalcCriticalNoCritsMelee" - { - "library" "server" - "linux" "@_ZN18CTFWeaponBaseMelee33CalcIsAttackCriticalHelperNoCritsEv" - "mac" "@_ZN18CTFWeaponBaseMelee33CalcIsAttackCriticalHelperNoCritsEv" - "windows" "\x56\x57\x8B\xF9\xE8\x2A\x2A\x2A\x2A\x8B\xF0\x85\xF6\x74\x2A\x8B\x06\x8B\x90\x40\x01\x00\x00\x8B\xCE\xFF\xD2\x84\xC0\x75\x2A\x5F\x32\xC0\x5E\xC3\x83\xBE\x80\x1D\x00\x00\x02" - } "Regenerate" { "library" "server" @@ -157,6 +115,18 @@ "linux" "325" "mac" "325" } + "CalcIsAttackCriticalHelper" + { + "windows" "381" + "linux" "388" + "mac" "388" + } + "CalcIsAttackCriticalHelperNoCrits" + { + "windows" "382" + "linux" "389" + "mac" "389" + } } } }