diff --git a/.autotools b/.autotools new file mode 100644 index 00000000..538972ac --- /dev/null +++ b/.autotools @@ -0,0 +1,83 @@ + + + + + + + diff --git a/.gitmodules b/.gitmodules old mode 100755 new mode 100644 index 84ae995f..2a79a1e6 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "external/co-library"] path = external/co-library url = https://github.com/nullworks/co-library.git +[submodule "external/TF2_NavFile_Reader"] + path = external/TF2_NavFile_Reader + url = https://github.com/nullworks/TF2_NavFile_Reader.git diff --git a/CMakeLists.txt b/CMakeLists.txt index ce8916c5..9ba09794 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,7 +110,8 @@ target_include_directories(cathook SYSTEM PRIVATE "external/source-sdk-2013-headers/mp/src/tier1" "external/source-sdk-2013-headers/mp/src") -target_include_directories(cathook PRIVATE "external/ucccccp") +target_include_directories(cathook PRIVATE "external/TF2_NavFile_Reader") +target_include_directories(cathook PRIVATE "external/PathFinder/src/") if(EnableWarnings) target_compile_options(cathook PRIVATE -Wall -Wextra) diff --git a/TF2_NavFile_Reader b/TF2_NavFile_Reader new file mode 160000 index 00000000..3bc452cb --- /dev/null +++ b/TF2_NavFile_Reader @@ -0,0 +1 @@ +Subproject commit 3bc452cbca4ab3dafadbf40fa44013a31f0b159a diff --git a/external/PathFinder b/external/PathFinder new file mode 160000 index 00000000..03bac251 --- /dev/null +++ b/external/PathFinder @@ -0,0 +1 @@ +Subproject commit 03bac25118aaa65822d036ac9f3b82124b681ad9 diff --git a/include/common.hpp b/include/common.hpp index 82e7845a..b82823c4 100755 --- a/include/common.hpp +++ b/include/common.hpp @@ -48,6 +48,8 @@ #include "core/macros.hpp" #include +#include +#include #if ENABLE_VISUALS #include diff --git a/include/core/netvars.hpp b/include/core/netvars.hpp index b22de707..cee7796b 100755 --- a/include/core/netvars.hpp +++ b/include/core/netvars.hpp @@ -11,9 +11,15 @@ class IClientEntity; +// Fix clang gay +#if defined(__clang__) +#define NET_VAR(entity, offset, type) \ + (*(reinterpret_cast(reinterpret_cast(entity) + (offset)))) +#elif defined(__GNUC__) || defined(__GNUG__) #define NET_VAR(entity, offset, type) \ (*(reinterpret_cast(reinterpret_cast(entity) + \ (offset)))) +#endif #define NET_INT(entity, offset) NET_VAR(entity, offset, int) diff --git a/include/hacks/Backtrack.hpp b/include/hacks/Backtrack.hpp index 343a69ba..cfe50210 100644 --- a/include/hacks/Backtrack.hpp +++ b/include/hacks/Backtrack.hpp @@ -25,6 +25,7 @@ struct BacktrackData float viewangles{ 0.0f }; float simtime{ 0.0f }; Vector entorigin{ 0.0f, 0.0f, 0.0f }; + int index{ 0 }; }; struct BestTickData { @@ -40,7 +41,6 @@ void Run(); void Draw(); void AddLatencyToNetchan(INetChannel *, float); void UpdateIncomingSequences(); -bool shouldBacktrack(); extern int lastincomingsequencenumber; extern int BestTick; extern int iBestTarget; @@ -60,7 +60,7 @@ typedef boost::circular_buffer_space_optimized circular_buf; extern circular_buf sequences; extern BacktrackData headPositions[32][66]; -bool isBacktrackEnabled(); +extern bool isBacktrackEnabled; float getLatency(); int getTicks(); bool ValidTick(BacktrackData &i, CachedEntity *ent); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0e7ab9cc..90a49c3a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,7 +33,8 @@ target_sources(cathook PRIVATE "${CMAKE_CURRENT_LIST_DIR}/votelogger.cpp" "${CMAKE_CURRENT_LIST_DIR}/MiscTemporary.cpp" "${CMAKE_CURRENT_LIST_DIR}/Options.cpp" - "${CMAKE_CURRENT_LIST_DIR}/PlayerTools.cpp") + "${CMAKE_CURRENT_LIST_DIR}/PlayerTools.cpp" + "${CMAKE_CURRENT_LIST_DIR}/pathfinder.cpp") add_subdirectory(core) add_subdirectory(classinfo) @@ -47,4 +48,4 @@ add_subdirectory(settings) if(EnableVisuals) add_subdirectory(visual) -endif() \ No newline at end of file +endif() diff --git a/src/hacks/Aimbot.cpp b/src/hacks/Aimbot.cpp index ebb0249c..3550c37b 100644 --- a/src/hacks/Aimbot.cpp +++ b/src/hacks/Aimbot.cpp @@ -93,10 +93,11 @@ Timer zoomTime{}; // This array will store calculated projectile/hitscan predictions // for current frame, to avoid performing them again AimbotCalculatedData_s calculated_data_array[2048]{}; +<<<<<<< Updated upstream #define IsMelee GetWeaponMode() == weapon_melee bool BacktrackAimbot() { - if (!hacks::shared::backtrack::isBacktrackEnabled() || !backtrackAimbot) + if (!hacks::shared::backtrack::isBacktrackEnabled || !*backtrackAimbot) return false; if (aimkey && !aimkey.isKeyDown()) return true; @@ -142,6 +143,7 @@ bool BacktrackAimbot() current_user_cmd->buttons |= IN_ATTACK; return true; } + // The main "loop" of the aimbot. void CreateMove() { @@ -162,25 +164,6 @@ void CreateMove() // the find target and aiming system. If we just call the func than toggle // aimkey would break so we save it to a var to use it twice bool aimkey_status = UpdateAimkey(); - // Refresh our best target - CachedEntity *target_entity = RetrieveBestTarget(aimkey_status); - if (CE_BAD(target_entity) || !foundTarget) - return; - // Auto-zoom - IF_GAME(IsTF()) - { - if (auto_zoom) - { - if (g_pLocalPlayer->holding_sniper_rifle) - { - zoomTime.update(); - if (not g_pLocalPlayer->bZoomed) - { - current_user_cmd->buttons |= IN_ATTACK2; - } - } - } - } // check if we need to run projectile Aimbot code projectileAimbotRequired = false; if (projectile_aimbot && @@ -204,8 +187,25 @@ void CreateMove() if (proj_gravity) cur_proj_grav = float(proj_gravity); } - if (BacktrackAimbot()) + // Refresh our best target + CachedEntity *target_entity = RetrieveBestTarget(aimkey_status); + if (CE_BAD(target_entity) || !foundTarget) return; + // Auto-zoom + IF_GAME(IsTF()) + { + if (auto_zoom) + { + if (g_pLocalPlayer->holding_sniper_rifle) + { + zoomTime.update(); + if (not g_pLocalPlayer->bZoomed) + { + current_user_cmd->buttons |= IN_ATTACK2; + } + } + } + } if (!g_IEntityList->GetClientEntity(target_entity->m_IDX)) return; @@ -413,50 +413,58 @@ CachedEntity *RetrieveBestTarget(bool aimkey_state) CachedEntity *ent; CachedEntity *target_highest_ent = 0; target_highest_score = -256; - - for (int i = 0; i < HIGHEST_ENTITY; i++) + if (!hacks::shared::backtrack::isBacktrackEnabled() || projectile_mode) { - ent = ENTITY(i); - if (CE_BAD(ent)) - continue; // Check for null and dormant - // Check whether the current ent is good enough to target - if (IsTargetStateGood(ent)) + for (int i = 0; i < HIGHEST_ENTITY; i++) { + ent = ENTITY(i); + if (CE_BAD(ent)) + continue; // Check for null and dormant + // Check whether the current ent is good enough to target + if (IsTargetStateGood(ent)) + { - // Distance Priority, Uses this is melee is used - if (GetWeaponMode() == weaponmode::weapon_melee || - (int) priority_mode == 2) - { - scr = 4096.0f - - calculated_data_array[i].aim_position.DistTo( - g_pLocalPlayer->v_Eye); - } - else - { - switch ((int) priority_mode) + // Distance Priority, Uses this is melee is used + if (GetWeaponMode() == weaponmode::weapon_melee || + (int) priority_mode == 2) { - case 0: // Smart Priority - scr = GetScoreForEntity(ent); - break; - case 1: // Fov Priority - scr = 360.0f - calculated_data_array[ent->m_IDX].fov; - break; - case 3: // Health Priority - scr = 450.0f - ent->m_iHealth(); - break; - default: - break; + scr = 4096.0f - + calculated_data_array[i].aim_position.DistTo( + g_pLocalPlayer->v_Eye); + } + else + { + switch ((int) priority_mode) + { + case 0: // Smart Priority + scr = GetScoreForEntity(ent); + break; + case 1: // Fov Priority + scr = 360.0f - calculated_data_array[ent->m_IDX].fov; + break; + case 3: // Health Priority + scr = 450.0f - ent->m_iHealth(); + break; + default: + break; + } + } + // Compare the top score to our current ents score + if (scr > target_highest_score) + { + foundTarget = true; + target_highest_score = scr; + target_highest_ent = ent; } - } - // Compare the top score to our current ents score - if (scr > target_highest_score) - { - foundTarget = true; - target_highest_score = scr; - target_highest_ent = ent; } } } + else if (hacks::shared::backtrack::iBestTarget != -1) + { + target_highest_ent = ENTITY(hacks::shared::backtrack::iBestTarget); + foundTarget = true; + } + // Save the ent for future use with target lock target_last = target_highest_ent; @@ -471,6 +479,9 @@ bool IsTargetStateGood(CachedEntity *entity) { PROF_SECTION(PT_aimbot_targetstatecheck); + if (hacks::shared::backtrack::isBacktrackEnabled() && + entity->m_Type() != ENTITY_PLAYER) + return false; // Checks for Players if (entity->m_Type() == ENTITY_PLAYER) { @@ -584,7 +595,7 @@ bool IsTargetStateGood(CachedEntity *entity) // Vis check + fov check if (!VischeckPredictedEntity(entity)) return false; - if ((float) fov > 0.0f && cd.fov > (float) fov) + if (*fov > 0.0f && cd.fov > *fov) return false; return true; @@ -633,7 +644,7 @@ bool IsTargetStateGood(CachedEntity *entity) // Vis and fov checks if (!VischeckPredictedEntity(entity)) return false; - if ((float) fov > 0.0f && cd.fov > (float) fov) + if (*fov > 0.0f && cd.fov > *fov) return false; return true; @@ -677,7 +688,7 @@ bool IsTargetStateGood(CachedEntity *entity) // Vis and fov check if (!VischeckPredictedEntity(entity)) return false; - if ((float) fov > 0.0f && cd.fov > (float) fov) + if (*fov > 0.0f && cd.fov > *fov) return false; return true; @@ -715,17 +726,35 @@ void Aim(CachedEntity *entity) // Get hitbox num AimbotCalculatedData_s &cd = calculated_data_array[entity->m_IDX]; float minx, maxx, miny, maxy, minz, maxz, centerx, centery, centerz; - auto hitbox = entity->hitboxes.GetHitbox(cd.hitbox); + auto hitboxmin = entity->hitboxes.GetHitbox(cd.hitbox)->min; + auto hitboxmax = entity->hitboxes.GetHitbox(cd.hitbox)->max; + auto hitboxcenter = entity->hitboxes.GetHitbox(cd.hitbox)->center; + if (hacks::shared::backtrack::isBacktrackEnabled()) + { + hitboxcenter = + hacks::shared::backtrack::headPositions + [entity->m_IDX][hacks::shared::backtrack::BestTick] + .hitboxes[cd.hitbox] + .center; + hitboxmin = hacks::shared::backtrack::headPositions + [entity->m_IDX][hacks::shared::backtrack::BestTick] + .hitboxes[cd.hitbox] + .min; + hitboxmax = hacks::shared::backtrack::headPositions + [entity->m_IDX][hacks::shared::backtrack::BestTick] + .hitboxes[cd.hitbox] + .max; + } // get positions - minx = hitbox->min.x; - miny = hitbox->min.y; - maxx = hitbox->max.x; - maxy = hitbox->max.y; - minz = hitbox->min.z; - maxz = hitbox->max.z; - centerx = hitbox->center.x; - centery = hitbox->center.y; - centerz = hitbox->center.z; + minx = hitboxmin.x; + miny = hitboxmin.y; + maxx = hitboxmax.x; + maxy = hitboxmax.y; + minz = hitboxmin.z; + maxz = hitboxmax.z; + centerx = hitboxcenter.x; + centery = hitboxcenter.y; + centerz = hitboxcenter.z; // Shrink positions std::vector positions; @@ -749,7 +778,7 @@ void Aim(CachedEntity *entity) positions.push_back({ maxx, maxy, centerz }); positions.push_back({ minx, miny, centerz }); positions.push_back({ maxx, maxy, centerz }); - positions.push_back(hitbox->center); + positions.push_back(hitboxcenter); for (auto pos : positions) if (IsVectorVisible(g_pLocalPlayer->v_Eye, pos)) { @@ -771,7 +800,15 @@ void Aim(CachedEntity *entity) if (silent && !slow_aim) g_pLocalPlayer->bUseSilentAngles = true; - + if (hacks::shared::backtrack::isBacktrackEnabled()) + { + auto i = hacks::shared::backtrack::headPositions + [hacks::shared::backtrack::iBestTarget] + [hacks::shared::backtrack::BestTick]; + current_user_cmd->tick_count = i.tickcount; + float &simtime = NET_FLOAT(RAW_ENT(entity), netvar.m_flSimulationTime); + simtime = i.simtime; + } // Finish function return; } @@ -888,45 +925,64 @@ const Vector &PredictEntity(CachedEntity *entity) if (cd.predict_tick == tickcount) return result; - // Players - if ((entity->m_Type() == ENTITY_PLAYER)) + if (!hacks::shared::backtrack::isBacktrackEnabled() || projectile_mode) { - // If using projectiles, predict a vector - if (projectileAimbotRequired) + + // Players + if ((entity->m_Type() == ENTITY_PLAYER)) { - // Use prediction engine if user settings allow - if (engine_projpred) - result = ProjectilePrediction_Engine( - entity, cd.hitbox, cur_proj_speed, cur_proj_grav, 0); + // If using projectiles, predict a vector + if (projectileAimbotRequired) + { + // Use prediction engine if user settings allow + if (engine_projpred) + result = ProjectilePrediction_Engine( + entity, cd.hitbox, cur_proj_speed, cur_proj_grav, 0); + else + result = ProjectilePrediction(entity, cd.hitbox, + cur_proj_speed, cur_proj_grav, + PlayerGravityMod(entity)); + } else - result = ProjectilePrediction(entity, cd.hitbox, cur_proj_speed, - cur_proj_grav, - PlayerGravityMod(entity)); + { + // If using extrapolation, then predict a vector + if (extrapolate) + result = SimpleLatencyPrediction(entity, cd.hitbox); + // else just grab strait from the hitbox + else + GetHitbox(entity, cd.hitbox, result); + } + // Buildings + } + else if (entity->m_Type() == ENTITY_BUILDING) + { + result = GetBuildingPosition(entity); + // Other } else { - // If using extrapolation, then predict a vector - if (extrapolate) - result = SimpleLatencyPrediction(entity, cd.hitbox); - // else just grab strait from the hitbox - else - GetHitbox(entity, cd.hitbox, result); + result = entity->m_vecOrigin(); } - // Buildings - } - else if (entity->m_Type() == ENTITY_BUILDING) - { - result = GetBuildingPosition(entity); - // Other + + cd.predict_tick = tickcount; + + cd.fov = GetFov(g_pLocalPlayer->v_OrigViewangles, g_pLocalPlayer->v_Eye, + result); } else { - result = entity->m_vecOrigin(); + // Players only + if ((entity->m_Type() == ENTITY_PLAYER)) + { + auto hb = hacks::shared::backtrack::headPositions + [entity->m_IDX] + [hacks::shared::backtrack::BestTick]; + cd.predict_tick = tickcount; + result = hb.hitboxes[cd.hitbox].center; + cd.fov = GetFov(g_pLocalPlayer->v_OrigViewangles, + g_pLocalPlayer->v_Eye, result); + } } - - cd.predict_tick = tickcount; - cd.fov = - GetFov(g_pLocalPlayer->v_OrigViewangles, g_pLocalPlayer->v_Eye, result); // Return the found vector return result; } @@ -1114,7 +1170,16 @@ bool VischeckPredictedEntity(CachedEntity *entity) // Update info cd.vcheck_tick = tickcount; - cd.visible = IsEntityVectorVisible(entity, PredictEntity(entity)); + if (!hacks::shared::backtrack::isBacktrackEnabled() || projectile_mode) + cd.visible = IsEntityVectorVisible(entity, PredictEntity(entity)); + else + cd.visible = IsVectorVisible( + g_pLocalPlayer->v_Eye, + hacks::shared::backtrack::headPositions + [entity->m_IDX][hacks::shared::backtrack::BestTick] + .hitboxes[cd.hitbox] + .center, + true); return cd.visible; } diff --git a/src/hacks/AutoBackstab.cpp b/src/hacks/AutoBackstab.cpp index c63b3b6a..7afed9ec 100644 --- a/src/hacks/AutoBackstab.cpp +++ b/src/hacks/AutoBackstab.cpp @@ -45,9 +45,9 @@ int ClosestDistanceHitbox(CachedEntity *target, { int closest = -1; float closest_dist = 0.0f, dist = 0.0f; - for (int i = spine_0; i < spine_3; i++) + for (int i = pelvis; i < lowerArm_R; i++) { - if (hacks::shared::backtrack::isBacktrackEnabled()) + if (hacks::shared::backtrack::isBacktrackEnabled) dist = g_pLocalPlayer->v_Eye.DistTo(btd.hitboxes.at(i).center); else dist = g_pLocalPlayer->v_Eye.DistTo( @@ -67,7 +67,7 @@ bool unifiedCanBackstab(Vector &vecAngle, Vector min, Vector max, // Get melee range float meleeRange = re::C_TFWeaponBaseMelee::GetSwingRange(RAW_ENT(LOCAL_W)); if (fabsf(vecAngle.y - - NET_VECTOR(RAW_ENT(besttarget), netvar.m_angEyeAngles).y) >= 50) + NET_VECTOR(RAW_ENT(besttarget), netvar.m_angEyeAngles).y) >= 60.0f) return false; if (!min.x && !max.x) return false; @@ -122,7 +122,7 @@ void CreateMove() if (!CanShoot()) return; CachedEntity *besttarget = nullptr; - if (!backtrack::isBacktrackEnabled()) + if (!backtrack::isBacktrackEnabled) { for (int i = 0; i < g_IEngine->GetMaxClients(); i++) { @@ -173,7 +173,7 @@ void CreateMove() { hacks::shared::anti_anti_aim::resolveEnt(besttarget->m_IDX); Vector angle = NET_VECTOR(RAW_ENT(LOCAL_E), netvar.m_angEyeAngles); - if (!backtrack::isBacktrackEnabled()) + if (!backtrack::isBacktrackEnabled) { for (angle.y = -180.0f; angle.y < 180.0f; angle.y += 10.0f) { diff --git a/src/hacks/Backtrack.cpp b/src/hacks/Backtrack.cpp index 3ad849fa..5d444127 100644 --- a/src/hacks/Backtrack.cpp +++ b/src/hacks/Backtrack.cpp @@ -22,10 +22,12 @@ namespace hacks::shared::backtrack { void EmptyBacktrackData(BacktrackData &i); std::pair getBestEntBestTick(); +bool shouldBacktrack(); + BacktrackData headPositions[32][66]{}; int highesttick[32]{}; int lastincomingsequencenumber = 0; -static bool shouldDrawBt; +bool isBacktrackEnabled = false; circular_buf sequences{ 2048 }; void UpdateIncomingSequences() @@ -48,6 +50,8 @@ void UpdateIncomingSequences() } void AddLatencyToNetchan(INetChannel *ch, float Latency) { + if (!isBacktrackEnabled) + return; if (Latency > 200.0f) Latency -= ch->GetLatency(MAX_FLOWS); for (auto &seq : sequences) @@ -69,21 +73,24 @@ void Init() int BestTick = 0; int iBestTarget = -1; +bool istickvalid[66]{}; +bool istickinvalid[66]{}; void Run() { - if (!enable) + if (!shouldBacktrack()) + { + isBacktrackEnabled = false; return; + } + isBacktrackEnabled = true; if (CE_BAD(LOCAL_E)) return; - if (!shouldBacktrack()) - { - shouldDrawBt = false; - return; - } - shouldDrawBt = true; - + for (auto &a : istickvalid) + a = false; + for (auto &a : istickinvalid) + a = false; CUserCmd *cmd = current_user_cmd; float bestFov = 99999; @@ -124,7 +131,7 @@ void Run() auto hdr = g_IModelInfo->GetStudiomodel(RAW_ENT(pEntity)->GetModel()); headPositions[i][cmd->command_number % getTicks()] = BacktrackData{ cmd->tick_count, hbdArray, viewangles, simtime, - ent_orig }; + ent_orig, cmd->command_number % getTicks() }; } if (iBestTarget != -1 && CanShoot()) { @@ -151,12 +158,10 @@ void Run() void Draw() { #if ENABLE_VISUALS - if (!enable) + if (!isBacktrackEnabled) return; if (!draw_bt) return; - if (!shouldDrawBt) - return; for (int i = 0; i < g_IEngine->GetMaxClients(); i++) { CachedEntity *ent = ENTITY(i); @@ -192,10 +197,16 @@ void Draw() #endif } +// Internal only, use isBacktrackEnabled var instead bool shouldBacktrack() { + if (!*enable) + return false; + CachedEntity *wep = g_pLocalPlayer->weapon(); + if (CE_BAD(wep)) + return false; int slot = - re::C_BaseCombatWeapon::GetSlot(RAW_ENT(g_pLocalPlayer->weapon())); + re::C_BaseCombatWeapon::GetSlot(RAW_ENT(wep)); switch ((int) slots) { case 0: @@ -229,11 +240,6 @@ bool shouldBacktrack() return false; } -bool isBacktrackEnabled() -{ - return *enable; -} - float getLatency() { return *latency; @@ -246,8 +252,19 @@ int getTicks() bool ValidTick(BacktrackData &i, CachedEntity *ent) { - return fabsf(NET_FLOAT(RAW_ENT(ent), netvar.m_flSimulationTime) * 1000.0f - - getLatency() - i.simtime * 1000.0f) < 200.0f; + if (istickvalid[i.index]) + return true; + if (istickinvalid[i.index]) + return false; + if (IsVectorVisible(g_pLocalPlayer->v_Eye, i.hitboxes[head].center, true)) + if (fabsf(NET_FLOAT(RAW_ENT(ent), netvar.m_flSimulationTime) * 1000.0f - + getLatency() - i.simtime * 1000.0f) < 200.0f) + { + istickvalid[i.index] = true; + return true; + } + istickinvalid[i.index] = true; + return false; } void EmptyBacktrackData(BacktrackData &i) diff --git a/src/hacks/Trigger.cpp b/src/hacks/Trigger.cpp index 628e2864..9ba10f8f 100644 --- a/src/hacks/Trigger.cpp +++ b/src/hacks/Trigger.cpp @@ -45,7 +45,9 @@ int last_hb_traced = 0; Vector forward; bool CanBacktrack() { - CachedEntity *tar = ENTITY(hacks::shared::backtrack::iBestTarget); + CachedEntity *tar = (hacks::shared::backtrack::iBestTarget != -1) + ? ENTITY(hacks::shared::backtrack::iBestTarget) + : nullptr; if (CE_BAD(tar)) return false; for (auto i : hacks::shared::backtrack::headPositions[tar->m_IDX]) @@ -113,7 +115,7 @@ void CreateMove() CachedEntity *ent = FindEntInSight(EffectiveTargetingRange()); // Check if can backtrack, shoot if we can - if (!CanBacktrack() || hacks::shared::backtrack::isBacktrackEnabled()) + if (!CanBacktrack() || hacks::shared::backtrack::isBacktrackEnabled) return; // Check if dormant or null to prevent crashes diff --git a/src/pathfinder.cpp b/src/pathfinder.cpp new file mode 100644 index 00000000..a544d620 --- /dev/null +++ b/src/pathfinder.cpp @@ -0,0 +1,139 @@ +#include "common.hpp" +#include "external/TF2_NavFile_Reader/CNavFile.h" +#include "external/PathFinder/src/PathFinder.h" +#include "external/PathFinder/src/AStar.h" + +namespace hacks::shared::pathfinder +{ +Vector loc; +//std::vector findPath(Vector loc, Vector dest); +//bool initiatenavfile(); + +//CatCommand navset("nav_set", "Debug nav set", +// [](const CCommand &args) { loc = g_pLocalPlayer->v_Origin; }); + +//CatCommand navfind("nav_find", "Debug nav find", [](const CCommand &args) { +// std::vector path = findPath(g_pLocalPlayer->v_Origin, loc); +// if (path.empty()) +// { +// logging::Info("Pathing: No path found"); +// } +// std::string output = "Pathing: Path found! Path: "; +// for (int i = 0; i < path.size(); i++) +// { +// output.append(format(path.at(i).x, ",", format(path.at(i).y))); +// } +// logging::Info(output.c_str()); +//}); + +//CatCommand navinit("nav_init", "Debug nav init", +// [](const CCommand &args) { initiatenavfile(); }); + +class navNode : public AStarNode +{ +// navNode() +// { +// } + +// ~navNode() +// { +// } +public: + Vector vecLoc; +}; + +std::vector nodes; +//settings::Bool enabled{ "pathing.enabled", 0 }; + +bool initiatenavfile() +{ + //if (!enabled) + // return false; + logging::Info("Pathing: Initiating path..."); + + // This will not work, please fix + std::string dir = + "/home/elite/.steam/steam/steamapps/common/Team Fortress 2/tf/maps/"; + std::string levelName = g_IEngine->GetLevelName(); + int dotpos = levelName.find('.'); + levelName = levelName.substr(0, dotpos); + levelName.append(".nav"); + dir.append(levelName); + + CNavFile navData(dir.c_str()); + if (!navData.m_isOK) + { + logging::Info("Pathing: Failed to parse nav file!"); + return false; + } + std::vector *areas = &navData.m_areas; + int nodeCount = areas->size(); + + nodes.clear(); + nodes.reserve(nodeCount); + + // register nodes + for (int i = 0; i < nodeCount; i++) + { + navNode *node{}; + // node->setPosition(areas->at(i).m_center.x, areas->at(i).m_center.y); + node->vecLoc = areas->at(i).m_center; + nodes.push_back(node); + } + + for (int i = 0; i < nodeCount; ++i) + { + std::vector *connections = &areas->at(i).m_connections; + int childCount = connections->size(); + navNode *currNode = nodes.at(i); + for (int j = 0; j < childCount; j++) + { + currNode->addChild(nodes.at(connections->at(j).id), 1.0f); + } + } + logging::Info("Path init successful"); + return true; +} + +int findClosestNavSquare(Vector vec) +{ + float bestDist = 999999.0f; + int bestSquare = -1; + for (int i = 0; i < nodes.size(); i++) + { + float dist = nodes.at(i)->vecLoc.DistTo(vec); + if (dist < bestDist) + { + bestDist = dist; + bestSquare = i; + } + } + return bestSquare; +} + +std::vector findPath(Vector loc, Vector dest) +{ + if (nodes.empty()) + return std::vector(0); + + int id_loc = findClosestNavSquare(loc); + int id_dest = findClosestNavSquare(dest); + + navNode &node_loc = *nodes.at(id_loc); + navNode &node_dest = *nodes.at(id_dest); + + PathFinder p; + std::vector pathNodes; + + p.setStart(node_loc); + p.setGoal(node_dest); + + p.findPath(pathNodes); + + std::vector path; + for (int i = 0; i < pathNodes.size(); i++) + { + path.push_back(pathNodes.at(i)->vecLoc); + } + return path; +}}