From 4e098883060c27ca398459ba132dac4cc3851295 Mon Sep 17 00:00:00 2001 From: BenCat07 Date: Thu, 14 Jul 2022 00:46:54 +0200 Subject: [PATCH] Fix crithack issues with Minigun and flamethrower --- CMakeLists.txt | 9 +++-- include/core/offsets.hpp | 4 ++ include/crits.hpp | 1 + include/hooks/HookedMethods.hpp | 2 + src/crits.cpp | 5 ++- src/hooks/RunCommand.cpp | 68 +++++++++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a3555d8..9691b4a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,8 +22,6 @@ set(CMAKE_BUILD_TYPE_VALUES "Debug;Release" CACHE INTERNAL "List of supported bu set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${CMAKE_BUILD_TYPE_VALUES}) project(cathook VERSION 0.0.1) - -set(CMAKE_CXX_STANDARD 23) add_library(cathook SHARED "") set(GameSpecific 1 CACHE BOOL "Build for specific target game (As opposed to universal, but slower, lib)") @@ -161,13 +159,18 @@ endif() configure_file(include/config.h.in ${CMAKE_SOURCE_DIR}/include/config.h @ONLY) configure_file(include/version.h.in ${CMAKE_SOURCE_DIR}/include/version.h @ONLY) -set(CMAKE_CXX_FLAGS "-m32 -march=native -fexceptions -fno-gnu-unique -DNDEBUG") +set(CMAKE_CXX_FLAGS "-m32 -march=native -fexceptions -DNDEBUG") +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-gnu-unique") +endif() set(CMAKE_CXX_FLAGS_DEBUG "-march=native -rdynamic -ggdb -Og") if (Internal_Symbolized) set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -ggdb -fvisibility=hidden -fvisibility-inlines-hidden") else() set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -s -fvisibility=hidden -fvisibility-inlines-hidden") endif() +set(CMAKE_CXX_FLAGS "-std=gnu++2b ${CMAKE_CXX_FLAGS}") + target_compile_definitions(cathook PRIVATE _GLIBCXX_USE_CXX11_ABI=0 diff --git a/include/core/offsets.hpp b/include/core/offsets.hpp index 69647f1b..69cb445d 100644 --- a/include/core/offsets.hpp +++ b/include/core/offsets.hpp @@ -232,4 +232,8 @@ struct offsets { return PlatformOffset(27, undefined, undefined); } + static constexpr uint32_t CalcIsAttackCriticalHelper_brokenweps() + { + return PlatformOffset(464, undefined, 464); + } }; diff --git a/include/crits.hpp b/include/crits.hpp index b6a98e8f..22f3c217 100644 --- a/include/crits.hpp +++ b/include/crits.hpp @@ -8,6 +8,7 @@ extern settings::Boolean enabled; extern settings::Boolean melee; extern std::map> crit_cmds; extern size_t current_index; +extern bool calling_crithelper; extern bool isEnabled(); extern bool force_crit_this_tick; void fixBucket(IClientEntity *weapon, CUserCmd *cmd); diff --git a/include/hooks/HookedMethods.hpp b/include/hooks/HookedMethods.hpp index a9da7c9d..30115f03 100644 --- a/include/hooks/HookedMethods.hpp +++ b/include/hooks/HookedMethods.hpp @@ -96,6 +96,8 @@ DECLARE_HOOKED_METHOD(EmitSound3, void, void *, IRecipientFilter &, int, int, in DECLARE_HOOKED_METHOD(RunCommand, void, IPrediction *, IClientEntity *, CUserCmd *, IMoveHelper *); // g_IToolFramework DECLARE_HOOKED_METHOD(Think, void, IToolFrameworkInternal *, bool); +// CTFMinigun and CTFFlameThrower +DECLARE_HOOKED_METHOD(CalcIsAttackCriticalHelper_brokenweps, bool, IClientEntity *); } // namespace hooked_methods // TODO diff --git a/src/crits.cpp b/src/crits.cpp index 5706c77a..950b0e3c 100644 --- a/src/crits.cpp +++ b/src/crits.cpp @@ -39,6 +39,7 @@ static bool is_out_of_sync = false; // Optimization static int shots_to_fill_bucket = 0; +bool calling_crithelper = false; static float getBucketCap() { static ConVar *tf_weapon_criticals_bucket_cap = g_ICvar->FindVar("tf_weapon_criticals_bucket_cap"); @@ -220,7 +221,9 @@ static int nextCritTick(int loops = 4096) *g_PredictionRandomSeed = MD5_PseudoRandom(cmd_number) & 0x7FFFFFFF; // Save weapon state to not break anything weapon_info info(wep); - bool is_crit = re::C_TFWeaponBase::CalcIsAttackCritical(wep); + calling_crithelper = true; + bool is_crit = re::C_TFWeaponBase::CalcIsAttackCritical(wep); + calling_crithelper = false; // Restore state info.restore_data(wep); // Is a crit diff --git a/src/hooks/RunCommand.cpp b/src/hooks/RunCommand.cpp index ed019c0d..1d2d924f 100644 --- a/src/hooks/RunCommand.cpp +++ b/src/hooks/RunCommand.cpp @@ -1,5 +1,6 @@ #include "HookedMethods.hpp" +#include "WeaponData.hpp" namespace hooked_methods { @@ -17,4 +18,71 @@ DEFINE_HOOKED_METHOD(RunCommand, void, IPrediction *prediction, IClientEntity *e else return original::RunCommand(prediction, entity, usercmd, move); } + +static std::map previous_ammo; + +// Also fix heavy M2 causing bucket to fill faster, same for pyro +DEFINE_HOOKED_METHOD(CalcIsAttackCriticalHelper_brokenweps, bool, IClientEntity *ent) +{ + if (CE_GOOD(LOCAL_E) && CE_GOOD(LOCAL_W) && ent && re::C_TFWeaponBase::GetOwnerViaInterface(ent) == LOCAL_E->InternalEntity() && !criticals::calling_crithelper) + { + auto current_ammo = CE_INT(LOCAL_E, netvar.m_iAmmo + 4); + if (previous_ammo[ent->entindex()] == current_ammo) + { + weapon_info info(ent); + auto ret = original::CalcIsAttackCriticalHelper_brokenweps(ent); + info.restore_data(ent); + return ret; + } + previous_ammo[ent->entindex()] = current_ammo; + } + + if (LOCAL_W->m_iClassID() == CL_CLASS(CTFMinigun)) + { + int weapon_mode = NET_INT(ent, 0xb08); + NET_INT(ent, 0xb08) = 0; + auto ret = original::CalcIsAttackCriticalHelper_brokenweps(ent); + NET_INT(ent, 0xb08) = weapon_mode; + return ret; + } + else + return original::CalcIsAttackCriticalHelper_brokenweps(ent); +} + +static hooks::VMTHook minigun_hook{}; +static Timer minigun_check_timer{}; +static InitRoutine minigun_check( + []() + { + EC::Register( + EC::CreateMove, + []() + { + if (CE_BAD(LOCAL_E) || HasCondition(LOCAL_E) || !LOCAL_E->m_bAlivePlayer() || !minigun_check_timer.test_and_set(1000)) + return; + // Grab the handle and store it into the var + int *hWeapons = &CE_INT(LOCAL_E, netvar.hMyWeapons); + if (!hWeapons) + return; + // Go through the handle array and search for the item + for (int i = 0; hWeapons[i]; i++) + { + if (IDX_BAD(HandleToIDX(hWeapons[i]))) + continue; + // Get the weapon + CachedEntity *weapon = ENTITY(HandleToIDX(hWeapons[i])); + // if weapon is what we are looking for, hook and move on + if (CE_VALID(weapon) && (weapon->m_iClassID() == CL_CLASS(CTFMinigun) || weapon->m_iClassID() == CL_CLASS(CTFFlameThrower)) && !minigun_hook.IsHooked(weapon->InternalEntity())) + { + logging::Info("Found and hooked Minigun/Flamethrower!"); + minigun_hook.Set(weapon->InternalEntity()); + minigun_hook.HookMethod(HOOK_ARGS(CalcIsAttackCriticalHelper_brokenweps)); + minigun_hook.Apply(); + break; + } + } + }, + "cm_runcommand"); + }); + } // namespace hooked_methods