commit
28c190138a
@ -87,7 +87,7 @@ configure_file(include/version.h.in ${CMAKE_SOURCE_DIR}/include/version.h @ONLY)
|
||||
|
||||
#set_target_properties(cathook PROPERTIES COMPILE_FLAGS "-m32 -msse -msse2 -msse3 -fexceptions" LINK_FLAGS "-m32 -fno-gnu-unique -fexceptions -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS "-m32 -msse -msse2 -msse3 -fexceptions -fno-gnu-unique -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -ggdb -rdynamic")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
||||
|
||||
|
||||
|
@ -62,8 +62,10 @@
|
||||
<Select target="aimbot.priority-mode">
|
||||
<Option name="Smart" value="0"/>
|
||||
<Option name="FOV" value="1"/>
|
||||
<Option name="Distance" value="2"/>
|
||||
<Option name="Health" value="3"/>
|
||||
<Option name="Distance (Closest)" value="2"/>
|
||||
<Option name="Distance (Highest)" value="4"/>
|
||||
<Option name="Health (Lowest)" value="3"/>
|
||||
<Option name="Health (Highest)" value="5"/>
|
||||
</Select>
|
||||
</LabeledObject>
|
||||
<AutoVariable width="fill" target="aimbot.target.max-range" label="Max Range" min="0" max="4096"/>
|
||||
@ -78,7 +80,7 @@
|
||||
<AutoVariable width="fill" target="aimbot.slow" label="Slow Aimbot"/>
|
||||
</List>
|
||||
</Box>
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Target Options" x="380">
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Target Options" x="400">
|
||||
<List width="150">
|
||||
<AutoVariable width="fill" target="aimbot.target.sentry" label="Sentry guns"/>
|
||||
<AutoVariable width="fill" target="aimbot.target.stickybomb" label="Stickybombs"/>
|
||||
@ -96,7 +98,7 @@
|
||||
<AutoVariable width="fill" target="aimbot.target.other-buildings" label="Other buildings"/>
|
||||
</List>
|
||||
</Box>
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Backtrack" y="140" x="380">
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Backtrack" y="140" x="400">
|
||||
<List width="150">
|
||||
<AutoVariable width="fill" target="backtrack.enable" label="Enable Backtrack"/>
|
||||
<AutoVariable width="fill" target="backtrack.draw" label="Draw Backtrack"/>
|
||||
|
@ -64,12 +64,13 @@
|
||||
<List width="170">
|
||||
<AutoVariable width="fill" target="misc.pathing" label="Enable Pathing"/>
|
||||
<AutoVariable width="fill" target="misc.pathing.draw" label="Draw Path"/>
|
||||
<AutoVariable width="fill" target="navbot.enable" label="Enable NavBot"/>
|
||||
<AutoVariable width="fill" target="navbot.enable" label="Master Switch"/>
|
||||
<AutoVariable width="fill" target="navbot.sniper-mode" label="Enable Sniper Mode"/>
|
||||
<AutoVariable width="fill" target="navbot.scout-mode" label="Enable Scout Mode"/>
|
||||
<AutoVariable width="fill" target="navbot.spy-mode" label="Enable Spy Mode"/>
|
||||
<AutoVariable width="fill" target="navbot.heavy-mode" label="Enable Heavy Mode"/>
|
||||
<AutoVariable width="fill" target="navbot.engi-mode" label="Enable Engie Mode"/>
|
||||
<AutoVariable width="fill" target="navbot.primary-only" label="Best Weapon only"/>
|
||||
<AutoVariable width="fill" target="navbot.random-jumps" label="Randomly Jump"/>
|
||||
<AutoVariable width="fill" target="navbot.best-slot" label="Best Weapon only"/>
|
||||
<AutoVariable width="fill" target="navbot.jump-distance" label="Jump Distance"/>
|
||||
<AutoVariable width="fill" target="navbot.target-sentry" label="Try to target sentries"/>
|
||||
<AutoVariable width="fill" target="navbot.stay-near" label="Zone enemies (stay near)"/>
|
||||
|
2
external/libglez
vendored
2
external/libglez
vendored
@ -1 +1 @@
|
||||
Subproject commit 4e9c1ea11dfa80ace20ab0243c7e9dff499a4851
|
||||
Subproject commit 9457ea150e041689c6f38f5720b4d571cf64a943
|
@ -1,12 +1,26 @@
|
||||
//
|
||||
// Created by bencat07 on 17.08.18.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "config.h"
|
||||
namespace hacks::tf2::NavBot
|
||||
|
||||
namespace hacks::shared::NavBot
|
||||
{
|
||||
void Init();
|
||||
void initonce();
|
||||
} // namespace hacks::tf2::NavBot
|
||||
|
||||
// Main Functions
|
||||
void Init(bool from_LevelInit);
|
||||
|
||||
// Helper
|
||||
bool CanPath();
|
||||
bool HasLowHealth();
|
||||
bool HasLowAmmo();
|
||||
CachedEntity *nearestHealth();
|
||||
CachedEntity *nearestAmmo();
|
||||
CachedEntity *nearestEnemy();
|
||||
CachedEntity *nearestTeleporter();
|
||||
Vector GetClosestValidByDist(CachedEntity *ent, float mindist, float maxdist, bool near);
|
||||
void UpdateSlot();
|
||||
void Jump();
|
||||
|
||||
// Path
|
||||
bool NavToSniperSpot(int priority);
|
||||
bool NavToNearestEnemy();
|
||||
bool NavToBacktrackTick(int priority);
|
||||
|
||||
} // namespace hacks::shared::NavBot
|
||||
|
@ -1,367 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "micropather.h"
|
||||
#include "pwd.h"
|
||||
#include <thread>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#if ENABLE_VISUALS
|
||||
#include <glez/draw.hpp>
|
||||
#endif
|
||||
#include <memory>
|
||||
#include <CNavFile.h>
|
||||
|
||||
namespace nav
|
||||
{
|
||||
extern bool init;
|
||||
extern bool ReadyForCommands;
|
||||
extern int priority;
|
||||
extern std::vector<CNavArea> areas;
|
||||
std::vector<Vector> findPath(Vector loc, Vector dest, int &id_loc,
|
||||
int &id_dest);
|
||||
bool NavTo(Vector dest, bool navToLocalCenter = true, bool persistent = true,
|
||||
int instructionPriority = 5);
|
||||
void clearInstructions();
|
||||
int findClosestNavSquare(Vector vec);
|
||||
bool Prepare();
|
||||
void Draw();
|
||||
|
||||
int FindInVector(size_t id);
|
||||
int FindNearestValid(Vector vec);
|
||||
int FindNearestValidbyDist(Vector vec, float mindist, float maxdist,
|
||||
bool closest);
|
||||
|
||||
class inactivityTracker
|
||||
enum init_status : uint8_t
|
||||
{
|
||||
// Map for storing inactivity per connection
|
||||
std::unordered_map<std::pair<int, int>, std::pair<int, unsigned int>,
|
||||
boost::hash<std::pair<int, int>>>
|
||||
inactives;
|
||||
|
||||
public:
|
||||
std::unordered_map<int, bool> sentryAreas;
|
||||
|
||||
private:
|
||||
std::vector<Vector> sentries{};
|
||||
|
||||
public:
|
||||
bool vischeckConnection(std::pair<int, int> &connection)
|
||||
{
|
||||
int id0 = FindInVector(connection.first);
|
||||
int id1 = FindInVector(connection.second);
|
||||
if (id0 == -1 || id1 == -1)
|
||||
return false;
|
||||
Vector begin = areas.at(id0).m_center;
|
||||
Vector end = areas.at(id1).m_center;
|
||||
begin.z += 72;
|
||||
end.z += 72;
|
||||
bool result = IsVectorVisible(begin, end, false);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::pair<int, int> VectorsToId(std::pair<Vector, Vector> &connection)
|
||||
{
|
||||
CNavArea *currnode = nullptr;
|
||||
for (size_t i = 0; i < areas.size(); i++)
|
||||
{
|
||||
if (areas.at(i).m_center == connection.first)
|
||||
{
|
||||
currnode = &areas.at(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!currnode)
|
||||
return { -1, -1 };
|
||||
|
||||
CNavArea *nextnode = nullptr;
|
||||
for (size_t i = 0; i < areas.size(); i++)
|
||||
{
|
||||
if (areas.at(i).m_center == connection.second)
|
||||
{
|
||||
nextnode = &areas.at(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!nextnode)
|
||||
return { -1, -1 };
|
||||
|
||||
for (auto i : currnode->m_connections)
|
||||
{
|
||||
if (i.area->m_id == nextnode->m_id)
|
||||
{
|
||||
return { currnode->m_id, nextnode->m_id };
|
||||
}
|
||||
}
|
||||
return { -1, -1 };
|
||||
}
|
||||
|
||||
int VectorToID(Vector vec)
|
||||
{
|
||||
CNavArea *currnode = nullptr;
|
||||
for (size_t i = 0; i < areas.size(); i++)
|
||||
{
|
||||
if (areas.at(i).m_center == vec)
|
||||
{
|
||||
currnode = &areas.at(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!currnode)
|
||||
return -1;
|
||||
return currnode->m_id;
|
||||
}
|
||||
|
||||
public:
|
||||
void reset()
|
||||
{
|
||||
for (auto i : inactives)
|
||||
{
|
||||
// What is this tf
|
||||
i.second.second = 0;
|
||||
}
|
||||
}
|
||||
bool ShouldCancelPath(std::vector<Vector> crumbs)
|
||||
{
|
||||
for (auto crumb : crumbs)
|
||||
{
|
||||
int id = VectorToID(crumb);
|
||||
if (id == -1)
|
||||
continue;
|
||||
if (sentryAreas[id])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void AddSentries()
|
||||
{
|
||||
for (int i = 0; i < HIGHEST_ENTITY; i++)
|
||||
{
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
if (CE_BAD(ent) ||
|
||||
ent->m_iClassID() != CL_CLASS(CObjectSentrygun) ||
|
||||
ent->m_iTeam() == LOCAL_E->m_iTeam())
|
||||
continue;
|
||||
Vector sentryloc = GetBuildingPosition(ent);
|
||||
sentries.push_back(sentryloc);
|
||||
for (auto i : areas)
|
||||
{
|
||||
Vector area = i.m_center;
|
||||
area.z += 83.0f;
|
||||
if (area.DistTo(sentryloc) > 1100.0f)
|
||||
continue;
|
||||
if (!IsVectorVisible(area, sentryloc, true))
|
||||
continue;
|
||||
sentryAreas[i.m_id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
void ClearSentries()
|
||||
{
|
||||
sentries.clear();
|
||||
sentryAreas.clear();
|
||||
}
|
||||
bool IsIgnored(std::pair<int, int> connection)
|
||||
{
|
||||
if (!IsPlayerDisguised(LOCAL_E))
|
||||
{
|
||||
if (sentryAreas[connection.first] || sentryAreas[connection.second])
|
||||
{
|
||||
logging::Info(
|
||||
"Ignored a connection due to sentry gun coverage");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (inactives.find(connection) == inactives.end())
|
||||
return false;
|
||||
auto &pair = inactives.at(connection);
|
||||
if (pair.second >= 5000)
|
||||
{
|
||||
pair.first = 1;
|
||||
return true;
|
||||
}
|
||||
if (pair.first == 2 && !vischeckConnection(connection))
|
||||
{
|
||||
logging::Info(
|
||||
"Ignored a connection due to type 2 connection type.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AddTime(std::pair<int, int> connection, Timer &timer,
|
||||
bool &resetPather)
|
||||
{
|
||||
if (inactives.find(connection) == inactives.end())
|
||||
{
|
||||
inactives[connection] = { 0, 0 };
|
||||
}
|
||||
auto &pair = inactives.at(connection);
|
||||
|
||||
unsigned int newTime =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now() - timer.last)
|
||||
.count();
|
||||
if (pair.first == 2 && !vischeckConnection(connection))
|
||||
newTime = (newTime > 2500 ? 2500 : newTime);
|
||||
pair.second = pair.second + newTime;
|
||||
if (pair.second >= 5000)
|
||||
resetPather = true;
|
||||
}
|
||||
void AddTime(std::pair<Vector, Vector> connection, Timer &timer,
|
||||
bool &resetPather)
|
||||
{
|
||||
auto pair = VectorsToId(connection);
|
||||
if (pair.first == -1 || pair.second == -1)
|
||||
return;
|
||||
AddTime(pair, timer, resetPather);
|
||||
}
|
||||
bool CheckType2(std::pair<int, int> connection)
|
||||
{
|
||||
// Fix calls vischeckConnection too often
|
||||
if (inactives.find(connection) == inactives.end())
|
||||
{
|
||||
inactives[connection] = { 0, 0 };
|
||||
}
|
||||
auto pair = inactives.at(connection);
|
||||
switch (pair.first)
|
||||
{
|
||||
case 0:
|
||||
if (!vischeckConnection(connection))
|
||||
{
|
||||
inactives[connection].first = 2;
|
||||
return true;
|
||||
}
|
||||
case 1:
|
||||
case 2:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool CheckType2(std::pair<Vector, Vector> connection)
|
||||
{
|
||||
auto pair = VectorsToId(connection);
|
||||
if (pair.first == -1 || pair.second == -1)
|
||||
return false;
|
||||
return CheckType2(pair);
|
||||
}
|
||||
}; // namespace nav
|
||||
|
||||
struct MAP : public micropather::Graph
|
||||
{
|
||||
std::unique_ptr<micropather::MicroPather> pather;
|
||||
std::unordered_map<std::pair<int, int>, int,
|
||||
boost::hash<std::pair<int, int>>>
|
||||
vischeck_cd;
|
||||
Timer vischeck_t{};
|
||||
// Maps already utilize dynamic allocation and we don't need a custom
|
||||
// constructor
|
||||
inactivityTracker inactiveTracker;
|
||||
Vector GetClosestCornerToArea(CNavArea *CornerOf, CNavArea *Target)
|
||||
{
|
||||
std::array<Vector, 4> corners;
|
||||
corners.at(0) = CornerOf->m_nwCorner; // NW
|
||||
corners.at(1) = CornerOf->m_seCorner; // SE
|
||||
corners.at(2) = Vector{ CornerOf->m_seCorner.x, CornerOf->m_nwCorner.y,
|
||||
CornerOf->m_nwCorner.z }; // NE
|
||||
corners.at(3) = Vector{ CornerOf->m_nwCorner.x, CornerOf->m_seCorner.y,
|
||||
CornerOf->m_seCorner.z }; // SW
|
||||
|
||||
Vector bestVec{};
|
||||
float bestDist = FLT_MAX;
|
||||
|
||||
for (size_t i = 0; i < corners.size(); i++)
|
||||
{
|
||||
float dist = corners.at(i).DistTo(Target->m_center);
|
||||
if (dist < bestDist)
|
||||
{
|
||||
bestVec = corners.at(i);
|
||||
bestDist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
Vector bestVec2{};
|
||||
float bestDist2 = FLT_MAX;
|
||||
|
||||
for (size_t i = 0; i < corners.size(); i++)
|
||||
{
|
||||
if (corners.at(i) == bestVec2)
|
||||
continue;
|
||||
float dist = corners.at(i).DistTo(Target->m_center);
|
||||
if (dist < bestDist2)
|
||||
{
|
||||
bestVec2 = corners.at(i);
|
||||
bestDist2 = dist;
|
||||
}
|
||||
}
|
||||
return (bestVec + bestVec2) / 2;
|
||||
}
|
||||
|
||||
float GetZBetweenAreas(CNavArea *start, CNavArea *end)
|
||||
{
|
||||
float z1 = GetClosestCornerToArea(start, end).z;
|
||||
float z2 = GetClosestCornerToArea(end, start).z;
|
||||
|
||||
return z2 - z1;
|
||||
}
|
||||
// Function required by MicroPather for getting an estimated cost
|
||||
float LeastCostEstimate(void *stateStart, void *stateEnd)
|
||||
{
|
||||
CNavArea *start = static_cast<CNavArea *>(stateStart);
|
||||
CNavArea *end = static_cast<CNavArea *>(stateEnd);
|
||||
float dist = start->m_center.DistTo(end->m_center);
|
||||
return dist;
|
||||
}
|
||||
// Function required by MicroPather to retrieve neighbours and their
|
||||
// associated costs.
|
||||
void AdjacentCost(void *state, MP_VECTOR<micropather::StateCost> *adjacent)
|
||||
{
|
||||
CNavArea *area = static_cast<CNavArea *>(state);
|
||||
auto &neighbours = area->m_connections;
|
||||
for (auto i : neighbours)
|
||||
{
|
||||
if (GetZBetweenAreas(area, i.area) > 42)
|
||||
continue;
|
||||
std::pair<int, int> connection =
|
||||
std::pair{ area->m_id, i.area->m_id };
|
||||
if (inactiveTracker.IsIgnored(connection))
|
||||
continue;
|
||||
int id = FindInVector(i.area->m_id);
|
||||
if (id == -1)
|
||||
return;
|
||||
micropather::StateCost cost;
|
||||
cost.state = static_cast<void *>(&areas.at(id));
|
||||
cost.cost = area->m_center.DistTo(i.area->m_center);
|
||||
if (vischeck_t.test_and_set(2000))
|
||||
vischeck_cd.clear();
|
||||
if (vischeck_cd[connection] == 0)
|
||||
{
|
||||
if (!inactiveTracker.vischeckConnection(connection))
|
||||
{
|
||||
cost.cost *= 99;
|
||||
vischeck_cd[connection] = 2;
|
||||
}
|
||||
else
|
||||
vischeck_cd[connection] = 1;
|
||||
}
|
||||
else if (vischeck_cd[connection] == 2)
|
||||
cost.cost *= 99;
|
||||
adjacent->push_back(cost);
|
||||
}
|
||||
}
|
||||
void PrintStateInfo(void *state)
|
||||
{
|
||||
CNavArea *area = static_cast<CNavArea *>(state);
|
||||
logging::Info(format(area->m_center.x, " ", area->m_center.y, " ",
|
||||
area->m_center.z)
|
||||
.c_str());
|
||||
}
|
||||
MAP(size_t size)
|
||||
{
|
||||
pather =
|
||||
std::make_unique<micropather::MicroPather>(this, size, 6, true);
|
||||
}
|
||||
|
||||
~MAP()
|
||||
{
|
||||
}
|
||||
off = 0,
|
||||
unavailable,
|
||||
initing,
|
||||
on
|
||||
};
|
||||
|
||||
// Call prepare first and check its return value
|
||||
extern std::unique_ptr<CNavFile> navfile;
|
||||
|
||||
// Current path priority
|
||||
extern int curr_priority;
|
||||
// Check if ready to recieve another NavTo (to avoid overwriting of
|
||||
// instructions)
|
||||
extern bool ReadyForCommands;
|
||||
// Ignore. For level init only
|
||||
extern std::atomic<init_status> status;
|
||||
|
||||
// Nav to vector
|
||||
bool navTo(Vector destination, int priority = 5, bool should_repath = true,
|
||||
bool nav_to_local = true, bool is_repath = false);
|
||||
// Check and init navparser
|
||||
bool prepare();
|
||||
// Clear current path
|
||||
void clearInstructions();
|
||||
// Check if area is safe from stickies and sentries
|
||||
bool isSafe(CNavArea *area);
|
||||
|
||||
} // namespace nav
|
||||
|
@ -18,20 +18,27 @@ class EffectChams : public IScreenSpaceEffect
|
||||
{
|
||||
public:
|
||||
virtual void Init();
|
||||
inline virtual void Shutdown(){};
|
||||
inline virtual void Shutdown()
|
||||
{
|
||||
mat_unlit.Shutdown();
|
||||
mat_unlit_z.Shutdown();
|
||||
mat_lit.Shutdown();
|
||||
mat_lit_z.Shutdown();
|
||||
init = false;
|
||||
}
|
||||
|
||||
inline virtual void SetParameters(KeyValues *params){};
|
||||
inline virtual void SetParameters(KeyValues *params){}
|
||||
|
||||
virtual void Render(int x, int y, int w, int h);
|
||||
|
||||
inline virtual void Enable(bool bEnable)
|
||||
{
|
||||
enabled = bEnable;
|
||||
};
|
||||
}
|
||||
inline virtual bool IsEnabled()
|
||||
{
|
||||
return enabled;
|
||||
};
|
||||
}
|
||||
|
||||
void SetEntityColor(CachedEntity *ent, rgba_t color);
|
||||
rgba_t ChamsColor(IClientEntity *entity);
|
||||
|
@ -17,20 +17,28 @@ class EffectGlow : public IScreenSpaceEffect
|
||||
{
|
||||
public:
|
||||
virtual void Init();
|
||||
inline virtual void Shutdown(){};
|
||||
inline virtual void Shutdown(){
|
||||
mat_unlit.Shutdown();
|
||||
mat_unlit_z.Shutdown();
|
||||
mat_blit.Shutdown();
|
||||
mat_unlit.Shutdown();
|
||||
mat_unlit_z.Shutdown();
|
||||
mat_blur_x.Shutdown();
|
||||
mat_blur_y.Shutdown();
|
||||
}
|
||||
|
||||
inline virtual void SetParameters(KeyValues *params){};
|
||||
inline virtual void SetParameters(KeyValues *params){}
|
||||
|
||||
virtual void Render(int x, int y, int w, int h);
|
||||
|
||||
inline virtual void Enable(bool bEnable)
|
||||
{
|
||||
enabled = bEnable;
|
||||
};
|
||||
}
|
||||
inline virtual bool IsEnabled()
|
||||
{
|
||||
return enabled;
|
||||
};
|
||||
}
|
||||
|
||||
void StartStenciling();
|
||||
void EndStenciling();
|
||||
|
@ -164,6 +164,7 @@ void crit_err_hdlr(int sig_num, siginfo_t *info, void *ucontext)
|
||||
fclose(backtraceFile);
|
||||
free(messages);
|
||||
|
||||
std::abort();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -183,8 +184,6 @@ void hack::Initialize()
|
||||
{
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
installSignal(SIGSEGV);
|
||||
installSignal(SIGABRT);
|
||||
installSignal(SIGINT);
|
||||
time_injected = time(nullptr);
|
||||
/*passwd *pwd = getpwuid(getuid());
|
||||
char *logname = strfmt("/tmp/cathook-game-stdout-%s-%u.log", pwd->pw_name,
|
||||
|
@ -118,7 +118,7 @@ void CreateMove()
|
||||
current_user_cmd->buttons |= IN_ATTACK2;
|
||||
|
||||
if (g_pLocalPlayer->weapon()->m_iClassID() == CL_CLASS(CTFMinigun))
|
||||
if (auto_spin_up && !zoomTime.check(3000))
|
||||
if (auto_spin_up && CE_INT(g_pLocalPlayer->weapon(), netvar.m_iClip1) != 0 && !zoomTime.check(1000))
|
||||
current_user_cmd->buttons |= IN_ATTACK2;
|
||||
|
||||
// We do this as we need to pass whether the aimkey allows aiming to both
|
||||
@ -401,9 +401,16 @@ CachedEntity *RetrieveBestTarget(bool aimkey_state)
|
||||
case 1: // Fov Priority
|
||||
scr = 360.0f - calculated_data_array[ent->m_IDX].fov;
|
||||
break;
|
||||
case 3: // Health Priority
|
||||
case 3: // Health Priority (Lowest)
|
||||
scr = 450.0f - ent->m_iHealth();
|
||||
break;
|
||||
case 4: // Distance Priority (Furthest Away)
|
||||
scr = calculated_data_array[i].aim_position.DistTo(
|
||||
g_pLocalPlayer->v_Eye);
|
||||
break;
|
||||
case 6: // Health Priority (Highest)
|
||||
scr = ent->m_iHealth() * 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1059,9 +1066,10 @@ int BestHitbox(CachedEntity *target)
|
||||
// only if they have less than 150 health will it try to
|
||||
// bodyshot
|
||||
if (CanHeadshot() &&
|
||||
(cdmg >= target->m_iHealth() ||
|
||||
(std::floor(cdmg) >= target->m_iHealth() ||
|
||||
IsPlayerCritBoosted(g_pLocalPlayer->entity) ||
|
||||
!g_pLocalPlayer->bZoomed || target->m_iHealth() <= bdmg) &&
|
||||
!g_pLocalPlayer->bZoomed ||
|
||||
target->m_iHealth() <= std::floor(bdmg)) &&
|
||||
target->m_iHealth() <= 150)
|
||||
{
|
||||
// We dont need to hit the head as a bodyshot will kill
|
||||
|
@ -374,6 +374,8 @@ bool ShouldChargePlayer(int idx)
|
||||
const float damage_accum_duration =
|
||||
g_GlobalVars->curtime - data[idx].accum_damage_start;
|
||||
const int health = target->m_iHealth();
|
||||
if (health > g_pPlayerResource->GetMaxHealth(target))
|
||||
return false;
|
||||
if (!data[idx].accum_damage_start)
|
||||
return false;
|
||||
if (health > 30 && data[idx].accum_damage < 45)
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <glez/draw.hpp>
|
||||
#endif
|
||||
#include <settings/Bool.hpp>
|
||||
#include "PlayerTools.hpp"
|
||||
#include <hacks/Backtrack.hpp>
|
||||
|
||||
static settings::Bool enable{ "backtrack.enable", "false" };
|
||||
@ -124,6 +125,8 @@ void Run()
|
||||
continue;
|
||||
if (!pEntity->hitboxes.GetHitbox(0))
|
||||
continue;
|
||||
if (HasCondition<TFCond_HalloweenGhostMode>(pEntity))
|
||||
continue;
|
||||
float _viewangles = CE_VECTOR(pEntity, netvar.m_angEyeAngles).y;
|
||||
float viewangles =
|
||||
(_viewangles > 180) ? _viewangles - 360 : _viewangles;
|
||||
|
@ -216,6 +216,8 @@ void reportall()
|
||||
// server
|
||||
if (!ent)
|
||||
continue;
|
||||
|
||||
// Pointer comparison is fine
|
||||
if (ent == LOCAL_E)
|
||||
continue;
|
||||
player_info_s info;
|
||||
@ -255,7 +257,7 @@ void smart_crouch()
|
||||
if (CE_BAD(ent) || ent->m_Type() != ENTITY_PLAYER ||
|
||||
ent->m_iTeam() == LOCAL_E->m_iTeam() ||
|
||||
!(ent->hitboxes.GetHitbox(0)) || !(ent->m_bAlivePlayer()) ||
|
||||
player_tools::shouldTargetSteamId(ent->player_info.friendsID) !=
|
||||
player_tools::shouldTarget(ent) !=
|
||||
player_tools::IgnoreReason::DO_NOT_IGNORE ||
|
||||
should_ignore_player(ent))
|
||||
continue;
|
||||
|
@ -30,8 +30,9 @@ static settings::Bool corneractivate{ "follow-bot.corners", "true" };
|
||||
static settings::Int steam_var{ "follow-bot.steamid", "0" };
|
||||
namespace hacks::shared::followbot
|
||||
{
|
||||
|
||||
static Timer navBotInterval{};
|
||||
unsigned steamid = 0x0;
|
||||
|
||||
CatCommand
|
||||
follow_steam("fb_steam", "Follow Steam Id", [](const CCommand &args) {
|
||||
if (args.ArgC() < 1)
|
||||
@ -171,7 +172,7 @@ void addCrumbPair(CachedEntity *player1, CachedEntity *player2,
|
||||
* tf_engineer = 9
|
||||
*/
|
||||
|
||||
static int priority_list[10][10] = {
|
||||
constexpr int priority_list[10][10] = {
|
||||
/*0 1 2 3 4 5 6 7 8 9 */
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // No class
|
||||
{ 0, 8, 2, 7, 6, 2, 5, 1, 0, 0 }, // Scout
|
||||
@ -230,12 +231,12 @@ static HookedFunction
|
||||
}
|
||||
if (CE_GOOD(ENTITY(follow_target)) && navtime.test_and_set(2000))
|
||||
{
|
||||
if (nav::NavTo(ENTITY(follow_target)->m_vecOrigin()))
|
||||
if (nav::navTo(ENTITY(follow_target)->m_vecOrigin(), 5, true, false))
|
||||
{
|
||||
navtimeout.update();
|
||||
}
|
||||
}
|
||||
if (navtimeout.check(15000) || nav::priority == 0)
|
||||
if (navtimeout.check(15000) || nav::curr_priority == 0)
|
||||
{
|
||||
isnaving = false;
|
||||
nav::clearInstructions();
|
||||
@ -257,7 +258,12 @@ static HookedFunction
|
||||
|
||||
if (!follow_target)
|
||||
breadcrumbs.clear(); // no target == no path
|
||||
|
||||
bool isNavBotCM = navBotInterval.test_and_set(3000);
|
||||
|
||||
// Target Selection
|
||||
{
|
||||
|
||||
if (steamid &&
|
||||
((follow_target &&
|
||||
ENTITY(follow_target)->player_info.friendsID != steamid) ||
|
||||
@ -312,9 +318,9 @@ static HookedFunction
|
||||
if (VisCheckEntFromEnt(LOCAL_E, entity))
|
||||
found = true;
|
||||
}
|
||||
if (!found && nav::Prepare())
|
||||
if (isNavBotCM && !found)
|
||||
{
|
||||
if (!nav::NavTo(entity->m_vecOrigin()))
|
||||
if (!nav::navTo(entity->m_vecOrigin()))
|
||||
continue;
|
||||
navtimeout.update();
|
||||
found = true;
|
||||
@ -325,9 +331,10 @@ static HookedFunction
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// If we dont have a follow target from that, we look again for someone
|
||||
// else who is suitable
|
||||
{
|
||||
if ((!follow_target || change ||
|
||||
(ClassPriority(ENTITY(follow_target)) < 6 &&
|
||||
ENTITY(follow_target)->player_info.friendsID != steamid)) &&
|
||||
@ -416,9 +423,9 @@ static HookedFunction
|
||||
if (VisCheckEntFromEnt(LOCAL_E, entity))
|
||||
found = true;
|
||||
}
|
||||
if (!found && nav::Prepare())
|
||||
if (isNavBotCM && !found)
|
||||
{
|
||||
if (!nav::NavTo(entity->m_vecOrigin()))
|
||||
if (!nav::navTo(entity->m_vecOrigin()))
|
||||
continue;
|
||||
navtimeout.update();
|
||||
found = true;
|
||||
@ -430,6 +437,7 @@ static HookedFunction
|
||||
afkTicks[i].update(); // set afk time to 0
|
||||
}
|
||||
}
|
||||
}
|
||||
lastent++;
|
||||
if (lastent > g_IEngine->GetMaxClients())
|
||||
lastent = 0;
|
||||
|
@ -101,7 +101,7 @@ class KillSayEventListener : public IGameEventListener2
|
||||
std::string message = hacks::shared::killsay::ComposeKillSay(event);
|
||||
if (!message.empty())
|
||||
{
|
||||
int vid = event->GetInt("userid");
|
||||
int vid = event->GetInt("userid");
|
||||
killsay_storage[vid].delay = *delay;
|
||||
killsay_storage[vid].timer.update();
|
||||
killsay_storage[vid].message = message;
|
||||
@ -109,20 +109,21 @@ class KillSayEventListener : public IGameEventListener2
|
||||
}
|
||||
};
|
||||
|
||||
static HookedFunction ProcessKillsay(HookedFunctions_types::HF_Paint, "KillSay_send", 1, []() {
|
||||
if (killsay_storage.empty())
|
||||
return;
|
||||
for (auto &i : killsay_storage)
|
||||
{
|
||||
if (i.second.message.empty())
|
||||
continue;
|
||||
if (i.second.timer.test_and_set(i.second.delay))
|
||||
static HookedFunction
|
||||
ProcessKillsay(HookedFunctions_types::HF_Paint, "KillSay_send", 1, []() {
|
||||
if (killsay_storage.empty())
|
||||
return;
|
||||
for (auto &i : killsay_storage)
|
||||
{
|
||||
chat_stack::Say(i.second.message, false);
|
||||
i.second = {};
|
||||
if (i.second.message.empty())
|
||||
continue;
|
||||
if (i.second.timer.test_and_set(i.second.delay))
|
||||
{
|
||||
chat_stack::Say(i.second.message, false);
|
||||
i.second = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
static KillSayEventListener listener{};
|
||||
|
||||
|
1145
src/hacks/NavBot.cpp
1145
src/hacks/NavBot.cpp
File diff suppressed because it is too large
Load Diff
@ -255,8 +255,10 @@ DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time,
|
||||
#if !ENABLE_VISUALS
|
||||
if (no_shake && CE_GOOD(LOCAL_E) && LOCAL_E->m_bAlivePlayer())
|
||||
{
|
||||
NET_VECTOR(RAW_ENT(LOCAL_E), netvar.vecPunchAngle) = {0.0f, 0.0f, 0.0f};
|
||||
NET_VECTOR(RAW_ENT(LOCAL_E), netvar.vecPunchAngleVel) = {0.0f, 0.0f, 0.0f};
|
||||
NET_VECTOR(RAW_ENT(LOCAL_E), netvar.vecPunchAngle) = { 0.0f, 0.0f,
|
||||
0.0f };
|
||||
NET_VECTOR(RAW_ENT(LOCAL_E), netvar.vecPunchAngleVel) = { 0.0f, 0.0f,
|
||||
0.0f };
|
||||
}
|
||||
#endif
|
||||
// PROF_END("Entity Cache updating");
|
||||
@ -273,9 +275,11 @@ DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time,
|
||||
if (firstcm)
|
||||
{
|
||||
DelayTimer.update();
|
||||
hacks::tf2::NavBot::Init();
|
||||
hacks::tf2::NavBot::initonce();
|
||||
// hacks::tf2::NavBot::Init();
|
||||
// hacks::tf2::NavBot::initonce();
|
||||
nav::status = nav::off;
|
||||
IRC::auth();
|
||||
hacks::shared::NavBot::Init(true);
|
||||
firstcm = false;
|
||||
}
|
||||
g_Settings.bInvalid = false;
|
||||
|
@ -56,8 +56,8 @@ DEFINE_HOOKED_METHOD(LevelInit, void, void *this_, const char *name)
|
||||
hacks::shared::backtrack::lastincomingsequencenumber = 0;
|
||||
hacks::shared::backtrack::sequences.clear();
|
||||
#endif
|
||||
firstcm = true;
|
||||
nav::init = false;
|
||||
firstcm = true;
|
||||
// nav::init = false;
|
||||
#if !LAGBOT_MODE
|
||||
playerlist::Save();
|
||||
#endif
|
||||
|
@ -105,8 +105,10 @@ DEFINE_HOOKED_METHOD(FrameStageNotify, void, void *this_,
|
||||
RemoveCondition<TFCond_Zoomed>(LOCAL_E);
|
||||
if (no_shake && CE_GOOD(LOCAL_E) && LOCAL_E->m_bAlivePlayer())
|
||||
{
|
||||
NET_VECTOR(RAW_ENT(LOCAL_E), netvar.vecPunchAngle) = {0.0f, 0.0f, 0.0f};
|
||||
NET_VECTOR(RAW_ENT(LOCAL_E), netvar.vecPunchAngleVel) = {0.0f, 0.0f, 0.0f};
|
||||
NET_VECTOR(RAW_ENT(LOCAL_E),
|
||||
netvar.vecPunchAngle) = { 0.0f, 0.0f, 0.0f };
|
||||
NET_VECTOR(RAW_ENT(LOCAL_E),
|
||||
netvar.vecPunchAngleVel) = { 0.0f, 0.0f, 0.0f };
|
||||
}
|
||||
}
|
||||
hacks::tf::thirdperson::frameStageNotify();
|
||||
|
@ -13,6 +13,8 @@ DEFINE_HOOKED_METHOD(SDL_PollEvent, int, SDL_Event *event)
|
||||
{
|
||||
auto ret = original::SDL_PollEvent(event);
|
||||
#if ENABLE_GUI
|
||||
if (!isHackActive())
|
||||
return ret;
|
||||
static Timer waitfirst{};
|
||||
if (gui::handleSdlEvent(event))
|
||||
return 0;
|
||||
|
@ -78,11 +78,12 @@ void authreq(std::string &msg)
|
||||
// Get playerinfo and check if player on server
|
||||
if (!g_IEngine->GetPlayerInfo(i, &pinfo))
|
||||
continue;
|
||||
auto tarsteamid = pinfo.friendsID;
|
||||
auto tarsteamid = pinfo.friendsID;
|
||||
std::string total_hash = std::to_string(tarsteamid) + pinfo.name;
|
||||
MD5Value_t result;
|
||||
// Hash steamid
|
||||
MD5_ProcessSingleBuffer(total_hash.c_str(), strlen(total_hash.c_str()), result);
|
||||
MD5_ProcessSingleBuffer(total_hash.c_str(), strlen(total_hash.c_str()),
|
||||
result);
|
||||
// Get bits of hash and store in string
|
||||
std::string tarhash;
|
||||
for (auto i : result.bits)
|
||||
|
@ -1,113 +1,383 @@
|
||||
#include "common.hpp"
|
||||
#include "navparser.hpp"
|
||||
#include <thread>
|
||||
#include "micropather.h"
|
||||
#include <pwd.h>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#if ENABLE_VISUALS
|
||||
#include <glez/draw.hpp>
|
||||
#endif
|
||||
|
||||
namespace nav
|
||||
{
|
||||
static CNavFile navfile(nullptr);
|
||||
// Vector containing areas on map
|
||||
std::vector<CNavArea> areas;
|
||||
bool init = false;
|
||||
static bool pathfinding = true;
|
||||
bool ReadyForCommands = false;
|
||||
|
||||
static settings::Bool enabled{ "misc.pathing", "true" };
|
||||
// Whether or not to run vischecks at pathtime
|
||||
static settings::Bool vischecks{ "misc.pathing.pathtime-vischecks", "false" };
|
||||
static settings::Bool draw{ "misc.pathing.draw", "false" };
|
||||
static std::atomic<bool> threadingFinished;
|
||||
|
||||
static std::unique_ptr<MAP> TF2MAP;
|
||||
static std::vector<Vector> crumbs;
|
||||
|
||||
// Function to get place in Vector by connection ID
|
||||
// Todo: find an alternative for this, maybe a map for storing ptrs to the
|
||||
// std::vector?
|
||||
int FindInVector(size_t id)
|
||||
enum ignore_status : uint8_t
|
||||
{
|
||||
for (int i = 0; i < areas.size(); i++)
|
||||
// Status is unknown
|
||||
unknown = 0,
|
||||
// Something like Z check failed, these are unchanging
|
||||
const_ignored,
|
||||
// LOS between areas is given
|
||||
vischeck_success,
|
||||
// No LOS between areas
|
||||
vischeck_failed,
|
||||
// Failed to actually walk thru connection
|
||||
explicit_ignored,
|
||||
// Danger like sentry gun or sticky
|
||||
danger_found
|
||||
};
|
||||
|
||||
void ResetPather();
|
||||
void repath();
|
||||
|
||||
struct ignoredata
|
||||
{
|
||||
ignore_status status{ unknown };
|
||||
float stucktime{ 0.0f };
|
||||
Timer ignoreTimeout{};
|
||||
};
|
||||
|
||||
CNavArea *getNavArea(Vector &vec)
|
||||
{
|
||||
for (auto &i : navfile->m_areas)
|
||||
{
|
||||
if (areas.at(i).m_id == id)
|
||||
return i;
|
||||
if (vec == i.m_center)
|
||||
return &i;
|
||||
}
|
||||
return -1;
|
||||
return nullptr;
|
||||
}
|
||||
static int bestarea = -1;
|
||||
Timer reselect{};
|
||||
int FindNearestValidbyDist(Vector vec, float mindist, float maxdist,
|
||||
bool closest)
|
||||
|
||||
Vector GetClosestCornerToArea(CNavArea *CornerOf, CNavArea *Target)
|
||||
{
|
||||
if (reselect.test_and_set(500))
|
||||
std::array<Vector, 4> corners;
|
||||
corners.at(0) = CornerOf->m_nwCorner; // NW
|
||||
corners.at(1) = CornerOf->m_seCorner; // SE
|
||||
corners.at(2) = Vector{ CornerOf->m_seCorner.x, CornerOf->m_nwCorner.y,
|
||||
CornerOf->m_nwCorner.z }; // NE
|
||||
corners.at(3) = Vector{ CornerOf->m_nwCorner.x, CornerOf->m_seCorner.y,
|
||||
CornerOf->m_seCorner.z }; // SW
|
||||
|
||||
Vector bestVec{};
|
||||
float bestDist = FLT_MAX;
|
||||
|
||||
for (size_t i = 0; i < corners.size(); i++)
|
||||
{
|
||||
float bestscr = FLT_MAX;
|
||||
bestarea = -1;
|
||||
for (int ar = 0; ar < areas.size(); ar++)
|
||||
float dist = corners.at(i).DistTo(Target->m_center);
|
||||
if (dist < bestDist)
|
||||
{
|
||||
Vector area = areas[ar].m_center;
|
||||
area.z += 72.0f;
|
||||
float scr = area.DistTo(vec);
|
||||
if (scr > maxdist || scr < mindist)
|
||||
continue;
|
||||
if (closest)
|
||||
{
|
||||
if (scr > bestscr)
|
||||
continue;
|
||||
}
|
||||
else if (scr < bestscr)
|
||||
continue;
|
||||
if (IsVectorVisible(vec, area, false))
|
||||
{
|
||||
bestscr = scr;
|
||||
bestarea = ar;
|
||||
}
|
||||
bestVec = corners.at(i);
|
||||
bestDist = dist;
|
||||
}
|
||||
}
|
||||
return bestarea;
|
||||
}
|
||||
int FindNearestValid(Vector vec)
|
||||
{
|
||||
if (reselect.test_and_set(500))
|
||||
|
||||
Vector bestVec2{};
|
||||
float bestDist2 = FLT_MAX;
|
||||
|
||||
for (size_t i = 0; i < corners.size(); i++)
|
||||
{
|
||||
float bestscr = FLT_MAX;
|
||||
if (bestarea != -1)
|
||||
if (corners.at(i) == bestVec2)
|
||||
continue;
|
||||
float dist = corners.at(i).DistTo(Target->m_center);
|
||||
if (dist < bestDist2)
|
||||
{
|
||||
bool success = false;
|
||||
Vector area = areas[bestarea].m_center;
|
||||
area.z += 72.0f;
|
||||
if (IsPlayerDisguised(LOCAL_E) ||
|
||||
!TF2MAP->inactiveTracker.sentryAreas[bestarea])
|
||||
{
|
||||
float scr = area.DistTo(vec);
|
||||
if (scr < 2000.0f)
|
||||
if (IsVectorVisible(vec, area, false))
|
||||
success = true;
|
||||
}
|
||||
if (!success)
|
||||
bestarea = -1;
|
||||
bestVec2 = corners.at(i);
|
||||
bestDist2 = dist;
|
||||
}
|
||||
}
|
||||
return (bestVec + bestVec2) / 2;
|
||||
}
|
||||
|
||||
float getZBetweenAreas(CNavArea *start, CNavArea *end)
|
||||
{
|
||||
float z1 = GetClosestCornerToArea(start, end).z;
|
||||
float z2 = GetClosestCornerToArea(end, start).z;
|
||||
|
||||
return z2 - z1;
|
||||
}
|
||||
|
||||
class ignoremanager
|
||||
{
|
||||
static std::unordered_map<std::pair<CNavArea *, CNavArea *>, ignoredata,
|
||||
boost::hash<std::pair<CNavArea *, CNavArea *>>>
|
||||
ignores;
|
||||
static bool vischeck(CNavArea *begin, CNavArea *end)
|
||||
{
|
||||
Vector first = begin->m_center;
|
||||
Vector second = end->m_center;
|
||||
first.z += 42;
|
||||
second.z += 42;
|
||||
return IsVectorVisible(first, second, true);
|
||||
}
|
||||
static ignore_status runIgnoreChecks(CNavArea *begin, CNavArea *end)
|
||||
{
|
||||
if (getZBetweenAreas(begin, end) > 42)
|
||||
return const_ignored;
|
||||
if (!vischecks)
|
||||
return vischeck_success;
|
||||
if (vischeck(begin, end))
|
||||
return vischeck_success;
|
||||
else
|
||||
for (int ar = 0; ar < areas.size(); ar++)
|
||||
return vischeck_failed;
|
||||
}
|
||||
static void updateDanger()
|
||||
{
|
||||
for (size_t i = 0; i < HIGHEST_ENTITY; i++)
|
||||
{
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
if (CE_BAD(ent))
|
||||
continue;
|
||||
if (ent->m_iClassID() == CL_CLASS(CObjectSentrygun))
|
||||
{
|
||||
Vector area = areas[ar].m_center;
|
||||
area.z += 72.0f;
|
||||
if (!IsPlayerDisguised(LOCAL_E) &&
|
||||
TF2MAP->inactiveTracker.sentryAreas[ar])
|
||||
if (!ent->m_bEnemy())
|
||||
continue;
|
||||
float scr = area.DistTo(vec);
|
||||
if (scr > 2000.0f)
|
||||
continue;
|
||||
if (scr > bestscr)
|
||||
continue;
|
||||
if (IsVectorVisible(vec, area, false))
|
||||
Vector loc = GetBuildingPosition(ent);
|
||||
for (auto &i : navfile->m_areas)
|
||||
{
|
||||
bestscr = scr;
|
||||
bestarea = ar;
|
||||
Vector area = i.m_center;
|
||||
area.z += 41.5f;
|
||||
if (loc.DistTo(area) > 1100)
|
||||
continue;
|
||||
// Check if sentry can see us
|
||||
if (!IsVectorVisible(loc, area, true))
|
||||
continue;
|
||||
ignoredata &data = ignores[{ &i, nullptr }];
|
||||
data.status = danger_found;
|
||||
data.ignoreTimeout.update();
|
||||
}
|
||||
}
|
||||
else if (ent->m_iClassID() ==
|
||||
CL_CLASS(CTFGrenadePipebombProjectile))
|
||||
{
|
||||
if (!ent->m_bEnemy())
|
||||
continue;
|
||||
if (CE_INT(ent, netvar.iPipeType) == 1)
|
||||
continue;
|
||||
Vector loc = ent->m_vecOrigin();
|
||||
for (auto &i : navfile->m_areas)
|
||||
{
|
||||
Vector area = i.m_center;
|
||||
if (loc.DistTo(area) > 130)
|
||||
continue;
|
||||
area.z += 41.5f;
|
||||
// Check if sentry can see us
|
||||
if (!IsVectorVisible(loc, area, true))
|
||||
continue;
|
||||
ignoredata &data = ignores[{ &i, nullptr }];
|
||||
data.status = danger_found;
|
||||
data.ignoreTimeout.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestarea;
|
||||
}
|
||||
void Init()
|
||||
|
||||
static void checkPath()
|
||||
{
|
||||
bool perform_repath = false;
|
||||
// Vischecks
|
||||
for (size_t i = 0; i < crumbs.size() - 1; i++)
|
||||
{
|
||||
CNavArea *begin = getNavArea(crumbs.at(i));
|
||||
CNavArea *end = getNavArea(crumbs.at(i + 1));
|
||||
if (!begin || !end)
|
||||
continue;
|
||||
ignoredata &data = ignores[{ begin, end }];
|
||||
if (data.status == vischeck_failed)
|
||||
return;
|
||||
if (!vischeck(begin, end))
|
||||
{
|
||||
data.status = vischeck_failed;
|
||||
data.ignoreTimeout.update();
|
||||
perform_repath = true;
|
||||
}
|
||||
else if (ignores[{ end, nullptr }].status == danger_found)
|
||||
{
|
||||
perform_repath = true;
|
||||
}
|
||||
}
|
||||
if (perform_repath)
|
||||
repath();
|
||||
}
|
||||
|
||||
public:
|
||||
// 0 = Not ignored, 1 = low priority, 2 = ignored
|
||||
static int isIgnored(CNavArea *begin, CNavArea *end)
|
||||
{
|
||||
if (ignores[{ end, nullptr }].status == danger_found)
|
||||
return 2;
|
||||
ignore_status &status = ignores[{ begin, end }].status;
|
||||
if (status == unknown)
|
||||
status = runIgnoreChecks(begin, end);
|
||||
if (status == vischeck_success)
|
||||
return 0;
|
||||
else if (status == vischeck_failed)
|
||||
return 1;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
static void addTime(CNavArea *begin, CNavArea *end, Timer &time)
|
||||
{
|
||||
// Check if connection is already known
|
||||
if (ignores.find({ begin, end }) == ignores.end())
|
||||
{
|
||||
ignores[{ begin, end }] = {};
|
||||
}
|
||||
ignoredata &connection = ignores[{ begin, end }];
|
||||
connection.stucktime +=
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now() - time.last)
|
||||
.count();
|
||||
if (connection.stucktime > 3999)
|
||||
{
|
||||
connection.status = explicit_ignored;
|
||||
connection.ignoreTimeout.update();
|
||||
logging::Info("Ignored Connection %i-%i", begin->m_id, end->m_id);
|
||||
}
|
||||
}
|
||||
static void addTime(Vector &begin, Vector &end, Timer &time)
|
||||
{
|
||||
// todo: check nullptr
|
||||
CNavArea *begin_area = getNavArea(begin);
|
||||
CNavArea *end_area = getNavArea(end);
|
||||
if (!begin_area || !end_area)
|
||||
{
|
||||
// We can't reach the destination vector. Destination vector might
|
||||
// be out of bounds/reach.
|
||||
crumbs.clear();
|
||||
return;
|
||||
}
|
||||
addTime(begin_area, end_area, time);
|
||||
}
|
||||
static void reset()
|
||||
{
|
||||
ignores.clear();
|
||||
ResetPather();
|
||||
}
|
||||
static void updateIgnores()
|
||||
{
|
||||
static Timer update{};
|
||||
static Timer last_pather_reset{};
|
||||
static bool reset_pather = false;
|
||||
if (!update.test_and_set(500))
|
||||
return;
|
||||
updateDanger();
|
||||
if (crumbs.empty())
|
||||
{
|
||||
for (auto &i : ignores)
|
||||
{
|
||||
switch (i.second.status)
|
||||
{
|
||||
case explicit_ignored:
|
||||
if (i.second.ignoreTimeout.check(60000))
|
||||
{
|
||||
i.second.status = unknown;
|
||||
i.second.stucktime = 0;
|
||||
reset_pather = true;
|
||||
}
|
||||
break;
|
||||
case unknown:
|
||||
break;
|
||||
case danger_found:
|
||||
if (i.second.ignoreTimeout.check(20000))
|
||||
{
|
||||
i.second.status = unknown;
|
||||
reset_pather = true;
|
||||
}
|
||||
break;
|
||||
case vischeck_failed:
|
||||
case vischeck_success:
|
||||
default:
|
||||
if (i.second.ignoreTimeout.check(30000))
|
||||
{
|
||||
i.second.status = unknown;
|
||||
i.second.stucktime = 0;
|
||||
reset_pather = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
checkPath();
|
||||
if (reset_pather && last_pather_reset.test_and_set(10000))
|
||||
{
|
||||
reset_pather = false;
|
||||
ResetPather();
|
||||
}
|
||||
}
|
||||
static bool isSafe(CNavArea *area)
|
||||
{
|
||||
return !(ignores[{ area, nullptr }].status == danger_found);
|
||||
}
|
||||
ignoremanager() = delete;
|
||||
};
|
||||
std::unordered_map<std::pair<CNavArea *, CNavArea *>, ignoredata,
|
||||
boost::hash<std::pair<CNavArea *, CNavArea *>>>
|
||||
ignoremanager::ignores;
|
||||
|
||||
struct Graph : public micropather::Graph
|
||||
{
|
||||
std::unique_ptr<micropather::MicroPather> pather;
|
||||
|
||||
Graph()
|
||||
{
|
||||
pather =
|
||||
std::make_unique<micropather::MicroPather>(this, 3000, 6, true);
|
||||
}
|
||||
~Graph() override
|
||||
{
|
||||
}
|
||||
void AdjacentCost(void *state,
|
||||
MP_VECTOR<micropather::StateCost> *adjacent) override
|
||||
{
|
||||
CNavArea *center = static_cast<CNavArea *>(state);
|
||||
for (auto &i : center->m_connections)
|
||||
{
|
||||
CNavArea *neighbour = i.area;
|
||||
int isIgnored = ignoremanager::isIgnored(center, neighbour);
|
||||
if (isIgnored == 2)
|
||||
continue;
|
||||
float distance = center->m_center.DistTo(i.area->m_center);
|
||||
if (isIgnored == 1)
|
||||
distance += 50000;
|
||||
micropather::StateCost cost{ static_cast<void *>(neighbour),
|
||||
distance };
|
||||
adjacent->push_back(cost);
|
||||
}
|
||||
}
|
||||
float LeastCostEstimate(void *stateStart, void *stateEnd) override
|
||||
{
|
||||
CNavArea *start = static_cast<CNavArea *>(stateStart);
|
||||
CNavArea *end = static_cast<CNavArea *>(stateEnd);
|
||||
return start->m_center.DistTo(end->m_center);
|
||||
}
|
||||
void PrintStateInfo(void *) override
|
||||
{
|
||||
// Uhh no
|
||||
}
|
||||
};
|
||||
|
||||
// Navfile containing areas
|
||||
std::unique_ptr<CNavFile> navfile;
|
||||
// Status
|
||||
std::atomic<init_status> status;
|
||||
|
||||
// See "Graph", does pathing and stuff I guess
|
||||
static Graph Map;
|
||||
|
||||
void initThread()
|
||||
{
|
||||
// Get NavFile location
|
||||
std::string lvlname(g_IEngine->GetLevelName());
|
||||
size_t dotpos = lvlname.find('.');
|
||||
lvlname = lvlname.substr(0, dotpos);
|
||||
|
||||
std::string lvldir("/home/");
|
||||
passwd *pwd = getpwuid(getuid());
|
||||
lvldir.append(pwd->pw_name);
|
||||
@ -116,136 +386,131 @@ void Init()
|
||||
lvldir.append(".nav");
|
||||
logging::Info(format("Pathing: Nav File location: ", lvldir).c_str());
|
||||
|
||||
areas.clear();
|
||||
// Load the NavFile
|
||||
navfile = CNavFile(lvldir.c_str());
|
||||
if (!navfile.m_isOK)
|
||||
logging::Info("Pathing: Invalid Nav File");
|
||||
else
|
||||
navfile = std::make_unique<CNavFile>(lvldir.c_str());
|
||||
|
||||
if (!navfile->m_isOK)
|
||||
{
|
||||
size_t size = navfile.m_areas.size();
|
||||
logging::Info(
|
||||
format("Pathing: Number of areas to index:", size).c_str());
|
||||
areas.reserve(size);
|
||||
// Add areas from CNavFile to our Vector
|
||||
for (auto i : navfile.m_areas)
|
||||
areas.push_back(i);
|
||||
// Don't reserve more than 7000 states
|
||||
if (size > 7000)
|
||||
size = 7000;
|
||||
// Initiate "Map", contains micropather object
|
||||
TF2MAP = std::make_unique<MAP>(size);
|
||||
TF2MAP->inactiveTracker.reset();
|
||||
navfile.reset();
|
||||
status = unavailable;
|
||||
return;
|
||||
}
|
||||
if (!areas.empty())
|
||||
pathfinding = true;
|
||||
threadingFinished.store(true);
|
||||
logging::Info("Pather: Initing with %i Areas", navfile->m_areas.size());
|
||||
status = on;
|
||||
}
|
||||
|
||||
static std::string lastmap;
|
||||
// Function that decides if pathing is possible, and inits pathing if necessary
|
||||
bool Prepare()
|
||||
void init()
|
||||
{
|
||||
ignoremanager::reset();
|
||||
status = initing;
|
||||
std::thread thread;
|
||||
thread = std::thread(initThread);
|
||||
thread.detach();
|
||||
}
|
||||
|
||||
bool prepare()
|
||||
{
|
||||
if (!enabled)
|
||||
return false;
|
||||
if (!init)
|
||||
init_status fast_status = status;
|
||||
if (fast_status == on)
|
||||
return true;
|
||||
if (fast_status == off)
|
||||
{
|
||||
// Don't reinit if same map
|
||||
if (lastmap == g_IEngine->GetLevelName())
|
||||
{
|
||||
init = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastmap = g_IEngine->GetLevelName();
|
||||
pathfinding = false;
|
||||
init = true;
|
||||
threadingFinished.store(false);
|
||||
// Parsing CNavFile takes time, run it in a seperate thread
|
||||
std::thread initer(Init);
|
||||
// We need to either detach or join to avoid std::terminate
|
||||
initer.detach();
|
||||
}
|
||||
init();
|
||||
}
|
||||
if (!pathfinding || !threadingFinished.load())
|
||||
return false;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// This prevents the bot from gettings completely stuck in some cases
|
||||
static std::vector<int> findClosestNavSquare_localAreas(6);
|
||||
static std::vector<CNavArea *> findClosestNavSquare_localAreas(6);
|
||||
// Function for getting closest Area to player, aka "LocalNav"
|
||||
int findClosestNavSquare(Vector vec)
|
||||
CNavArea *findClosestNavSquare(Vector vec)
|
||||
{
|
||||
if (findClosestNavSquare_localAreas.size() > 5)
|
||||
findClosestNavSquare_localAreas.erase(
|
||||
findClosestNavSquare_localAreas.begin());
|
||||
std::vector<std::pair<int, CNavArea *>> overlapping;
|
||||
for (size_t i = 0; i < areas.size(); i++)
|
||||
|
||||
bool is_local = vec == g_pLocalPlayer->v_Origin;
|
||||
|
||||
auto &areas = navfile->m_areas;
|
||||
std::vector<CNavArea *> overlapping;
|
||||
|
||||
for (auto &i : areas)
|
||||
{
|
||||
// Check if we are within x and y bounds of an area
|
||||
if (areas.at(i).IsOverlapping(vec))
|
||||
if (i.IsOverlapping(vec))
|
||||
{
|
||||
// Make sure we're not stuck on the same area for too long
|
||||
if (std::count(findClosestNavSquare_localAreas.begin(),
|
||||
findClosestNavSquare_localAreas.end(), i) < 3)
|
||||
overlapping.emplace_back(i, &areas.at(i));
|
||||
findClosestNavSquare_localAreas.end(), &i) < 3)
|
||||
{
|
||||
if (IsVectorVisible(vec, i.m_center, true))
|
||||
overlapping.push_back(&i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If multiple candidates for LocalNav have been found, pick the closest
|
||||
float bestDist = FLT_MAX;
|
||||
int bestSquare = -1;
|
||||
for (size_t i = 0; i < overlapping.size(); i++)
|
||||
float bestDist = FLT_MAX;
|
||||
CNavArea *bestSquare = nullptr;
|
||||
for (auto &i : overlapping)
|
||||
{
|
||||
float dist = overlapping.at(i).second->m_center.DistTo(vec);
|
||||
float dist = i->m_center.DistTo(vec);
|
||||
if (dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
bestSquare = overlapping.at(i).first;
|
||||
bestSquare = i;
|
||||
}
|
||||
}
|
||||
if (bestSquare != -1)
|
||||
|
||||
if (bestSquare != nullptr)
|
||||
{
|
||||
if (vec == g_pLocalPlayer->v_Origin)
|
||||
if (is_local)
|
||||
findClosestNavSquare_localAreas.push_back(bestSquare);
|
||||
return bestSquare;
|
||||
}
|
||||
// If no LocalNav was found, pick the closest available Area
|
||||
for (size_t i = 0; i < areas.size(); i++)
|
||||
bestDist = FLT_MAX;
|
||||
for (auto &i : areas)
|
||||
{
|
||||
float dist = areas.at(i).m_center.DistTo(vec);
|
||||
float dist = i.m_center.DistTo(vec);
|
||||
if (dist < bestDist)
|
||||
{
|
||||
if (std::count(findClosestNavSquare_localAreas.begin(),
|
||||
findClosestNavSquare_localAreas.end(), i) < 3)
|
||||
findClosestNavSquare_localAreas.end(), &i) < 3)
|
||||
{
|
||||
bestDist = dist;
|
||||
bestSquare = i;
|
||||
bestSquare = &i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vec == g_pLocalPlayer->v_Origin)
|
||||
if (is_local)
|
||||
findClosestNavSquare_localAreas.push_back(bestSquare);
|
||||
return bestSquare;
|
||||
}
|
||||
|
||||
std::vector<Vector> findPath(Vector loc, Vector dest, int &id_loc, int &id_dest)
|
||||
std::vector<Vector> findPath(Vector start, Vector end)
|
||||
{
|
||||
if (areas.empty())
|
||||
return std::vector<Vector>(0);
|
||||
// Get areas of Vector loc and dest
|
||||
id_loc = findClosestNavSquare(loc);
|
||||
id_dest = findClosestNavSquare(dest);
|
||||
if (id_loc == -1 || id_dest == -1)
|
||||
return std::vector<Vector>(0);
|
||||
float cost;
|
||||
if (status != on)
|
||||
return {};
|
||||
CNavArea *local = findClosestNavSquare(start);
|
||||
CNavArea *dest = findClosestNavSquare(end);
|
||||
|
||||
if (!local || !dest)
|
||||
return {};
|
||||
micropather::MPVector<void *> pathNodes;
|
||||
// Find a solution to get to location
|
||||
int result = TF2MAP->pather->Solve(static_cast<void *>(&areas.at(id_loc)),
|
||||
static_cast<void *>(&areas.at(id_dest)),
|
||||
&pathNodes, &cost);
|
||||
logging::Info(format("Pathing: Pather result: ", result).c_str());
|
||||
float cost;
|
||||
std::chrono::time_point begin_pathing =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
int result =
|
||||
Map.pather->Solve(static_cast<void *>(local), static_cast<void *>(dest),
|
||||
&pathNodes, &cost);
|
||||
long long timetaken =
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::high_resolution_clock::now() - begin_pathing)
|
||||
.count();
|
||||
logging::Info("Pathing: Pather result: %i. Time taken (NS): %lld", result,
|
||||
timetaken);
|
||||
// If no result found, return empty Vector
|
||||
if (result == micropather::MicroPather::NO_SOLUTION)
|
||||
return std::vector<Vector>(0);
|
||||
@ -256,117 +521,67 @@ std::vector<Vector> findPath(Vector loc, Vector dest, int &id_loc, int &id_dest)
|
||||
path.push_back(static_cast<CNavArea *>(pathNodes[i])->m_center);
|
||||
}
|
||||
// Add our destination to the std::vector
|
||||
path.push_back(dest);
|
||||
path.push_back(end);
|
||||
return path;
|
||||
}
|
||||
|
||||
// Timer for measuring inactivity, aka time between not reaching a crumb
|
||||
static Vector loc(0.0f, 0.0f, 0.0f);
|
||||
static Vector last_area(0.0f, 0.0f, 0.0f);
|
||||
bool ReadyForCommands = true;
|
||||
static Timer inactivity{};
|
||||
// Time since our last Jump
|
||||
static Timer lastJump{};
|
||||
// std::vector containing our path
|
||||
static std::vector<Vector> crumbs;
|
||||
// Bot will keep trying to get to the target even if it fails a few times
|
||||
static bool ensureArrival;
|
||||
// Priority value for current instructions, only higher or equal priorites can
|
||||
// overwrite it
|
||||
int priority = 0;
|
||||
static Vector lastArea = { 0.0f, 0.0f, 0.0f };
|
||||
static int persistentTries = 0;
|
||||
int curr_priority = 0;
|
||||
static bool ensureArrival = false;
|
||||
|
||||
// dest = Destination, navToLocalCenter = Should bot travel to local center
|
||||
// first before resuming pathing activity? (Increases accuracy) persistent =
|
||||
// ensureArrival above, instructionPriority = priority above
|
||||
bool NavTo(Vector dest, bool navToLocalCenter, bool persistent,
|
||||
int instructionPriority)
|
||||
bool navTo(Vector destination, int priority, bool should_repath,
|
||||
bool nav_to_local, bool is_repath)
|
||||
{
|
||||
if (CE_BAD(LOCAL_E))
|
||||
if (!prepare())
|
||||
return false;
|
||||
if (!Prepare())
|
||||
if (priority < curr_priority)
|
||||
return false;
|
||||
// Only allow instructions to overwrite others if their priority is higher
|
||||
if (instructionPriority < priority)
|
||||
return false;
|
||||
int locNav = 0, tarNav = 0;
|
||||
auto path = findPath(g_pLocalPlayer->v_Origin, dest, locNav, tarNav);
|
||||
std::vector<Vector> path = findPath(g_pLocalPlayer->v_Origin, destination);
|
||||
if (path.empty())
|
||||
return false;
|
||||
last_area = path.at(0);
|
||||
if (!nav_to_local)
|
||||
{
|
||||
path.erase(path.begin());
|
||||
if (path.empty())
|
||||
return false;
|
||||
}
|
||||
inactivity.update();
|
||||
if (!is_repath)
|
||||
{
|
||||
findClosestNavSquare_localAreas.clear();
|
||||
}
|
||||
if (!crumbs.empty())
|
||||
{
|
||||
bool reset = false;
|
||||
TF2MAP->inactiveTracker.AddTime({ lastArea, crumbs.at(0) }, inactivity,
|
||||
reset);
|
||||
if (reset)
|
||||
TF2MAP->pather->Reset();
|
||||
ignoremanager::addTime(last_area, crumbs.at(0), inactivity);
|
||||
}
|
||||
ensureArrival = should_repath;
|
||||
ReadyForCommands = false;
|
||||
curr_priority = priority;
|
||||
crumbs.clear();
|
||||
crumbs = std::move(path);
|
||||
if (crumbs.empty())
|
||||
return false;
|
||||
lastArea = crumbs.at(0);
|
||||
if (!navToLocalCenter && crumbs.size() > 1)
|
||||
crumbs.erase(crumbs.begin());
|
||||
ensureArrival = persistent;
|
||||
findClosestNavSquare_localAreas.clear();
|
||||
priority = instructionPriority;
|
||||
inactivity.update();
|
||||
persistentTries = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void clearInstructions()
|
||||
void repath()
|
||||
{
|
||||
crumbs.clear();
|
||||
}
|
||||
|
||||
static Timer ignoreReset{};
|
||||
static Timer patherReset{};
|
||||
static Timer sentryUpdate{};
|
||||
static Timer sentryClear{};
|
||||
static Timer sentryCheck{};
|
||||
// Function for removing ignores
|
||||
void ignoreManagerCM()
|
||||
{
|
||||
if (!TF2MAP || !TF2MAP->pather)
|
||||
return;
|
||||
if (ignoreReset.test_and_set(120000))
|
||||
TF2MAP->inactiveTracker.reset();
|
||||
if (patherReset.test_and_set(30000))
|
||||
TF2MAP->pather->Reset();
|
||||
if (sentryClear.test_and_set(20000))
|
||||
TF2MAP->inactiveTracker.ClearSentries();
|
||||
if (sentryUpdate.test_and_set(500))
|
||||
TF2MAP->inactiveTracker.AddSentries();
|
||||
}
|
||||
|
||||
void Repath()
|
||||
{
|
||||
if (ensureArrival && persistentTries < 10)
|
||||
if (ensureArrival)
|
||||
{
|
||||
logging::Info("Pathing: NavBot inactive for too long. Ignoring "
|
||||
"connection and finding another path...");
|
||||
// Throwaway int
|
||||
int i1 = 0, i2 = 0;
|
||||
// Find a new path
|
||||
TF2MAP->pather->Reset();
|
||||
crumbs = findPath(g_pLocalPlayer->v_Origin, crumbs.back(), i1, i2);
|
||||
persistentTries++;
|
||||
}
|
||||
else
|
||||
{
|
||||
logging::Info(
|
||||
"Pathing: NavBot inactive for too long. Canceling tasks and "
|
||||
"ignoring connection...");
|
||||
// Wait for new instructions
|
||||
TF2MAP->pather->Reset();
|
||||
Vector last = crumbs.back();
|
||||
crumbs.clear();
|
||||
ResetPather();
|
||||
navTo(last, curr_priority, true, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
static Timer last_jump{};
|
||||
// Main movement function, gets path from NavTo
|
||||
static HookedFunction
|
||||
CreateMove(HookedFunctions_types::HF_CreateMove, "NavParser", 17, []() {
|
||||
if (!enabled || !threadingFinished.load())
|
||||
if (!enabled || status != on)
|
||||
return;
|
||||
if (CE_BAD(LOCAL_E))
|
||||
return;
|
||||
@ -376,11 +591,11 @@ static HookedFunction
|
||||
crumbs.clear();
|
||||
return;
|
||||
}
|
||||
ignoreManagerCM();
|
||||
ignoremanager::updateIgnores();
|
||||
// Crumbs empty, prepare for next instruction
|
||||
if (crumbs.empty())
|
||||
{
|
||||
priority = 0;
|
||||
curr_priority = 0;
|
||||
ReadyForCommands = true;
|
||||
ensureArrival = false;
|
||||
return;
|
||||
@ -390,56 +605,33 @@ static HookedFunction
|
||||
if (g_pLocalPlayer->v_Origin.DistTo(Vector{
|
||||
crumbs.at(0).x, crumbs.at(0).y, crumbs.at(0).z }) < 50.0f)
|
||||
{
|
||||
lastArea = crumbs.at(0);
|
||||
last_area = crumbs.at(0);
|
||||
crumbs.erase(crumbs.begin());
|
||||
inactivity.update();
|
||||
}
|
||||
if (crumbs.empty())
|
||||
return;
|
||||
// Detect when jumping is necessary
|
||||
if ((crumbs.at(0).z - g_pLocalPlayer->v_Origin.z > 18 &&
|
||||
lastJump.test_and_set(200)) ||
|
||||
(lastJump.test_and_set(200) && inactivity.check(2000)))
|
||||
if ((!(g_pLocalPlayer->holding_sniper_rifle &&
|
||||
g_pLocalPlayer->bZoomed) &&
|
||||
crumbs.at(0).z - g_pLocalPlayer->v_Origin.z > 18 &&
|
||||
last_jump.test_and_set(200)) ||
|
||||
(last_jump.test_and_set(200) && inactivity.check(3000)))
|
||||
current_user_cmd->buttons |= IN_JUMP;
|
||||
// Check if were dealing with a type 2 connection
|
||||
if (inactivity.check(3000) &&
|
||||
TF2MAP->inactiveTracker.CheckType2({ lastArea, crumbs.at(0) }))
|
||||
{
|
||||
logging::Info("Pathing: Type 2 connection detected!");
|
||||
TF2MAP->pather->Reset();
|
||||
Repath();
|
||||
inactivity.update();
|
||||
return;
|
||||
}
|
||||
// Check for new sentries
|
||||
if (sentryCheck.test_and_set(500) &&
|
||||
TF2MAP->inactiveTracker.ShouldCancelPath(crumbs))
|
||||
{
|
||||
logging::Info("Pathing: New Sentry found!");
|
||||
TF2MAP->pather->Reset();
|
||||
Repath();
|
||||
return;
|
||||
}
|
||||
// If inactive for too long
|
||||
if (inactivity.check(3000))
|
||||
if (inactivity.check(4000))
|
||||
{
|
||||
// Ignore connection
|
||||
bool resetPather = false;
|
||||
TF2MAP->inactiveTracker.AddTime({ lastArea, crumbs.at(0) },
|
||||
inactivity, resetPather);
|
||||
if (resetPather)
|
||||
TF2MAP->pather->Reset();
|
||||
Repath();
|
||||
inactivity.update();
|
||||
ignoremanager::addTime(last_area, crumbs.at(0), inactivity);
|
||||
repath();
|
||||
return;
|
||||
}
|
||||
// Walk to next crumb
|
||||
WalkTo(crumbs.at(0));
|
||||
});
|
||||
|
||||
void Draw()
|
||||
{
|
||||
#if ENABLE_VISUALS
|
||||
static HookedFunction drawcrumbs(HF_Draw, "navparser", 10, []() {
|
||||
if (!enabled || !draw)
|
||||
return;
|
||||
if (!enabled)
|
||||
@ -465,27 +657,21 @@ void Draw()
|
||||
return;
|
||||
glez::draw::rect(wts.x - 4, wts.y - 4, 8, 8, colors::white);
|
||||
glez::draw::rect_outline(wts.x - 4, wts.y - 4, 7, 7, colors::white, 1.0f);
|
||||
});
|
||||
#endif
|
||||
|
||||
void ResetPather()
|
||||
{
|
||||
Map.pather->Reset();
|
||||
}
|
||||
|
||||
CatCommand navinit("nav_init", "Debug nav init", [](const CCommand &args) {
|
||||
lastmap = "";
|
||||
init = false;
|
||||
Prepare();
|
||||
});
|
||||
bool isSafe(CNavArea *area)
|
||||
{
|
||||
return ignoremanager::isSafe(area);
|
||||
}
|
||||
|
||||
Vector loc;
|
||||
|
||||
CatCommand navset("nav_set", "Debug nav set",
|
||||
[](const CCommand &args) { loc = LOCAL_E->m_vecOrigin(); });
|
||||
CatCommand navprint("nav_print", "Debug nav print", [](const CCommand &args) {
|
||||
logging::Info(
|
||||
format(findClosestNavSquare(g_pLocalPlayer->v_Origin)).c_str());
|
||||
});
|
||||
|
||||
CatCommand navfind("nav_find", "Debug nav find", [](const CCommand &args) {
|
||||
int i1 = 0, i2 = 0;
|
||||
std::vector<Vector> path = findPath(g_pLocalPlayer->v_Origin, loc, i1, i2);
|
||||
static CatCommand nav_find("nav_find", "Debug nav find", []() {
|
||||
std::vector<Vector> path = findPath(g_pLocalPlayer->v_Origin, loc);
|
||||
if (path.empty())
|
||||
{
|
||||
logging::Info("Pathing: No path found");
|
||||
@ -499,29 +685,23 @@ CatCommand navfind("nav_find", "Debug nav find", [](const CCommand &args) {
|
||||
logging::Info(output.c_str());
|
||||
});
|
||||
|
||||
CatCommand navpath("nav_path", "Debug nav path", [](const CCommand &args) {
|
||||
if (NavTo(loc, true, true, 50 + priority))
|
||||
{
|
||||
logging::Info("Pathing: Success! Walking to path...");
|
||||
}
|
||||
else
|
||||
{
|
||||
logging::Info("Pathing: Failed!");
|
||||
}
|
||||
static CatCommand nav_set("nav_set", "Debug nav find",
|
||||
[]() { loc = g_pLocalPlayer->v_Origin; });
|
||||
|
||||
static CatCommand nav_init("nav_init", "Debug nav init", []() {
|
||||
status = off;
|
||||
prepare();
|
||||
});
|
||||
|
||||
// Clang format pls
|
||||
CatCommand navpathnolocal("nav_path_nolocal", "Debug nav path",
|
||||
[](const CCommand &args) {
|
||||
if (NavTo(loc, false, true, 50 + priority))
|
||||
{
|
||||
logging::Info(
|
||||
"Pathing: Success! Walking to path...");
|
||||
}
|
||||
else
|
||||
{
|
||||
logging::Info("Pathing: Failed!");
|
||||
}
|
||||
});
|
||||
static CatCommand nav_path("nav_path", "Debug nav path", []() { navTo(loc); });
|
||||
|
||||
static CatCommand nav_reset_ignores("nav_reset_ignores", "Reset all ignores.",
|
||||
[]() { ignoremanager::reset(); });
|
||||
|
||||
void clearInstructions()
|
||||
{
|
||||
crumbs.clear();
|
||||
curr_priority = 0;
|
||||
}
|
||||
|
||||
} // namespace nav
|
||||
|
@ -86,6 +86,7 @@ bool trace::FilterNoPlayer::ShouldHitEntity(IHandleEntity *handle, int mask)
|
||||
return false;
|
||||
entity = (IClientEntity *) handle;
|
||||
clazz = entity->GetClientClass();
|
||||
|
||||
/* Ignore invisible entities that we don't wanna hit */
|
||||
switch (clazz->m_ClassID)
|
||||
{
|
||||
@ -129,6 +130,21 @@ void trace::FilterNoEntity::SetSelf(IClientEntity *self)
|
||||
|
||||
bool trace::FilterNoEntity::ShouldHitEntity(IHandleEntity *handle, int mask)
|
||||
{
|
||||
IClientEntity *entity;
|
||||
ClientClass *clazz;
|
||||
|
||||
if (!handle)
|
||||
return false;
|
||||
entity = (IClientEntity *) handle;
|
||||
clazz = entity->GetClientClass();
|
||||
|
||||
// Hit doors, carts, etc
|
||||
switch (clazz->m_ClassID)
|
||||
{
|
||||
case 6:
|
||||
case 7:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,10 @@ static settings::Bool disco_chams{ "chams.disco", "false" };
|
||||
|
||||
namespace effect_chams
|
||||
{
|
||||
|
||||
CatCommand fix_black_chams("fix_black_chams", "Fix Black Chams", [](){
|
||||
effect_chams::g_EffectChams.Shutdown();
|
||||
effect_chams::g_EffectChams.Init();
|
||||
});
|
||||
void EffectChams::Init()
|
||||
{
|
||||
logging::Info("Init EffectChams...");
|
||||
@ -79,7 +82,7 @@ void EffectChams::EndRenderChams()
|
||||
CMatRenderContextPtr ptr(GET_RENDER_CONTEXT);
|
||||
g_IVModelRender->ForcedMaterialOverride(nullptr);
|
||||
}
|
||||
static rgba_t data[32] = {};
|
||||
static rgba_t data[32] = {colors::empty};
|
||||
void EffectChams::SetEntityColor(CachedEntity *ent, rgba_t color)
|
||||
{
|
||||
if (ent->m_IDX > 31 || ent->m_IDX < 0)
|
||||
@ -151,10 +154,11 @@ rgba_t EffectChams::ChamsColor(IClientEntity *entity)
|
||||
}
|
||||
return disco;
|
||||
}
|
||||
if (data[entity->entindex()])
|
||||
if (data[entity->entindex()] != colors::empty)
|
||||
{
|
||||
data[entity->entindex()] = {};
|
||||
return data[entity->entindex()];
|
||||
auto toret = data[entity->entindex()];
|
||||
data[entity->entindex()] = colors::empty;
|
||||
return toret;
|
||||
}
|
||||
if (CE_BAD(ent))
|
||||
return colors::white;
|
||||
@ -327,7 +331,6 @@ void EffectChams::RenderChams(IClientEntity *entity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EffectChams::Render(int x, int y, int w, int h)
|
||||
{
|
||||
PROF_SECTION(DRAW_chams);
|
||||
@ -351,7 +354,6 @@ void EffectChams::Render(int x, int y, int w, int h)
|
||||
}
|
||||
EndRenderChams();
|
||||
}
|
||||
|
||||
EffectChams g_EffectChams;
|
||||
CScreenSpaceEffectRegistration *g_pEffectChams = nullptr;
|
||||
} // namespace effect_chams
|
||||
|
@ -138,6 +138,11 @@ static ShaderStencilState_t SS_SolidInvisible{};
|
||||
static ShaderStencilState_t SS_Null{};
|
||||
static ShaderStencilState_t SS_Drawing{};
|
||||
|
||||
CatCommand fix_black_glow("fix_black_glow", "Fix Black Glow", [](){
|
||||
effect_glow::g_EffectGlow.Shutdown();
|
||||
effect_glow::g_EffectGlow.Init();
|
||||
});
|
||||
|
||||
void EffectGlow::Init()
|
||||
{
|
||||
logging::Info("Init Glow...");
|
||||
|
@ -146,10 +146,6 @@ void DrawCheatVisuals()
|
||||
PROF_SECTION(DRAW_walkbot);
|
||||
hacks::shared::walkbot::Draw();
|
||||
}
|
||||
{
|
||||
PROF_SECTION(DRAW_navparse);
|
||||
nav::Draw();
|
||||
}
|
||||
IF_GAME(IsTF())
|
||||
{
|
||||
PROF_SECTION(PT_antidisguise);
|
||||
|
@ -173,7 +173,9 @@ bool gui::handleSdlEvent(SDL_Event *event)
|
||||
}
|
||||
}
|
||||
zerokernel::Menu::instance->handleSdlEvent(event);
|
||||
if (!zerokernel::Menu::instance->isInGame() && event->type == SDL_MOUSEBUTTONDOWN)
|
||||
if (!zerokernel::Menu::instance->isInGame() &&
|
||||
(event->type == SDL_MOUSEBUTTONDOWN || event->type == SDL_TEXTINPUT ||
|
||||
event->type == SDL_KEYDOWN))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
8
update
8
update
@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
#Get updated source code
|
||||
git fetch;git pull origin;git submodule update --init --recursive
|
||||
git fetch && git pull origin && git submodule update --init --recursive || { echo -e "\033[1;31m \n \nFailed to pull from github!"; exit 1; }
|
||||
#Update cathook
|
||||
cd build; cmake ..; make -j$(grep -c '^processor' /proc/cpuinfo)
|
||||
cd build && cmake .. && cmake --build . --target cathook -- -j$(grep -c '^processor' /proc/cpuinfo) || { echo -e "\033[1;31m \n \nFailed to compile cathook"; exit 1; }
|
||||
#Update data
|
||||
sudo make data; cd ..; cd ..
|
||||
printf "\n\n";printf '\e[1;34m%-6s\e' "Cathook update complete!";printf "\n\n"
|
||||
sudo cmake --build . --target data || { echo -e "\033[1;31m \n \nFailed to update /opt/cathook/data directory"; exit 1; }
|
||||
echo -e "\n\n\033[1;34mCathook updated successfully"
|
||||
|
Reference in New Issue
Block a user