From 08dcfe7ffdf3d5e64da0898914f8b4c993681fe4 Mon Sep 17 00:00:00 2001 From: TotallyNotElite <1yourexperiment@protonmail.com> Date: Fri, 22 May 2020 00:26:42 +0200 Subject: [PATCH] Dynamically allocate entity hitbox cache to reduce memory usage. --- include/entitycache.hpp | 1 + include/entityhitboxcache.hpp | 7 ++++--- report-crash | 1 - src/crits.cpp | 8 ++++---- src/entitycache.cpp | 9 +++++++++ src/entityhitboxcache.cpp | 37 ++++++++++++++++++++++++----------- src/hooks/HookTools.cpp | 3 +-- src/hooks/LevelShutdown.cpp | 2 ++ 8 files changed, 47 insertions(+), 21 deletions(-) diff --git a/include/entitycache.hpp b/include/entitycache.hpp index 9f59b74b1..a4dcd27e8 100644 --- a/include/entitycache.hpp +++ b/include/entitycache.hpp @@ -224,5 +224,6 @@ inline CachedEntity &Get(int idx) } void Update(); void Invalidate(); +void Shutdown(); extern int max; } // namespace entity_cache diff --git a/include/entityhitboxcache.hpp b/include/entityhitboxcache.hpp index bb2bd7b9a..271a1c592 100644 --- a/include/entityhitboxcache.hpp +++ b/include/entityhitboxcache.hpp @@ -10,6 +10,7 @@ #include #include #include +#include // Forward declaration from entitycache.hpp class CachedEntity; @@ -39,7 +40,7 @@ class EntityHitboxCache 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 @@ class EntityHitboxCache 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 m_CacheInternal; - matrix3x4_t bones[128]; + std::vector bones; bool bones_setup{ false }; }; diff --git a/report-crash b/report-crash index 1cfa57e35..4b37f1a1a 100755 --- a/report-crash +++ b/report-crash @@ -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 diff --git a/src/crits.cpp b/src/crits.cpp index 98caf8c98..9c5d02ed6 100644 --- a/src/crits.cpp +++ b/src/crits.cpp @@ -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)) { diff --git a/src/entitycache.cpp b/src/entitycache.cpp index 8e05a12d1..4d8d1128b 100644 --- a/src/entitycache.cpp +++ b/src/entitycache.cpp @@ -164,5 +164,14 @@ void Invalidate() } } +void Shutdown() +{ + for (auto &ent : array) + { + ent.Reset(); + ent.hitboxes.Reset(); + } +} + int max = 0; } // namespace entity_cache diff --git a/src/entityhitboxcache.cpp b/src/entityhitboxcache.cpp index 867bc09d8..deb77d3a9 100644 --- a/src/entityhitboxcache.cpp +++ b/src/entityhitboxcache.cpp @@ -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(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; diff --git a/src/hooks/HookTools.cpp b/src/hooks/HookTools.cpp index a5a1d2148..474c978e1 100644 --- a/src/hooks/HookTools.cpp +++ b/src/hooks/HookTools.cpp @@ -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; diff --git a/src/hooks/LevelShutdown.cpp b/src/hooks/LevelShutdown.cpp index 54117a779..20b139518 100644 --- a/src/hooks/LevelShutdown.cpp +++ b/src/hooks/LevelShutdown.cpp @@ -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) {