Merge pull request #617 from nullworks/experimental

NavParser Rewrite
This commit is contained in:
TotallyNotElite 2018-10-28 17:02:41 +01:00 committed by GitHub
commit 28c190138a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1154 additions and 1433 deletions

View File

@ -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")

View File

@ -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"/>

View File

@ -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

@ -1 +1 @@
Subproject commit 4e9c1ea11dfa80ace20ab0243c7e9dff499a4851
Subproject commit 9457ea150e041689c6f38f5720b4d571cf64a943

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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();

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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{};

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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...");

View File

@ -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);

View File

@ -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
View File

@ -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"