Merge pull request #1037 from nullworks/totallynotelite

Dyamic hitbox cache + remove gru exploit
This commit is contained in:
TotallyNotElite 2020-05-27 10:42:22 +02:00 committed by GitHub
commit 99c0390d95
10 changed files with 47 additions and 233 deletions

View File

@ -224,5 +224,6 @@ inline CachedEntity &Get(int idx)
}
void Update();
void Invalidate();
void Shutdown();
extern int max;
} // namespace entity_cache

View File

@ -10,6 +10,7 @@
#include <cdll_int.h>
#include <studio.h>
#include <stdexcept>
#include <memory>
// Forward declaration from entitycache.hpp
class CachedEntity;
@ -39,7 +40,7 @@ public:
void Init();
int GetNumHitboxes();
void Reset();
matrix3x4_t *GetBones();
matrix3x4_t *GetBones(int numbones = -1);
int m_nNumHitboxes;
bool m_bModelSet;
@ -52,9 +53,9 @@ public:
bool m_VisCheckValidationFlags[CACHE_MAX_HITBOXES]{ false };
bool m_VisCheck[CACHE_MAX_HITBOXES]{ false };
bool m_CacheValidationFlags[CACHE_MAX_HITBOXES]{ false };
CachedHitbox m_CacheInternal[CACHE_MAX_HITBOXES]{};
std::vector<CachedHitbox> m_CacheInternal;
matrix3x4_t bones[128];
std::vector<matrix3x4_t> bones;
bool bones_setup{ false };
};

View File

@ -78,7 +78,6 @@ has_debug_info "$CATHOOK" || SYMBOLS=false
if [ $SYMBOLS == false ]; then
echo "No debug symbols detected!"
proccount=$(grep -c '^processor' /proc/cpuinfo)
\cp ./build/CMakeCache.txt ./scripts/CMakeCacheBackup.txt
pushd build
cmake -DInternal_Symbolized=true .. && cmake --build . --target cathook -- -j$proccount
popd

View File

@ -326,7 +326,7 @@ bool shouldCrit()
static bool can_beggars_crit = false;
static bool attacked_last_tick = false;
bool canWeaponCrit(bool canShootCheck = true)
bool canWeaponCrit(bool draw = false)
{
// Is weapon elligible for crits?
IClientEntity *weapon = RAW_ENT(LOCAL_W);
@ -344,9 +344,9 @@ bool canWeaponCrit(bool canShootCheck = true)
// Misc checks
if (!isAllowedToWithdrawFromBucket(weapon))
return false;
if (canShootCheck && !CanShoot() && !isRapidFire(weapon))
if (!draw && !CanShoot() && !isRapidFire(weapon))
return false;
if (CE_INT(LOCAL_W, netvar.iItemDefinitionIndex) == 730 && !can_beggars_crit)
if (!draw && CE_INT(LOCAL_W, netvar.iItemDefinitionIndex) == 730 && !can_beggars_crit)
return false;
// Check if we have done enough damage to crit
auto crit_mult_info = critMultInfo(weapon);
@ -752,7 +752,7 @@ void Draw()
// fixObservedCritchance(wep);
// Used by multiple things
bool can_crit = canWeaponCrit(false);
bool can_crit = canWeaponCrit(true);
if (bucket != last_bucket || wep->entindex() != last_wep || update_shots.test_and_set(500))
{

View File

@ -164,5 +164,14 @@ void Invalidate()
}
}
void Shutdown()
{
for (auto &ent : array)
{
ent.Reset();
ent.hitboxes.Reset();
}
}
int max = 0;
} // namespace entity_cache

View File

