Merge pull request #830 from nullworks/totallynotelite

Merge HWGS and other changes
This commit is contained in:
TotallyNotElite 2019-10-13 21:09:48 +02:00 committed by GitHub
commit 5de55010dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 424 additions and 382 deletions

2
.gitmodules vendored
View File

@ -18,7 +18,7 @@
url = https://github.com/nullworks/co-library.git url = https://github.com/nullworks/co-library.git
[submodule "external/MicroPather"] [submodule "external/MicroPather"]
path = external/MicroPather path = external/MicroPather
url = https://github.com/leethomason/MicroPather url = https://github.com/nullworks/MicroPather
[submodule "external/TF2_NavFile_Reader"] [submodule "external/TF2_NavFile_Reader"]
path = external/TF2_NavFile_Reader path = external/TF2_NavFile_Reader
url = https://github.com/nullworks/TF2_NavFile_Reader url = https://github.com/nullworks/TF2_NavFile_Reader

View File

@ -46,6 +46,7 @@
<Option name="FakeOffset" value="15"/> <Option name="FakeOffset" value="15"/>
<Option name="FakeEdge" value="16"/> <Option name="FakeEdge" value="16"/>
<Option name="FakeHeck" value="17"/> <Option name="FakeHeck" value="17"/>
<Option name="FakeSideways" value="18"/>
<Option name="FakeLeft" value="19"/> <Option name="FakeLeft" value="19"/>
<Option name="FakeRight" value="20"/> <Option name="FakeRight" value="20"/>
<Option name="FakeREdge" value="21"/> <Option name="FakeREdge" value="21"/>

@ -1 +1 @@
Subproject commit 33a3b8403f1bc3937c9d364fe6c3977169bee3b5 Subproject commit c3960ea5af374f2ed6195eb39f803f2611b882a9

View File

@ -32,15 +32,6 @@ struct BacktrackData
int index{ 0 }; int index{ 0 };
matrix3x4_t bones[128]{}; matrix3x4_t bones[128]{};
}; };
struct BestTickData
{
int tickcount{ 0 };
int tick{ 0 };
bool operator<(const BestTickData &rhs) const
{
return tickcount < rhs.tickcount;
}
};
void Init(); void Init();
void AddLatencyToNetchan(INetChannel *); void AddLatencyToNetchan(INetChannel *);
void UpdateIncomingSequences(); void UpdateIncomingSequences();

View File

@ -103,7 +103,7 @@ float DistToSqr(CachedEntity *entity);
void fClampAngle(Vector &qaAng); void fClampAngle(Vector &qaAng);
// const char* MakeInfoString(IClientEntity* player); // const char* MakeInfoString(IClientEntity* player);
bool GetProjectileData(CachedEntity *weapon, float &speed, float &gravity); bool GetProjectileData(CachedEntity *weapon, float &speed, float &gravity);
bool IsVectorVisible(Vector a, Vector b, bool enviroment_only = false, CachedEntity *self = LOCAL_E); bool IsVectorVisible(Vector a, Vector b, bool enviroment_only = false, CachedEntity *self = LOCAL_E, unsigned int mask = MASK_SHOT_HULL);
Vector GetForwardVector(Vector origin, Vector viewangles, float distance); Vector GetForwardVector(Vector origin, Vector viewangles, float distance);
Vector GetForwardVector(float distance); Vector GetForwardVector(float distance);
bool IsSentryBuster(CachedEntity *ent); bool IsSentryBuster(CachedEntity *ent);

View File

@ -26,7 +26,9 @@ extern bool ReadyForCommands;
extern std::atomic<init_status> status; extern std::atomic<init_status> status;
// Nav to vector // Nav to vector
bool navTo(Vector destination, int priority = 5, bool should_repath = true, bool nav_to_local = true, bool is_repath = false); bool navTo(const Vector &destination, int priority = 5, bool should_repath = true, bool nav_to_local = true, bool is_repath = false);
// Find closest to vector area
CNavArea *findClosestNavSquare(const Vector &vec);
// Check and init navparser // Check and init navparser
bool prepare(); bool prepare();
// Clear current path // Clear current path

View File