@ -105,7 +105,7 @@ static settings::Boolean bonecache_enabled{ "source.use-bone-cache", "false" };
static std::mutex setupbones_mutex;
matrix3x4_t *EntityHitboxCache::GetBones()
matrix3x4_t *EntityHitboxCache::GetBones(int numbones)
{
static float bones_setup_time = 0.0f;
switch (*setupbones_time)
@ -126,13 +126,24 @@ matrix3x4_t *EntityHitboxCache::GetBones()
}
if (!bones_setup)
{
// If numbones is not set, get it from some terrible and unnamed variable
if (numbones == -1)
{
if (parent_ref->m_Type() == ENTITY_PLAYER)
numbones = CE_INT(parent_ref, 0x844);
else
numbones = MAXSTUDIOBONES;
}
if (bones.size() < (size_t) numbones)
bones.resize(numbones);
if (g_Settings.is_create_move)
{
#if !ENABLE_TEXTMODE
if (!*bonecache_enabled || parent_ref->m_Type() != ENTITY_PLAYER || IsPlayerInvisible(parent_ref))
{
PROF_SECTION(bone_setup);
bones_setup = RAW_ENT(parent_ref)->SetupBones(bones, MAXSTUDIOBONES, 0x7FF00, bones_setup_time);
bones_setup = RAW_ENT(parent_ref)->SetupBones(bones.data(), numbones, 0x7FF00, bones_setup_time);
}
else
{
@ -140,24 +151,24 @@ matrix3x4_t *EntityHitboxCache::GetBones()
auto to_copy = CE_VAR(parent_ref, 0x838, matrix3x4_t *);
if (to_copy)
{
bones->Invalidate();
memcpy((matrix3x4_t *) bones, to_copy, 48 * (CE_INT(parent_ref, 0x844)));
// This is catastrophically bad, don't do this. Someone needs to fix this.
memcpy(bones.data(), to_copy, sizeof(matrix3x4_t) * numbones);
bones_setup = true;
}
else
{
PROF_SECTION(bone_setup);
bones_setup = RAW_ENT(parent_ref)->SetupBones(bones, MAXSTUDIOBONES, 0x7FF00, bones_setup_time);
bones_setup = RAW_ENT(parent_ref)->SetupBones(bones.data(), numbones, 0x7FF00, bones_setup_time);
}
}
#else
// Textmode bots miss/shoot at nothing when the tf2 bonecache is used
PROF_SECTION(bone_setup);
bones_setup = RAW_ENT(parent_ref)->SetupBones(bones, MAXSTUDIOBONES, 0x7FF00, bones_setup_time);
bones_setup = RAW_ENT(parent_ref)->SetupBones(bones, numbones, 0x7FF00, bones_setup_time);
#endif
}
}
return bones;
return bones.data();
}
void EntityHitboxCache::Reset()
@ -165,8 +176,10 @@ void EntityHitboxCache::Reset()
memset(m_VisCheck, 0, sizeof(bool) * CACHE_MAX_HITBOXES);
memset(m_VisCheckValidationFlags, 0, sizeof(bool) * CACHE_MAX_HITBOXES);
memset(m_CacheValidationFlags, 0, sizeof(bool) * CACHE_MAX_HITBOXES);
memset(m_CacheInternal, 0, sizeof(CachedHitbox) * CACHE_MAX_HITBOXES);
memset(&bones, 0, sizeof(matrix3x4_t) * 128);
m_CacheInternal.clear();
m_CacheInternal.shrink_to_fit();
bones.clear();
bones.shrink_to_fit();
m_nNumHitboxes = 0;
m_bInit = false;
m_bModelSet = false;
@ -198,13 +211,15 @@ CachedHitbox *EntityHitboxCache::GetHitbox(int id)
auto set = shdr->pHitboxSet(CE_INT(parent_ref, netvar.iHitboxSet));
if (!dynamic_cast<mstudiohitboxset_t *>(set))
return nullptr;
if (m_nNumHitboxes > m_CacheInternal.size())
m_CacheInternal.resize(m_nNumHitboxes);
box = set->pHitbox(id);
if (!box)
return nullptr;
if (box->bone < 0 || box->bone >= MAXSTUDIOBONES)
return nullptr;
VectorTransform(box->bbmin, GetBones()[box->bone], m_CacheInternal[id].min);
VectorTransform(box->bbmax, GetBones()[box->bone], m_CacheInternal[id].max);
VectorTransform(box->bbmin, GetBones(shdr->numbones)[box->bone], m_CacheInternal[id].min);
VectorTransform(box->bbmax, GetBones(shdr->numbones)[box->bone], m_CacheInternal[id].max);
m_CacheInternal[id].bbox = box;
m_CacheInternal[id].center = (m_CacheInternal[id].min + m_CacheInternal[id].max) / 2;
m_CacheValidationFlags[id] = true;