@ -14,8 +14,8 @@ class TextFile
{ {
public: public:
TextFile(); TextFile();
void Load(std::string filename); void Load(const std::string &filename);
bool TryLoad(std::string filename); bool TryLoad(const std::string &filename);
size_t LineCount() const; size_t LineCount() const;
const std::string &Line(size_t id) const; const std::string &Line(size_t id) const;

View File

@ -34,6 +34,7 @@ static settings::Int equip_primary{ "achievement.equip-primary", "0" };
static settings::Int equip_secondary{ "achievement.equip-secondary", "0" }; static settings::Int equip_secondary{ "achievement.equip-secondary", "0" };
static settings::Int equip_melee{ "achievement.equip-melee", "0" }; static settings::Int equip_melee{ "achievement.equip-melee", "0" };
static settings::Int equip_pda2{ "achievement.equip-pda2", "0" }; static settings::Int equip_pda2{ "achievement.equip-pda2", "0" };
static settings::Boolean hat_troll{ "misc.nohatsforyou", "false" };
bool checkachmngr() bool checkachmngr()
{ {
@ -158,7 +159,6 @@ CatCommand unlock("achievement_unlock", "Unlock all achievements", Unlock);
static bool accept_notifs; static bool accept_notifs;
static bool equip_hats; static bool equip_hats;
static bool equip; static bool equip;
static bool equip_first_half;
std::vector<Autoequip_unlock_list> equip_queue; std::vector<Autoequip_unlock_list> equip_queue;
void unlock_achievements_and_accept(std::vector<int> items) void unlock_achievements_and_accept(std::vector<int> items)
@ -190,16 +190,26 @@ static CatCommand get_best_hats("achievement_cathats", "Get and equip the bencat
hacks::shared::misc::generate_schema(); hacks::shared::misc::generate_schema();
hacks::shared::misc::Schema_Reload(); hacks::shared::misc::Schema_Reload();
equip_hats = true; equip_hats = true;
equip_first_half = true;
}); });
struct queue_struct
{
int clazz;
int slot;
unsigned long long uuid;
};
static std::deque<queue_struct> gc_queue;
bool equip_item(int clazz, int slot, int id) bool equip_item(int clazz, int slot, int id)
{ {
auto invmng = re::CTFInventoryManager::GTFInventoryManager(); auto invmng = re::CTFInventoryManager::GTFInventoryManager();
auto inv = invmng->GTFPlayerInventory(); auto inv = invmng->GTFPlayerInventory();
auto item_view = inv->GetFirstItemOfItemDef(id); auto item_view = inv->GetFirstItemOfItemDef(id);
if (item_view) if (item_view)
return invmng->EquipItemInLoadout(clazz, slot, item_view->UUID()); {
gc_queue.push_front({ clazz, slot, item_view->UUID() });
return true;
}
return false; return false;
} }
@ -212,6 +222,33 @@ bool equip_hats_fn(std::vector<int> hats, std::pair<int, int> classes)
return true; return true;
} }
static std::vector<int> hat_list = { 302, 940, 941 };
// TNE didn't want me to put "epic_" infront of it :(
static Timer hat_steal_timer{};
static Timer gc_timer{};
void CreateMove()
{
if (gc_queue.size() && gc_timer.test_and_set(3000))
{
queue_struct item = gc_queue.at(gc_queue.size() - 1);
auto invmng = re::CTFInventoryManager::GTFInventoryManager();
invmng->EquipItemInLoadout(item.clazz, item.slot, item.uuid);
gc_queue.pop_back();
}
if (!hat_troll)
return;
if (CE_BAD(LOCAL_E))
return;
if (hat_steal_timer.test_and_set(15000))
{
std::rotate(hat_list.begin(), hat_list.begin() + 1, hat_list.end());
equip_hats_fn(hat_list, { g_pLocalPlayer->clazz, g_pLocalPlayer->clazz });
}
}
void Callback(int after, int type) void Callback(int after, int type)
{ {
if (!after) if (!after)
@ -258,6 +295,84 @@ void Callback(int after, int type)
} }
} }
void Paint()
{
// Start accepting
if (accept_notifs)
{
accept_time.update();
accept_notifs = false;
}
// "Trigger/Accept first notification" aka Achievement items
if (!accept_time.check(5000) && cooldowm.test_and_set(500))
g_IEngine->ClientCmd_Unrestricted("cl_trigger_first_notification");
// Hat equip code
if (equip_hats)
{
// If done start accepting notifications, also time out after a while
if (accept_time.check(5000) && !accept_time.check(10000) && cooldowm.test_and_set(500))
{
// Inventory Manager
auto invmng = re::CTFInventoryManager::GTFInventoryManager();
// Inventory
auto inv = invmng->GTFPlayerInventory();
// Frontline field recorder
auto item_view1 = inv->GetFirstItemOfItemDef(302);
// Gibus
auto item_view2 = inv->GetFirstItemOfItemDef(940);
// Skull Island Tropper
auto item_view3 = inv->GetFirstItemOfItemDef(941);
if (item_view1 && item_view2 && item_view3)
{
if (!accept_time.check(7500))
{
// Equip these hats on all classes
bool success = equip_hats_fn({ 302, 940, 941 }, { tf_scout, tf_engineer });
if (success)
{
logging::Info("Equipping hats!");
equip_hats = false;
}
}
}
}
else if (accept_time.check(10000))
equip_hats = false;
}
// Equip weapons
if (equip)
{
// After 5 seconds of accept time, start
if (accept_time.check(5000) && !accept_time.check(10000) && cooldown_2.test_and_set(500))
{
// Watch for each item and equip it
for (int i = 0; i < equip_queue.size(); i++)
{
auto equip = equip_queue.at(i);
bool success = equip_item(equip.player_class, equip.slot, equip.item_id);
if (success)
{
logging::Info("Equipped Item!");
equip_queue.erase(equip_queue.begin() + i);
}
}
// We did it
if (!equip_queue.size())
equip = false;
}
else if (accept_time.check(10000) && cooldown_2.test_and_set(500))
{
if (equip_queue.size())
{
logging::Info("Equipping failed!");
equip_queue.clear();
}
}
}
};
static InitRoutine init([]() { static InitRoutine init([]() {
// Primary list // Primary list
primary.push_back(Autoequip_unlock_list("Force-A-Nature", 1036, 45, tf_scout, 0)); primary.push_back(Autoequip_unlock_list("Force-A-Nature", 1036, 45, tf_scout, 0));
@ -300,93 +415,16 @@ static InitRoutine init([]() {
equip_melee.installChangeCallback([](settings::VariableBase<int> &, int after) { Callback(after, 2); }); equip_melee.installChangeCallback([](settings::VariableBase<int> &, int after) { Callback(after, 2); });
equip_pda2.installChangeCallback([](settings::VariableBase<int> &, int after) { Callback(after, 3); }); equip_pda2.installChangeCallback([](settings::VariableBase<int> &, int after) { Callback(after, 3); });
EC::Register( EC::Register(EC::CreateMove, CreateMove, "cm_nohatsforyou");
EC::Paint, EC::Register(EC::Paint, Paint, "achievement_autounlock");
[]() { hat_troll.installChangeCallback([](settings::VariableBase<bool> &, bool after) {
// Start accepting static bool init = false;
if (accept_notifs) if (after && !init)
{ {
accept_time.update(); hacks::shared::misc::generate_schema();
accept_notifs = false; hacks::shared::misc::Schema_Reload();
init = true;
} }
// "Trigger/Accept first notification" aka Achievement items });
if (!accept_time.check(5000) && cooldowm.test_and_set(500))
g_IEngine->ClientCmd_Unrestricted("cl_trigger_first_notification");
// Hat equip code
if (equip_hats)
{
// If done start accepting notifications, also time out after a while
if (accept_time.check(5000) && !accept_time.check(10000) && cooldowm.test_and_set(500))
{
// Inventory Manager
auto invmng = re::CTFInventoryManager::GTFInventoryManager();
// Inventory
auto inv = invmng->GTFPlayerInventory();
// Frontline field recorder
auto item_view1 = inv->GetFirstItemOfItemDef(302);
// Gibus
auto item_view2 = inv->GetFirstItemOfItemDef(940);
// Skull Island Tropper
auto item_view3 = inv->GetFirstItemOfItemDef(941);
if (item_view1 && item_view2 && item_view3)
{
if (!accept_time.check(7500) && equip_first_half)
{
// Equip these hats on all classes
bool success = equip_hats_fn({ 302, 940, 941 }, { tf_scout, tf_medic });
if (success)
{
logging::Info("Equipped hats on first half!");
equip_first_half = false;
}
}
else if (accept_time.check(7500))
{
bool success = equip_hats_fn({ 302, 940, 941 }, { tf_heavy, tf_engineer });
if (success)
{
logging::Info("Equipped hats on second half!");
equip_hats = false;
}
}
}
}
else if (accept_time.check(10000))
equip_hats = false;
}
// Equip weapons
if (equip)
{
// After 5 seconds of accept time, start
if (accept_time.check(5000) && !accept_time.check(10000) && cooldown_2.test_and_set(500))
{
// Watch for each item and equip it
for (int i = 0; i < equip_queue.size(); i++)
{
auto equip = equip_queue.at(i);
bool success = equip_item(equip.player_class, equip.slot, equip.item_id);
if (success)
{
logging::Info("Equipped Item!");
equip_queue.erase(equip_queue.begin() + i);
}
}
// We did it
if (!equip_queue.size())
equip = false;
}
else if (accept_time.check(10000) && cooldown_2.test_and_set(500))
{
if (equip_queue.size())
{
logging::Info("Equipping failed!");
equip_queue.clear();
}
}
}
},
"achievement_autounlock");
}); });
} // namespace hacks::tf2::achievement } // namespace hacks::tf2::achievement

View File

@ -21,6 +21,7 @@ static settings::Boolean enable{ "aimbot.enable", "false" };
static settings::Button aimkey{ "aimbot.aimkey.button", "<null>" }; static settings::Button aimkey{ "aimbot.aimkey.button", "<null>" };
static settings::Int aimkey_mode{ "aimbot.aimkey.mode", "1" }; static settings::Int aimkey_mode{ "aimbot.aimkey.mode", "1" };
static settings::Boolean autoshoot{ "aimbot.autoshoot", "1" }; static settings::Boolean autoshoot{ "aimbot.autoshoot", "1" };
static settings::Boolean autoreload{ "aimbot.autoshoot.activate-heatmaker", "false" };
static settings::Boolean autoshoot_disguised{ "aimbot.autoshoot-disguised", "1" }; static settings::Boolean autoshoot_disguised{ "aimbot.autoshoot-disguised", "1" };
static settings::Boolean multipoint{ "aimbot.multipoint", "false" }; static settings::Boolean multipoint{ "aimbot.multipoint", "false" };
static settings::Int hitbox_mode{ "aimbot.hitbox-mode", "0" }; static settings::Int hitbox_mode{ "aimbot.hitbox-mode", "0" };
@ -97,6 +98,12 @@ bool IsBacktracking()
return (aimkey ? aimkey.isKeyDown() : true) && shouldBacktrack(); return (aimkey ? aimkey.isKeyDown() : true) && shouldBacktrack();
} }
// Am I holding Hitman's Heatmaker ?
static bool CarryingHeatmaker()
{
return CE_INT(LOCAL_W, netvar.iItemDefinitionIndex) == 752;
}
// Current Entity // Current Entity
int target_eid{ 0 }; int target_eid{ 0 };
CachedEntity *target = 0; CachedEntity *target = 0;
@ -787,7 +794,7 @@ void Aim(CachedEntity *entity)
minz += (maxz - minz) / 6; minz += (maxz - minz) / 6;
// Create Vectors // Create Vectors
const Vector positions[13] = { { minx, centery, minz }, { maxx, centery, minz }, { minx, centery, maxz }, { maxx, centery, maxz }, { centerx, miny, minz }, { centerx, maxy, minz }, { centerx, miny, maxz }, { centerx, maxy, maxz }, { minx, miny, centerz }, { maxx, maxy, centerz }, { minx, miny, centerz }, { maxx, maxy, centerz }, hitboxcenter }; const Vector positions[13] = { { minx, centery, minz }, { maxx, centery, minz }, { minx, centery, maxz }, { maxx, centery, maxz }, { centerx, miny, minz }, { centerx, maxy, minz }, { centerx, miny, maxz }, { centerx, maxy, maxz }, { minx, miny, centerz }, { maxx, maxy, centerz }, { minx, miny, centerz }, { maxx, maxy, centerz }, hitboxcenter };
for (int i = 0; i < 14; ++i) for (int i = 0; i < 13; ++i)
if (IsVectorVisible(g_pLocalPlayer->v_Eye, positions[i])) if (IsVectorVisible(g_pLocalPlayer->v_Eye, positions[i]))
{ {
tr = (positions[i] - g_pLocalPlayer->v_Eye); tr = (positions[i] - g_pLocalPlayer->v_Eye);
@ -905,7 +912,10 @@ void DoAutoshoot()
attack = false; attack = false;
if (attack) if (attack)
current_user_cmd->buttons |= IN_ATTACK; // TO DO: Sending both reload and attack will activate the hitmans heatmaker ability
// Don't activate it only on first kill (or somehow activate it before shoot)
current_user_cmd->buttons |= IN_ATTACK | (*autoreload && CarryingHeatmaker() ? IN_RELOAD : 0);
if (LOCAL_W->m_iClassID() == CL_CLASS(CTFLaserPointer)) if (LOCAL_W->m_iClassID() == CL_CLASS(CTFLaserPointer))
current_user_cmd->buttons |= IN_ATTACK2; current_user_cmd->buttons |= IN_ATTACK2;
hacks::shared::antiaim::SetSafeSpace(1); hacks::shared::antiaim::SetSafeSpace(1);
@ -1025,7 +1035,7 @@ int BestHitbox(CachedEntity *target)
IF_GAME(IsTF()) IF_GAME(IsTF())
{ {
int ci = g_pLocalPlayer->weapon()->m_iClassID(); int ci = g_pLocalPlayer->weapon()->m_iClassID();
preferred = hitbox_t::pelvis; preferred = hitbox_t::spine_2;
// Sniper rifle // Sniper rifle
if (g_pLocalPlayer->holding_sniper_rifle) if (g_pLocalPlayer->holding_sniper_rifle)
{ {
@ -1073,7 +1083,7 @@ int BestHitbox(CachedEntity *target)
{ {
float cdmg = CE_FLOAT(LOCAL_W, netvar.flChargedDamage); float cdmg = CE_FLOAT(LOCAL_W, netvar.flChargedDamage);
float bdmg = 50; float bdmg = CarryingHeatmaker() ? 40 : 50;
// Darwins damage correction, protects against 15% of damage // Darwins damage correction, protects against 15% of damage
// if (HasDarwins(target)) // if (HasDarwins(target))
// { // {
@ -1125,20 +1135,20 @@ int BestHitbox(CachedEntity *target)
auto ticks = bt::headPositions[target->m_IDX]; auto ticks = bt::headPositions[target->m_IDX];
for (int i = 0; i < 66; i++) for (int i = 0; i < 66; i++)
{ {
if (!ticks->tickcount) if (!ticks[i].tickcount)
continue; continue;
if (!bt::ValidTick(ticks[i], target)) if (!bt::ValidTick(ticks[i], target))
continue; continue;
if (*backtrackVischeckAll) if (*backtrackVischeckAll)
for (int j = 0; j < 18; j++) for (int j = 0; j < 18; j++)
{ {
if (IsEntityVectorVisible(target, ticks->hitboxes.at(j).center)) if (IsEntityVectorVisible(target, ticks[i].hitboxes[j].center))
{ {
good_tick = { i, target->m_IDX }; good_tick = { i, target->m_IDX };
break; break;
} }
} }
else if (IsEntityVectorVisible(target, ticks->hitboxes.at(0).center)) else if (IsEntityVectorVisible(target, ticks[i].hitboxes[0].center))
{ {
good_tick = { i, target->m_IDX }; good_tick = { i, target->m_IDX };
break; break;
@ -1159,7 +1169,7 @@ int BestHitbox(CachedEntity *target)
{ {
namespace bt = hacks::shared::backtrack; namespace bt = hacks::shared::backtrack;
if (good_tick.first != -1) if (good_tick.first != -1)
if (IsEntityVectorVisible(target, bt::headPositions[target->m_IDX][good_tick.first].hitboxes.at(preferred).center)) if (IsEntityVectorVisible(target, bt::headPositions[target->m_IDX - 1][good_tick.first].hitboxes[preferred].center))
return preferred; return preferred;
} }
else if (target->hitboxes.VisibilityCheck(preferred)) else if (target->hitboxes.VisibilityCheck(preferred))
@ -1191,11 +1201,11 @@ int BestHitbox(CachedEntity *target)
auto ticks = bt::headPositions[target->m_IDX]; auto ticks = bt::headPositions[target->m_IDX];
for (int i = 0; i < 66; i++) for (int i = 0; i < 66; i++)
{ {
if (!ticks->tickcount) if (!ticks[i].tickcount)
continue; continue;
if (!bt::ValidTick(ticks[i], target)) if (!bt::ValidTick(ticks[i], target))
continue; continue;
if (IsEntityVectorVisible(target, ticks->hitboxes.at(hb).center)) if (IsEntityVectorVisible(target, ticks[i].hitboxes[hb].center))
{ {
good_tick = { i, target->m_IDX }; good_tick = { i, target->m_IDX };
break; break;
@ -1216,11 +1226,11 @@ int BestHitbox(CachedEntity *target)
auto ticks = bt::headPositions[target->m_IDX]; auto ticks = bt::headPositions[target->m_IDX];
for (int i = 0; i < 66; i++) for (int i = 0; i < 66; i++)
{ {
if (!ticks->tickcount) if (!ticks[i].tickcount)
continue; continue;
if (!bt::ValidTick(ticks[i], target)) if (!bt::ValidTick(ticks[i], target))
continue; continue;
if (IsEntityVectorVisible(target, ticks->hitboxes.at(hb).center)) if (IsEntityVectorVisible(target, ticks[i].hitboxes[hb].center))
{ {
good_tick = { i, target->m_IDX }; good_tick = { i, target->m_IDX };
break; break;

View File

@ -18,6 +18,8 @@ float used_yaw = 0.0f;
static settings::Boolean enable{ "antiaim.enable", "0" }; static settings::Boolean enable{ "antiaim.enable", "0" };
static settings::Float yaw{ "antiaim.yaw.static", "0" }; static settings::Float yaw{ "antiaim.yaw.static", "0" };
static settings::Int yaw_mode{ "antiaim.yaw.mode", "0" }; static settings::Int yaw_mode{ "antiaim.yaw.mode", "0" };
static settings::Int yaw_sideways_min{ "antiaim.yaw.sideways.min", "0" };
static settings::Int yaw_sideways_max{ "antiaim.yaw.sideways.max", "4" };
static settings::Float pitch{ "antiaim.pitch.static", "0" }; static settings::Float pitch{ "antiaim.pitch.static", "0" };
static settings::Int pitch_mode{ "antiaim.pitch.mode", "0" }; static settings::Int pitch_mode{ "antiaim.pitch.mode", "0" };
@ -369,6 +371,14 @@ void ProcessUserCmd(CUserCmd *cmd)
static bool bsendflip = true; static bool bsendflip = true;
static float rngyaw = 0.0f; static float rngyaw = 0.0f;
bool clamp = !no_clamping; bool clamp = !no_clamping;
static int ticksUntilSwap = 0;
static bool swap = true;
if (ticksUntilSwap > 0 && *yaw_mode != 18) {
swap = true;
ticksUntilSwap = 0;
}
switch ((int) yaw_mode) switch ((int) yaw_mode)
{ {
case 1: // FIXED case 1: // FIXED
@ -481,8 +491,14 @@ void ProcessUserCmd(CUserCmd *cmd)
clamp = false; clamp = false;
} }
break; break;
case 20:
case 18: // Fake sideways case 18: // Fake sideways
if (*bSendPackets && ticksUntilSwap--) {
ticksUntilSwap = UniformRandomInt(*yaw_sideways_min, *yaw_sideways_max);
swap = !swap;
}
y += *bSendPackets ^ swap ? 90.0f : -90.0f;
break;
case 20: // Fake right
y += *bSendPackets ? 90.0f : -90.0f; y += *bSendPackets ? 90.0f : -90.0f;
break; break;
case 19: // Fake left case 19: // Fake left

View File

@ -611,39 +611,8 @@ void CreateMove()
current_user_cmd->buttons |= IN_ATTACK2; current_user_cmd->buttons |= IN_ATTACK2;
} }
} }
if (!steamid && !enable) if ((!steamid && !enable) || GetWeaponMode() != weapon_medigun)
return; return;
if (GetWeaponMode() != weapon_medigun)
return;
/*if (force_healing_target)
{
CachedEntity *target = ENTITY(force_healing_target);
if (CE_GOOD(target))
{
if (target->player_info.friendsID != steamid || !CanHeal(force_healing_target))
force_healing_target = 0;
else
{
}
}
else
force_healing_target = 0;
}
else if (steamid)
{
for (int i = 1; i <= g_IEngine->GetMaxClients(); i++)
{
CachedEntity *ent = ENTITY(i);
if (CE_BAD(ent) || !ent->player_info.friendsID)
continue;
if (ent->player_info.friendsID == steamid && CanHeal(i))
{
force_healing_target = steamid;
break;
}
}
}*/
bool healing_steamid = false; bool healing_steamid = false;
if (steamid) if (steamid)
{ {

View File

@ -24,6 +24,7 @@ static settings::Int slots{ "backtrack.slots", "0" };
settings::Boolean enable{ "backtrack.enable", "false" }; settings::Boolean enable{ "backtrack.enable", "false" };
settings::Boolean backtrack_chams_glow{ "backtrack.chams_glow", "true" }; settings::Boolean backtrack_chams_glow{ "backtrack.chams_glow", "true" };
settings::Int latency{ "backtrack.latency", "0" }; settings::Int latency{ "backtrack.latency", "0" };
settings::Boolean enable_latency_rampup{ "backtrack.latency.rampup", "true" };
void EmptyBacktrackData(BacktrackData &i); void EmptyBacktrackData(BacktrackData &i);
std::pair<int, int> getBestEntBestTick(); std::pair<int, int> getBestEntBestTick();
@ -51,19 +52,14 @@ void UpdateIncomingSequences()
sequences.pop_back(); sequences.pop_back();
} }
} }
void AddLatencyToNetchan(INetChannel *ch) void AddLatencyToNetchan(INetChannel *ch)
{ {
if (!isBacktrackEnabled) if (!isBacktrackEnabled)
return; return;
float Latency = *latency;
if (Latency > 1000.0f)
Latency = 800.0f;
Latency -= getRealLatency();
if (Latency < 0.0f)
Latency = 0.0f;
for (auto &seq : sequences) for (auto &seq : sequences)
{ {
if (g_GlobalVars->realtime - seq.curtime > Latency / 1000.0f) if (g_GlobalVars->realtime - seq.curtime > getLatency() / 1000.0f)
{ {
ch->m_nInReliableState = seq.inreliablestate; ch->m_nInReliableState = seq.inreliablestate;
ch->m_nInSequenceNr = seq.sequencenr; ch->m_nInSequenceNr = seq.sequencenr;
@ -84,13 +80,21 @@ int BestTick = -1;
int iBestTarget = -1; int iBestTarget = -1;
bool istickvalid[33][66]{}; bool istickvalid[33][66]{};
bool istickinvalid[33][66]{}; bool istickinvalid[33][66]{};
static float latency_rampup = 0.0f;
static void Run() static void Run()
{ {
if (!shouldBacktrack()) if (!shouldBacktrack())
{ {
isBacktrackEnabled = false; isBacktrackEnabled = false;
latency_rampup = 0;
return; return;
} }
// Limit to 2 ticks
latency_rampup += 1.0f / 66.0f;
latency_rampup = std::min(latency_rampup, 1.0f);
UpdateIncomingSequences(); UpdateIncomingSequences();
isBacktrackEnabled = true; isBacktrackEnabled = true;
@ -341,11 +345,11 @@ float getLatency()
if (!ch) if (!ch)
return 0; return 0;
float Latency = *latency; float Latency = *latency;
if (Latency > 1000.0f) Latency = std::min(Latency, 800.0f);
Latency = 800.0f;
Latency -= getRealLatency(); Latency -= getRealLatency();
if (Latency < 0.0f) Latency = std::max(Latency, 0.0f);
Latency = 0.0f; if (enable_latency_rampup)
Latency = Latency * latency_rampup;
return Latency; return Latency;
} }

View File

@ -164,7 +164,7 @@ IClientEntity *GetActiveTFWeapon_detour(IClientEntity *this_ /* C_TFPlayer * */)
QAngle angle = *(QAngle *) &NET_VECTOR(this_, netvar.angEyeAngles); QAngle angle = *(QAngle *) &NET_VECTOR(this_, netvar.angEyeAngles);
if (isLocal) if (isLocal)
{ {
g_IEngine->GetViewAngles(angle); angle = VectorToQAngle(current_user_cmd->viewangles);
eyePos = g_pLocalPlayer->v_Eye; eyePos = g_pLocalPlayer->v_Eye;
} }
Vector forward; Vector forward;

View File

@ -198,7 +198,7 @@ static bool isValidNearPosition(Vector vec, Vector target, const bot_class_confi
float dist = vec.DistTo(target); float dist = vec.DistTo(target);
if (dist < config.min || dist > config.max) if (dist < config.min || dist > config.max)
return false; return false;
if (!IsVectorVisible(vec, target, true)) if (!IsVectorVisible(vec, target, true, LOCAL_E, MASK_PLAYERSOLID))
return false; return false;
return true; return true;
} }

View File

@ -341,13 +341,12 @@ void createMove()
{ {
if (current_index >= source->size()) if (current_index >= source->size())
current_index = 0; current_index = 0;
if (random_order && source->size()) if (random_order && source->size() > 1)
{ {
current_index = rand() % source->size(); current_index = UniformRandomInt(0, source->size() - 1);
int tries = 0; while (current_index == last_index)
while (current_index == last_index && tries++ < 1000)
{ {
current_index = rand() % source->size(); current_index = UniformRandomInt(0, source->size() - 1);
} }
} }
last_index = current_index; last_index = current_index;

View File

@ -1177,7 +1177,7 @@ netvar.iHealth));
return buf; return buf;
}*/ }*/
bool IsVectorVisible(Vector origin, Vector target, bool enviroment_only, CachedEntity *self) bool IsVectorVisible(Vector origin, Vector target, bool enviroment_only, CachedEntity *self, unsigned int mask)
{ {
if (!enviroment_only) if (!enviroment_only)
@ -1188,7 +1188,7 @@ bool IsVectorVisible(Vector origin, Vector target, bool enviroment_only, CachedE
trace::filter_no_player.SetSelf(RAW_ENT(self)); trace::filter_no_player.SetSelf(RAW_ENT(self));
ray.Init(origin, target); ray.Init(origin, target);
PROF_SECTION(IEVV_TraceRay); PROF_SECTION(IEVV_TraceRay);
g_ITrace->TraceRay(ray, MASK_SHOT_HULL, &trace::filter_no_player, &trace_visible); g_ITrace->TraceRay(ray, mask, &trace::filter_no_player, &trace_visible);
return (trace_visible.fraction == 1.0f); return (trace_visible.fraction == 1.0f);
} }
else else
@ -1199,7 +1199,7 @@ bool IsVectorVisible(Vector origin, Vector target, bool enviroment_only, CachedE
trace::filter_no_entity.SetSelf(RAW_ENT(self)); trace::filter_no_entity.SetSelf(RAW_ENT(self));
ray.Init(origin, target); ray.Init(origin, target);
PROF_SECTION(IEVV_TraceRay); PROF_SECTION(IEVV_TraceRay);
g_ITrace->TraceRay(ray, MASK_SHOT_HULL, &trace::filter_no_entity, &trace_visible); g_ITrace->TraceRay(ray, mask, &trace::filter_no_entity, &trace_visible);
return (trace_visible.fraction == 1.0f); return (trace_visible.fraction == 1.0f);
} }
} }

View File

@ -10,23 +10,17 @@ namespace hooked_methods
{ {
DEFINE_HOOKED_METHOD(SendDatagram, int, INetChannel *ch, bf_write *buf) DEFINE_HOOKED_METHOD(SendDatagram, int, INetChannel *ch, bf_write *buf)
{ {
if (!round(*hacks::shared::backtrack::latency) || !isHackActive()) if (!isHackActive() || !ch || CE_BAD(LOCAL_E) || !round(*hacks::shared::backtrack::latency))
return original::SendDatagram(ch, buf); return original::SendDatagram(ch, buf);
int in = 0;
int state = 0; int in = ch->m_nInSequenceNr;
if (CE_GOOD(LOCAL_E) && ch) int state = ch->m_nInReliableState;
{
in = ch->m_nInSequenceNr;
state = ch->m_nInReliableState;
hacks::shared::backtrack::AddLatencyToNetchan(ch); hacks::shared::backtrack::AddLatencyToNetchan(ch);
}
int ret = original::SendDatagram(ch, buf); int ret = original::SendDatagram(ch, buf);
if (CE_GOOD(LOCAL_E) && ch)
{
ch->m_nInSequenceNr = in; ch->m_nInSequenceNr = in;
ch->m_nInReliableState = state; ch->m_nInReliableState = state;
}
return ret; return ret;
} }
} // namespace hooked_methods } // namespace hooked_methods

View File

@ -231,6 +231,9 @@ void UpdateTemporaryData()
void StoreClientData() void StoreClientData()
{ {
if (!peer)
return;
UpdateServerAddress(); UpdateServerAddress();
user_data_s &data = peer->memory->peer_user_data[peer->client_id]; user_data_s &data = peer->memory->peer_user_data[peer->client_id];
data.friendid = g_ISteamUser->GetSteamID().GetAccountID(); data.friendid = g_ISteamUser->GetSteamID().GetAccountID();

View File

@ -15,11 +15,14 @@ namespace nav
static settings::Boolean enabled{ "misc.pathing", "true" }; static settings::Boolean enabled{ "misc.pathing", "true" };
// Whether or not to run vischecks at pathtime // Whether or not to run vischecks at pathtime
static settings::Boolean vischecks{ "misc.pathing.pathtime-vischecks", "true" }; static settings::Boolean vischecks{ "misc.pathing.pathtime-vischecks", "true" };
static settings::Boolean vischeckBlock{ "misc.pathing.pathtime-vischeck-block", "false" };
static settings::Boolean draw{ "misc.pathing.draw", "false" }; static settings::Boolean draw{ "misc.pathing.draw", "false" };
static settings::Boolean look{ "misc.pathing.look-at-path", "false" }; static settings::Boolean look{ "misc.pathing.look-at-path", "false" };
static settings::Int stuck_time{ "misc.pathing.stuck-time", "4000" }; static settings::Int stuck_time{ "misc.pathing.stuck-time", "4000" };
static settings::Int unreachable_time{ "misc.pathing.unreachable-time", "1000" };
static std::vector<Vector> crumbs; static std::vector<CNavArea*> crumbs;
static Vector startPoint, endPoint;
enum ignore_status : uint8_t enum ignore_status : uint8_t
{ {
@ -48,72 +51,57 @@ struct ignoredata
Timer ignoreTimeout{}; Timer ignoreTimeout{};
}; };
CNavArea *getNavArea(Vector &vec) Vector GetClosestCornerToArea(CNavArea *CornerOf, const Vector &target)
{ {
for (auto &i : navfile->m_areas) std::array<Vector, 4> corners{
CornerOf->m_nwCorner, // NW
CornerOf->m_seCorner, // SE
{ CornerOf->m_seCorner.x, CornerOf->m_nwCorner.y, CornerOf->m_nwCorner.z },// NE
{ CornerOf->m_nwCorner.x, CornerOf->m_seCorner.y, CornerOf->m_seCorner.z } // SW
};
Vector *bestVec = &corners[0], *bestVec2 = bestVec;
float bestDist = corners[0].DistTo(target), bestDist2 = bestDist;
for (size_t i = 1; i < corners.size(); i++)
{ {
if (vec == i.m_center) float dist = corners[i].DistTo(target);
return &i;
}
return nullptr;
}
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) if (dist < bestDist)
{ {
bestVec = corners.at(i); bestVec = &corners[i];
bestDist = dist; bestDist = dist;
} }
} if (corners[i] == *bestVec2)
Vector bestVec2{};
float bestDist2 = FLT_MAX;
for (size_t i = 0; i < corners.size(); i++)
{
if (corners.at(i) == bestVec2)
continue; continue;
float dist = corners.at(i).DistTo(Target->m_center);
if (dist < bestDist2) if (dist < bestDist2)
{ {
bestVec2 = corners.at(i); bestVec2 = &corners[i];
bestDist2 = dist; bestDist2 = dist;
} }
} }
return (bestVec + bestVec2) / 2; return (*bestVec + *bestVec2) / 2;
} }
float getZBetweenAreas(CNavArea *start, CNavArea *end) float getZBetweenAreas(CNavArea *start, CNavArea *end)
{ {
float z1 = GetClosestCornerToArea(start, end).z; float z1 = GetClosestCornerToArea(start, end->m_center).z;
float z2 = GetClosestCornerToArea(end, start).z; float z2 = GetClosestCornerToArea(end, start->m_center).z;
return z2 - z1; return z2 - z1;
} }
class ignoremanager
static std::unordered_map<std::pair<CNavArea *, CNavArea *>, ignoredata, boost::hash<std::pair<CNavArea *, CNavArea *>>> ignores;
namespace ignoremanager
{ {
static std::unordered_map<std::pair<CNavArea *, CNavArea *>, ignoredata, boost::hash<std::pair<CNavArea *, CNavArea *>>> ignores;
static bool vischeck(CNavArea *begin, CNavArea *end) static bool vischeck(CNavArea *begin, CNavArea *end)
{ {
Vector first = begin->m_center; Vector first = begin->m_center;
Vector second = end->m_center; Vector second = end->m_center;
first.z += 42; first.z += 42;
second.z += 42; second.z += 42;
return IsVectorVisible(first, second, true); return IsVectorVisible(first, second, true, LOCAL_E, MASK_PLAYERSOLID);
} }
static ignore_status runIgnoreChecks(CNavArea *begin, CNavArea *end) static ignore_status runIgnoreChecks(CNavArea *begin, CNavArea *end)
{ {
@ -197,8 +185,8 @@ class ignoremanager
// Vischecks // Vischecks
for (size_t i = 0; i < crumbs.size() - 1; i++) for (size_t i = 0; i < crumbs.size() - 1; i++)
{ {
CNavArea *begin = getNavArea(crumbs.at(i)); CNavArea *begin = crumbs[i];
CNavArea *end = getNavArea(crumbs.at(i + 1)); CNavArea *end = crumbs[i + 1];
if (!begin || !end) if (!begin || !end)
continue; continue;
ignoredata &data = ignores[{ begin, end }]; ignoredata &data = ignores[{ begin, end }];
@ -218,14 +206,12 @@ class ignoremanager
if (perform_repath) if (perform_repath)
repath(); repath();
} }
public:
// 0 = Not ignored, 1 = low priority, 2 = ignored // 0 = Not ignored, 1 = low priority, 2 = ignored
static int isIgnored(CNavArea *begin, CNavArea *end) static int isIgnored(CNavArea *begin, CNavArea *end)
{ {
if (ignores[{ end, nullptr }].status == danger_found) if (ignores[{ end, nullptr }].status == danger_found)
return 2; return 2;
ignore_status &status = ignores[{ begin, end }].status; ignore_status status = ignores[{ begin, end }].status;
if (status == unknown) if (status == unknown)
status = runIgnoreChecks(begin, end); status = runIgnoreChecks(begin, end);
if (status == vischeck_success) if (status == vischeck_success)
@ -235,8 +221,27 @@ public:
else else
return 2; return 2;
} }
static bool addTime(ignoredata &connection, ignore_status status)
{
connection.status = status;
connection.ignoreTimeout.update();
return true;
}
static bool addTime(CNavArea *begin, CNavArea *end, ignore_status status)
{
logging::Info("Ignored Connection %i-%i", begin->m_id, end->m_id);
return addTime(ignores[{ begin, end }], status);
}
static bool addTime(CNavArea *begin, CNavArea *end, Timer &time) static bool addTime(CNavArea *begin, CNavArea *end, Timer &time)
{ {
if (!begin || !end)
{
// We can't reach the destination vector. Destination vector might
// be out of bounds/reach.
clearInstructions();
return true;
}
using namespace std::chrono; using namespace std::chrono;
// Check if connection is already known // Check if connection is already known
if (ignores.find({ begin, end }) == ignores.end()) if (ignores.find({ begin, end }) == ignores.end())
@ -247,27 +252,11 @@ public:
connection.stucktime += duration_cast<milliseconds>(system_clock::now() - time.last).count(); connection.stucktime += duration_cast<milliseconds>(system_clock::now() - time.last).count();
if (connection.stucktime >= *stuck_time) if (connection.stucktime >= *stuck_time)
{ {
connection.status = explicit_ignored;
connection.ignoreTimeout.update();
logging::Info("Ignored Connection %i-%i", begin->m_id, end->m_id); logging::Info("Ignored Connection %i-%i", begin->m_id, end->m_id);
return true; return addTime(connection, explicit_ignored);
} }
return false; return false;
} }
static bool 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 true;
}
return addTime(begin_area, end_area, time);
}
static void reset() static void reset()
{ {
ignores.clear(); ignores.clear();
@ -329,21 +318,16 @@ public:
{ {
return !(ignores[{ area, nullptr }].status == danger_found); 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 struct Graph : public micropather::Graph
{ {
std::unique_ptr<micropather::MicroPather> pather; std::unique_ptr<micropather::MicroPather> pather;
Graph() Graph() {
{
pather = std::make_unique<micropather::MicroPather>(this, 3000, 6, true); pather = std::make_unique<micropather::MicroPather>(this, 3000, 6, true);
} }
~Graph() override ~Graph() override {}
{
}
void AdjacentCost(void *state, MP_VECTOR<micropather::StateCost> *adjacent) override void AdjacentCost(void *state, MP_VECTOR<micropather::StateCost> *adjacent) override
{ {
CNavArea *center = static_cast<CNavArea *>(state); CNavArea *center = static_cast<CNavArea *>(state);
@ -354,22 +338,21 @@ struct Graph : public micropather::Graph
if (isIgnored == 2) if (isIgnored == 2)
continue; continue;
float distance = center->m_center.DistTo(i.area->m_center); float distance = center->m_center.DistTo(i.area->m_center);
if (isIgnored == 1) if (isIgnored == 1) {
if (*vischeckBlock)
continue;
distance += 50000; distance += 50000;
micropather::StateCost cost{ static_cast<void *>(neighbour), distance }; }
adjacent->push_back(cost); adjacent->emplace_back(micropather::StateCost{ reinterpret_cast<void *>(neighbour), distance });
} }
} }
float LeastCostEstimate(void *stateStart, void *stateEnd) override float LeastCostEstimate(void *stateStart, void *stateEnd) override
{ {
CNavArea *start = static_cast<CNavArea *>(stateStart); CNavArea *start = reinterpret_cast<CNavArea *>(stateStart);
CNavArea *end = static_cast<CNavArea *>(stateEnd); CNavArea *end = reinterpret_cast<CNavArea *>(stateEnd);
return start->m_center.DistTo(end->m_center); return start->m_center.DistTo(end->m_center);
} }
void PrintStateInfo(void *) override void PrintStateInfo(void *) override {}
{
// Uhh no
}
}; };
// Navfile containing areas // Navfile containing areas
@ -414,6 +397,7 @@ void initThread()
void init() void init()
{ {
endPoint.Invalidate();
ignoremanager::reset(); ignoremanager::reset();
status = initing; status = initing;
std::thread thread; std::thread thread;
@ -437,123 +421,100 @@ bool prepare()
// This prevents the bot from gettings completely stuck in some cases // This prevents the bot from gettings completely stuck in some cases
static std::vector<CNavArea *> findClosestNavSquare_localAreas(6); static std::vector<CNavArea *> findClosestNavSquare_localAreas(6);
// Function for getting closest Area to player, aka "LocalNav" // Function for getting closest Area to player, aka "LocalNav"
CNavArea *findClosestNavSquare(Vector vec) CNavArea *findClosestNavSquare(const Vector &vec)
{ {
if (findClosestNavSquare_localAreas.size() > 5) bool isLocal = vec == g_pLocalPlayer->v_Origin;
if (isLocal && findClosestNavSquare_localAreas.size() > 5)
findClosestNavSquare_localAreas.erase(findClosestNavSquare_localAreas.begin()); findClosestNavSquare_localAreas.erase(findClosestNavSquare_localAreas.begin());
bool is_local = vec == g_pLocalPlayer->v_Origin; float ovBestDist = FLT_MAX, bestDist = FLT_MAX;
// If multiple candidates for LocalNav have been found, pick the closest
auto &areas = navfile->m_areas; CNavArea *ovBestSquare = nullptr, *bestSquare = nullptr;
std::vector<CNavArea *> overlapping; for (auto &i : navfile->m_areas)
for (auto &i : areas)
{
// Check if we are within x and y bounds of an area
if (i.IsOverlapping(vec))
{ {
// Make sure we're not stuck on the same area for too long // Make sure we're not stuck on the same area for too long
if (std::count(findClosestNavSquare_localAreas.begin(), findClosestNavSquare_localAreas.end(), &i) < 3) if (isLocal && std::count(findClosestNavSquare_localAreas.begin(),
findClosestNavSquare_localAreas.end(), &i) >= 3)
{ {
if (IsVectorVisible(vec, i.m_center, true)) continue;
overlapping.push_back(&i);
} }
}
}
// If multiple candidates for LocalNav have been found, pick the closest
float bestDist = FLT_MAX;
CNavArea *bestSquare = nullptr;
for (auto &i : overlapping)
{
float dist = i->m_center.DistTo(vec);
if (dist < bestDist)
{
bestDist = dist;
bestSquare = i;
}
}
if (bestSquare != nullptr)
{
if (is_local)
findClosestNavSquare_localAreas.push_back(bestSquare);
return bestSquare;
}
// If no LocalNav was found, pick the closest available Area
bestDist = FLT_MAX;
for (auto &i : areas)
{
float dist = i.m_center.DistTo(vec); float dist = i.m_center.DistTo(vec);
if (dist < bestDist) if (dist < bestDist)
{
if (std::count(findClosestNavSquare_localAreas.begin(), findClosestNavSquare_localAreas.end(), &i) < 3)
{ {
bestDist = dist; bestDist = dist;
bestSquare = &i; bestSquare = &i;
} }
// Check if we are within x and y bounds of an area
if (ovBestDist >= dist || !i.IsOverlapping(vec) ||
!IsVectorVisible(vec, i.m_center, true, LOCAL_E, MASK_PLAYERSOLID))
{
continue;
} }
ovBestDist = dist;
ovBestSquare = &i;
} }
if (is_local) if (!ovBestSquare)
findClosestNavSquare_localAreas.push_back(bestSquare); ovBestSquare = bestSquare;
return bestSquare;
if (isLocal)
findClosestNavSquare_localAreas.push_back(ovBestSquare);
return ovBestSquare;
} }
std::vector<Vector> findPath(Vector start, Vector end) std::vector<CNavArea*> findPath(const Vector &start, const Vector &end)
{ {
using namespace std::chrono;
if (status != on) if (status != on)
return {}; return {};
CNavArea *local = findClosestNavSquare(start);
CNavArea *dest = findClosestNavSquare(end);
if (!local || !dest) CNavArea *local, *dest;
if (!(local = findClosestNavSquare(start)) || !(dest = findClosestNavSquare(end)))
return {}; return {};
micropather::MPVector<void *> pathNodes;
logging::Info("Start: (%f,%f,%f)", local->m_center.x, local->m_center.y, local->m_center.z);
logging::Info("End: (%f,%f,%f)", dest->m_center.x, dest->m_center.y, dest->m_center.z);
float cost; float cost;
std::chrono::time_point begin_pathing = std::chrono::high_resolution_clock::now(); std::vector<CNavArea*> pathNodes;
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(); time_point begin_pathing = high_resolution_clock::now();
int result = Map.pather->Solve(reinterpret_cast<void *>(local),
reinterpret_cast<void*>(dest),
reinterpret_cast<std::vector<void*>*>(&pathNodes), &cost);
long long timetaken = duration_cast<nanoseconds>(high_resolution_clock::now() - begin_pathing).count();
logging::Info("Pathing: Pather result: %i. Time taken (NS): %lld", result, timetaken); logging::Info("Pathing: Pather result: %i. Time taken (NS): %lld", result, timetaken);
// If no result found, return empty Vector // If no result found, return empty Vector
if (result == micropather::MicroPather::NO_SOLUTION) if (result == micropather::MicroPather::NO_SOLUTION)
return std::vector<Vector>(0); return {};
// Convert (void *) CNavArea * to Vector
std::vector<Vector> path; return pathNodes;
for (size_t i = 0; i < pathNodes.size(); i++)
{
path.push_back(static_cast<CNavArea *>(pathNodes[i])->m_center);
}
// Add our destination to the std::vector
path.push_back(end);
return path;
} }
static Vector loc(0.0f, 0.0f, 0.0f); static Vector loc(0.0f, 0.0f, 0.0f);
static Vector last_area(0.0f, 0.0f, 0.0f); static CNavArea *last_area = nullptr;
bool ReadyForCommands = true; bool ReadyForCommands = true;
static Timer inactivity{}; static Timer inactivity{};
int curr_priority = 0; int curr_priority = 0;
static bool ensureArrival = false; static bool ensureArrival = false;
bool navTo(Vector destination, int priority, bool should_repath, bool nav_to_local, bool is_repath) bool navTo(const Vector &destination, int priority, bool should_repath, bool nav_to_local, bool is_repath)
{ {
if (!prepare()) if (!prepare() || priority < curr_priority)
return false; return false;
if (priority < curr_priority)
return false; auto path = findPath(g_pLocalPlayer->v_Origin, destination);
std::vector<Vector> path = findPath(g_pLocalPlayer->v_Origin, destination);
if (path.empty()) if (path.empty())
{ {
crumbs.clear(); clearInstructions();
return false; return false;
} }
auto crumb = crumbs.begin(); auto crumb = crumbs.begin();
if (crumb != crumbs.end()) if (crumb != crumbs.end() && ignoremanager::addTime(last_area, *crumb, inactivity))
{
if (ignoremanager::addTime(last_area, *crumb, inactivity))
ResetPather(); ResetPather();
}
auto path_it = path.begin(); auto path_it = path.begin();
last_area = *path_it; last_area = *path_it;
if (!nav_to_local) if (!nav_to_local)
@ -564,25 +525,32 @@ bool navTo(Vector destination, int priority, bool should_repath, bool nav_to_loc
} }
inactivity.update(); inactivity.update();
if (!is_repath) if (!is_repath)
{
findClosestNavSquare_localAreas.clear(); findClosestNavSquare_localAreas.clear();
}
ensureArrival = should_repath; ensureArrival = should_repath;
ReadyForCommands = false; ReadyForCommands = false;
curr_priority = priority; curr_priority = priority;
crumbs = std::move(path); crumbs = std::move(path);
endPoint = destination;
return true; return true;
} }
void repath() void repath()
{ {
if (ensureArrival) if (!ensureArrival)
{ return;
Vector last = crumbs.back();
crumbs.clear(); Vector last;
if (!crumbs.empty())
last = crumbs.back()->m_center;
else if (endPoint.IsValid())
last = endPoint;
else
return;
clearInstructions();
ResetPather(); ResetPather();
navTo(last, curr_priority, true, true, true); navTo(last, curr_priority, true, true, true);
}
} }
static Timer last_jump{}; static Timer last_jump{};
@ -596,51 +564,82 @@ static void cm()
if (!LOCAL_E->m_bAlivePlayer()) if (!LOCAL_E->m_bAlivePlayer())
{ {
// Clear path if player dead // Clear path if player dead
crumbs.clear(); clearInstructions();
return; return;
} }
ignoremanager::updateIgnores(); ignoremanager::updateIgnores();
auto crumb = crumbs.begin(); auto crumb = crumbs.begin();
const Vector *crumb_vec;
// Crumbs empty, prepare for next instruction // Crumbs empty, prepare for next instruction
if (crumb == crumbs.end()) if (crumb == crumbs.end())
{
if (endPoint.IsValid())
crumb_vec = &endPoint;
else
{ {
curr_priority = 0; curr_priority = 0;
ReadyForCommands = true; ReadyForCommands = true;
ensureArrival = false; ensureArrival = false;
return; return;
} }
}
else
crumb_vec = &(*crumb)->m_center;
ReadyForCommands = false; ReadyForCommands = false;
// Remove old crumbs // Remove old crumbs
if (g_pLocalPlayer->v_Origin.DistTo(Vector{ crumb->x, crumb->y, crumb->z }) < 50.0f) if (g_pLocalPlayer->v_Origin.DistTo(*crumb_vec) < 50.0f)
{ {
inactivity.update();
if (crumb_vec == &endPoint)
{
endPoint.Invalidate();
return;
}
last_area = *crumb; last_area = *crumb;
crumbs.erase(crumb); crumbs.erase(crumb);
inactivity.update();
crumb = crumbs.begin(); crumb = crumbs.begin();
if (crumb == crumbs.end()) if (crumb == crumbs.end())
{
if (!endPoint.IsValid())
{
logging::Info("navparser.cpp cm -> endPoint.IsValid() == false");
return; return;
} }
crumb_vec = &endPoint;
}
}
if (look && LookAtPathTimer.check(1000)) if (look && LookAtPathTimer.check(1000))
{ {
Vector next = *crumb; Vector next{crumb_vec->x, crumb_vec->y, g_pLocalPlayer->v_Eye.z};
next.z = g_pLocalPlayer->v_Eye.z; next = GetAimAtAngles(g_pLocalPlayer->v_Eye, next);
Vector angle = GetAimAtAngles(g_pLocalPlayer->v_Eye, next); DoSlowAim(next);
DoSlowAim(angle); current_user_cmd->viewangles = next;
current_user_cmd->viewangles = angle;
} }
// Detect when jumping is necessary // Detect when jumping is necessary
if ((!(g_pLocalPlayer->holding_sniper_rifle && g_pLocalPlayer->bZoomed) && crumb->z - g_pLocalPlayer->v_Origin.z > 18 && last_jump.test_and_set(200)) || (last_jump.test_and_set(200) && inactivity.check(3000))) if ((!(g_pLocalPlayer->holding_sniper_rifle && g_pLocalPlayer->bZoomed) &&
current_user_cmd->buttons |= IN_JUMP | IN_DUCK; crumb_vec->z - g_pLocalPlayer->v_Origin.z > 18 && last_jump.test_and_set(200)) ||
// If inactive for too long (last_jump.test_and_set(200) && inactivity.check(*stuck_time / 2)))
if (inactivity.check(*stuck_time))
{ {
// Ignore connection current_user_cmd->buttons |= IN_JUMP;
}
// Walk to next crumb
WalkTo(*crumb_vec);
/* If can't go through for some time (doors aren't instantly opening)
* ignore that connection
* Or if inactive for too long
*/
if (inactivity.check(*stuck_time) || (inactivity.check(*unreachable_time) &&
!IsVectorVisible(g_pLocalPlayer->v_Origin, *crumb_vec + Vector(.0f, .0f, 41.5f),
false, LOCAL_E, MASK_PLAYERSOLID)))
{
/* crumb is invalid if endPoint is used */
if (crumb_vec != &endPoint)
ignoremanager::addTime(last_area, *crumb, inactivity); ignoremanager::addTime(last_area, *crumb, inactivity);
repath(); repath();
return; return;
} }
// Walk to next crumb
WalkTo(*crumb);
} }
#if ENABLE_VISUALS #if ENABLE_VISUALS
@ -654,16 +653,25 @@ static void drawcrumbs()
return; return;
if (crumbs.size() < 2) if (crumbs.size() < 2)
return; return;
for (size_t i = 0; i < crumbs.size() - 1; i++) for (size_t i = 0; i < crumbs.size(); i++)
{ {
Vector wts1, wts2; Vector wts1, wts2, *o1, *o2;
if (draw::WorldToScreen(crumbs[i], wts1) && draw::WorldToScreen(crumbs[i + 1], wts2)) if (crumbs.size() - 1 == i) {
if (!endPoint.IsValid())
break;
o2 = &endPoint;
} else
o2 = &crumbs[i + 1]->m_center;
o1 = &crumbs[i]->m_center;
if (draw::WorldToScreen(*o1, wts1) && draw::WorldToScreen(*o2, wts2))
{ {
draw::Line(wts1.x, wts1.y, wts2.x - wts1.x, wts2.y - wts1.y, colors::white, 0.3f); draw::Line(wts1.x, wts1.y, wts2.x - wts1.x, wts2.y - wts1.y, colors::white, 0.3f);
} }
} }
Vector wts; Vector wts;
if (!draw::WorldToScreen(crumbs[0], wts)) if (!draw::WorldToScreen(crumbs[0]->m_center, wts))
return; return;
draw::Rectangle(wts.x - 4, wts.y - 4, 8, 8, colors::white); draw::Rectangle(wts.x - 4, wts.y - 4, 8, 8, colors::white);
draw::RectangleOutlined(wts.x - 4, wts.y - 4, 7, 7, colors::white, 1.0f); draw::RectangleOutlined(wts.x - 4, wts.y - 4, 7, 7, colors::white, 1.0f);
@ -688,7 +696,7 @@ bool isSafe(CNavArea *area)
} }
static CatCommand nav_find("nav_find", "Debug nav find", []() { static CatCommand nav_find("nav_find", "Debug nav find", []() {
std::vector<Vector> path = findPath(g_pLocalPlayer->v_Origin, loc); auto path = findPath(g_pLocalPlayer->v_Origin, loc);
if (path.empty()) if (path.empty())
{ {
logging::Info("Pathing: No path found"); logging::Info("Pathing: No path found");
@ -697,7 +705,7 @@ static CatCommand nav_find("nav_find", "Debug nav find", []() {
std::string output = "Pathing: Path found! Path: "; std::string output = "Pathing: Path found! Path: ";
for (int i = 0; i < path.size(); i++) for (int i = 0; i < path.size(); i++)
{ {
output.append(format(path.at(i).x, ",", format(path.at(i).y), " ")); output.append(format(path[i]->m_center.x, ",", format(path[i]->m_center.y), " "));
} }
logging::Info(output.c_str()); logging::Info(output.c_str());
}); });
@ -775,6 +783,7 @@ void DoSlowAim(Vector &input_angle)
void clearInstructions() void clearInstructions()
{ {
crumbs.clear(); crumbs.clear();
endPoint.Invalidate();
curr_priority = 0; curr_priority = 0;
} }
static CatCommand nav_stop("nav_cancel", "Cancel Navigation", []() { clearInstructions(); }); static CatCommand nav_stop("nav_cancel", "Cancel Navigation", []() { clearInstructions(); });

View File

@ -13,7 +13,7 @@ TextFile::TextFile() : lines{}
{ {
} }
bool TextFile::TryLoad(std::string name) bool TextFile::TryLoad(const std::string &name)
{ {
if (name.length() == 0) if (name.length() == 0)
return false; return false;
@ -30,12 +30,15 @@ bool TextFile::TryLoad(std::string name)
line.erase(line.length() - 1, 1); line.erase(line.length() - 1, 1);
lines.push_back(line); lines.push_back(line);
} }
if (lines.size() > 0 && *lines.rbegin() == "\n")
lines.pop_back();
return true; return true;
} }
void TextFile::Load(std::string name) void TextFile::Load(const std::string &name)
{ {
std::string filename = format(DATA_PATH "/", name); std::string filename = DATA_PATH "/" + name;
std::ifstream file(filename, std::ios::in); std::ifstream file(filename, std::ios::in);
if (file.bad()) if (file.bad())
{ {

View File

@ -140,6 +140,9 @@ bool trace::FilterNoEntity::ShouldHitEntity(IHandleEntity *handle, int mask)
// Hit doors, carts, etc // Hit doors, carts, etc
switch (clazz->m_ClassID) switch (clazz->m_ClassID)
{ {
case CL_CLASS(CWorld):
case CL_CLASS(CPhysicsProp):
case CL_CLASS(CDynamicProp):
case CL_CLASS(CBaseDoor): case CL_CLASS(CBaseDoor):
case CL_CLASS(CBaseEntity): case CL_CLASS(CBaseEntity):
return true; return true;