View File

@ -24,7 +24,6 @@ set(files "${CMAKE_CURRENT_LIST_DIR}/AutoJoin.cpp"
"${CMAKE_CURRENT_LIST_DIR}/ChatCommands.cpp"
"${CMAKE_CURRENT_LIST_DIR}/CritSay.cpp"
"${CMAKE_CURRENT_LIST_DIR}/DataCenter.cpp"
"${CMAKE_CURRENT_LIST_DIR}/Exploits.cpp"
"${CMAKE_CURRENT_LIST_DIR}/FollowBot.cpp"
"${CMAKE_CURRENT_LIST_DIR}/KillSay.cpp"
"${CMAKE_CURRENT_LIST_DIR}/DominateSay.cpp"

View File

@ -1,211 +0,0 @@
#include "globals.h"
#include "HookTools.hpp"
#include "localplayer.hpp"
#include "init.hpp"
#include "cvwrapper.hpp"
#include "timer.hpp"
#include "hack.hpp"
#if ENABLE_VISUALS
#include "drawing.hpp"
#endif
namespace hacks::tf2::exploits
{
namespace heavy_health
{
enum STEPS
{
STEP_OFF = -1,
STEP_START,
STEP_INIT,
STEP_INIT_HEAVY,
STEP_INIT_MELEE,
STEP_KILL,
STEP_RANDOMCLASS,
STEP_HEAVY,
STEP_PRIMARY,
STEP_MONITOR,
STEP_MONITOR_HEAVY
};
static STEPS step = STEP_OFF;
static unsigned long start_tick = 0;
// Attempts to get the glitch working if it fails
static unsigned loops = 0;
static bool tf_remember_activeweapon_was_false;
static Timer timeout{};
static Timer commands_timer{};
void retry()
{
if (loops++ < 3)
{
timeout.update();
step = STEP_INIT;
}
else
step = STEP_OFF;
}
void CM()
{
static auto tf_remember_activeweapon = g_ICvar->FindVar("tf_remember_activeweapon");
switch (step)
{
case STEP_OFF:
if (tf_remember_activeweapon_was_false)
{
tf_remember_activeweapon->SetValue(false);
tf_remember_activeweapon_was_false = false;
}
break;
case STEP_START:
if (!tf_remember_activeweapon->GetBool())
{
tf_remember_activeweapon->SetValue(true);
tf_remember_activeweapon_was_false = true;
}
loops = 0;
timeout.update();
case STEP_INIT:
// Dead
if (g_pLocalPlayer->life_state)
{
step = STEP_OFF;
return;
}
if (g_pLocalPlayer->clazz != tf_heavy)
{
step = STEP_INIT_HEAVY;
return;
}
if (g_pLocalPlayer->weapon_mode != weapon_melee)
{
step = STEP_INIT_MELEE;
return;
}
step = STEP_RANDOMCLASS;
break;
case STEP_INIT_HEAVY:
if (g_pLocalPlayer->clazz == tf_heavy && !g_pLocalPlayer->life_state)
{
step = STEP_INIT_MELEE;
return;
}
if (timeout.check(5000))
{
retry();
return;
}
if (commands_timer.test_and_set(500))
{
g_IEngine->ClientCmd_Unrestricted("join_class heavyweapons");
}
break;
case STEP_INIT_MELEE:
if (g_pLocalPlayer->weapon_mode == weapon_melee)
{
step = STEP_KILL;
return;
}
if (timeout.check(5000))
{
retry();
return;
}
if (commands_timer.test_and_set(500))
g_IEngine->ClientCmd_Unrestricted("slot3");
break;
case STEP_KILL:
if (timeout.check(5000))
{
retry();
return;
}
if (commands_timer.test_and_set(500))
{
if (g_pLocalPlayer->life_state)
{
step = STEP_RANDOMCLASS;
return;
}
g_IEngine->ClientCmd_Unrestricted("kill");
}
break;
case STEP_RANDOMCLASS:
if (g_pLocalPlayer->clazz == tf_demoman && !g_pLocalPlayer->life_state)
{
step = STEP_HEAVY;
return;
}
if (timeout.check(5000))
{
retry();
return;
}
if (commands_timer.test_and_set(500))
g_IEngine->ClientCmd_Unrestricted("join_class demoman");
break;
case STEP_HEAVY:
if (commands_timer.test_and_set(1000))
{
g_IEngine->ClientCmd_Unrestricted("join_class heavyweapons;use *");
step = STEP_PRIMARY;
}
break;
case STEP_PRIMARY:
g_IEngine->ClientCmd_Unrestricted("use *");
step = STEP_MONITOR;
start_tick = tickcount;
break;
case STEP_MONITOR:
if (tickcount - start_tick < 33)
{
if (g_pLocalPlayer->clazz == tf_heavy && g_pLocalPlayer->health != 300)
{
retry();
}
}
else if (g_pLocalPlayer->clazz == tf_heavy && g_pLocalPlayer->weapon_mode != weapon_melee)
{
step = STEP_MONITOR_HEAVY;
}
else
retry();
break;
case STEP_MONITOR_HEAVY:
if (g_pLocalPlayer->weapon_mode == weapon_melee || g_pLocalPlayer->clazz != tf_heavy)
{
step = STEP_OFF;
}
break;
}
}
#if ENABLE_VISUALS
void draw()
{
if (step == STEP_MONITOR_HEAVY)
AddSideString("Heavy health exploit charging duration: " + std::to_string(int((tickcount - start_tick) * g_GlobalVars->interval_per_tick)), colors::orange);
}
#endif
static CatCommand exploit_heavyhealth("exploit_heavyhealth", "Activates the heavy health exploit", []() { step = STEP_START; });
} // namespace heavy_health
void CreateMove()
{
heavy_health::CM();
}
#if ENABLE_VISUALS
void Draw()
{
heavy_health::draw();
}
#endif
static InitRoutine init([]() {
EC::Register(EC::CreateMove, CreateMove, "cm_exploits");
#if ENABLE_VISUALS
EC::Register(EC::Draw, Draw, "draw_exploits");
#endif
});
} // namespace hacks::tf2::exploits

View File

@ -6,9 +6,8 @@ namespace EC
struct EventCallbackData
{
explicit EventCallbackData(const EventFunction &function, std::string name, enum ec_priority priority) : function{ function }, priority{ int(priority) }, section{ name }, event_name{ name }
explicit EventCallbackData(const EventFunction &function, std::string name, enum ec_priority priority) : function{ function }, priority{ int(priority) }, section(name), event_name{ name }
{
section.m_name = name;
}
EventFunction function;
int priority;

View File

@ -17,6 +17,8 @@ DEFINE_HOOKED_METHOD(LevelShutdown, void, void *this_)
g_Settings.bInvalid = true;
chat_stack::Reset();
EC::run(EC::LevelShutdown);
// Free memory for hitbox cache
entity_cache::Shutdown();
#if ENABLE_IPC
if (ipc::peer)
{