Merge pull request #830 from nullworks/totallynotelite
Merge HWGS and other changes
This commit is contained in:
commit
5de55010dc
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -18,7 +18,7 @@
|
||||
url = https://github.com/nullworks/co-library.git
|
||||
[submodule "external/MicroPather"]
|
||||
path = external/MicroPather
|
||||
url = https://github.com/leethomason/MicroPather
|
||||
url = https://github.com/nullworks/MicroPather
|
||||
[submodule "external/TF2_NavFile_Reader"]
|
||||
path = external/TF2_NavFile_Reader
|
||||
url = https://github.com/nullworks/TF2_NavFile_Reader
|
||||
|
@ -46,6 +46,7 @@
|
||||
<Option name="FakeOffset" value="15"/>
|
||||
<Option name="FakeEdge" value="16"/>
|
||||
<Option name="FakeHeck" value="17"/>
|
||||
<Option name="FakeSideways" value="18"/>
|
||||
<Option name="FakeLeft" value="19"/>
|
||||
<Option name="FakeRight" value="20"/>
|
||||
<Option name="FakeREdge" value="21"/>
|
||||
|
2
external/MicroPather
vendored
2
external/MicroPather
vendored
@ -1 +1 @@
|
||||
Subproject commit 33a3b8403f1bc3937c9d364fe6c3977169bee3b5
|
||||
Subproject commit c3960ea5af374f2ed6195eb39f803f2611b882a9
|
@ -32,15 +32,6 @@ struct BacktrackData
|
||||
int index{ 0 };
|
||||
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 AddLatencyToNetchan(INetChannel *);
|
||||
void UpdateIncomingSequences();
|
||||
|
@ -103,7 +103,7 @@ float DistToSqr(CachedEntity *entity);
|
||||
void fClampAngle(Vector &qaAng);
|
||||
// const char* MakeInfoString(IClientEntity* player);
|
||||
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(float distance);
|
||||
bool IsSentryBuster(CachedEntity *ent);
|
||||
|
@ -26,7 +26,9 @@ extern bool ReadyForCommands;
|
||||
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);
|
||||
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
|
||||
bool prepare();
|
||||
// Clear current path
|
||||
|
@ -14,8 +14,8 @@ class TextFile
|
||||
{
|
||||
public:
|
||||
TextFile();
|
||||
void Load(std::string filename);
|
||||
bool TryLoad(std::string filename);
|
||||
void Load(const std::string &filename);
|
||||
bool TryLoad(const std::string &filename);
|
||||
size_t LineCount() const;
|
||||
const std::string &Line(size_t id) const;
|
||||
|
||||
|
@ -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_melee{ "achievement.equip-melee", "0" };
|
||||
static settings::Int equip_pda2{ "achievement.equip-pda2", "0" };
|
||||
static settings::Boolean hat_troll{ "misc.nohatsforyou", "false" };
|
||||
|
||||
bool checkachmngr()
|
||||
{
|
||||
@ -158,7 +159,6 @@ CatCommand unlock("achievement_unlock", "Unlock all achievements", Unlock);
|
||||
static bool accept_notifs;
|
||||
static bool equip_hats;
|
||||
static bool equip;
|
||||
static bool equip_first_half;
|
||||
std::vector<Autoequip_unlock_list> equip_queue;
|
||||
|
||||
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::Schema_Reload();
|
||||
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)
|
||||
{
|
||||
auto invmng = re::CTFInventoryManager::GTFInventoryManager();
|
||||
auto inv = invmng->GTFPlayerInventory();
|
||||
auto item_view = inv->GetFirstItemOfItemDef(id);
|
||||
if (item_view)
|
||||
return invmng->EquipItemInLoadout(clazz, slot, item_view->UUID());
|
||||
{
|
||||
gc_queue.push_front({ clazz, slot, item_view->UUID() });
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -212,6 +222,33 @@ bool equip_hats_fn(std::vector<int> hats, std::pair<int, int> classes)
|
||||
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)
|
||||
{
|
||||
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([]() {
|
||||
// Primary list
|
||||
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_pda2.installChangeCallback([](settings::VariableBase<int> &, int after) { Callback(after, 3); });
|
||||
|
||||
EC::Register(
|
||||
EC::Paint,
|
||||
[]() {
|
||||
// Start accepting
|
||||
if (accept_notifs)
|
||||
EC::Register(EC::CreateMove, CreateMove, "cm_nohatsforyou");
|
||||
EC::Register(EC::Paint, Paint, "achievement_autounlock");
|
||||
hat_troll.installChangeCallback([](settings::VariableBase<bool> &, bool after) {
|
||||
static bool init = false;
|
||||
if (after && !init)
|
||||
{
|
||||
accept_time.update();
|
||||
accept_notifs = false;
|
||||
hacks::shared::misc::generate_schema();
|
||||
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
|
||||
|
@ -21,6 +21,7 @@ static settings::Boolean enable{ "aimbot.enable", "false" };
|
||||
static settings::Button aimkey{ "aimbot.aimkey.button", "<null>" };
|
||||
static settings::Int aimkey_mode{ "aimbot.aimkey.mode", "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 multipoint{ "aimbot.multipoint", "false" };
|
||||
static settings::Int hitbox_mode{ "aimbot.hitbox-mode", "0" };
|
||||
@ -97,6 +98,12 @@ bool IsBacktracking()
|
||||
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
|
||||
int target_eid{ 0 };
|
||||
CachedEntity *target = 0;
|
||||
@ -787,7 +794,7 @@ void Aim(CachedEntity *entity)
|
||||
minz += (maxz - minz) / 6;
|
||||
// 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 };
|
||||
for (int i = 0; i < 14; ++i)
|
||||
for (int i = 0; i < 13; ++i)
|
||||
if (IsVectorVisible(g_pLocalPlayer->v_Eye, positions[i]))
|
||||
{
|
||||
tr = (positions[i] - g_pLocalPlayer->v_Eye);
|
||||
@ -905,7 +912,10 @@ void DoAutoshoot()
|
||||
attack = false;
|
||||
|
||||
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))
|
||||
current_user_cmd->buttons |= IN_ATTACK2;
|
||||
hacks::shared::antiaim::SetSafeSpace(1);
|
||||
@ -1025,7 +1035,7 @@ int BestHitbox(CachedEntity *target)
|
||||
IF_GAME(IsTF())
|
||||
{
|
||||
int ci = g_pLocalPlayer->weapon()->m_iClassID();
|
||||
preferred = hitbox_t::pelvis;
|
||||
preferred = hitbox_t::spine_2;
|
||||
// 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 bdmg = 50;
|
||||
float bdmg = CarryingHeatmaker() ? 40 : 50;
|
||||
// Darwins damage correction, protects against 15% of damage
|
||||
// if (HasDarwins(target))
|
||||
// {
|
||||
@ -1125,20 +1135,20 @@ int BestHitbox(CachedEntity *target)
|
||||
auto ticks = bt::headPositions[target->m_IDX];
|
||||
for (int i = 0; i < 66; i++)
|
||||
{
|
||||
if (!ticks->tickcount)
|
||||
if (!ticks[i].tickcount)
|
||||
continue;
|
||||
if (!bt::ValidTick(ticks[i], target))
|
||||
continue;
|
||||
if (*backtrackVischeckAll)
|
||||
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 };
|
||||
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 };
|
||||
break;
|
||||
@ -1159,7 +1169,7 @@ int BestHitbox(CachedEntity *target)
|
||||
{
|
||||
namespace bt = hacks::shared::backtrack;
|
||||
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;
|
||||
}
|
||||
else if (target->hitboxes.VisibilityCheck(preferred))
|
||||
@ -1191,11 +1201,11 @@ int BestHitbox(CachedEntity *target)
|
||||
auto ticks = bt::headPositions[target->m_IDX];
|
||||
for (int i = 0; i < 66; i++)
|
||||
{
|
||||
if (!ticks->tickcount)
|
||||
if (!ticks[i].tickcount)
|
||||
continue;
|
||||
if (!bt::ValidTick(ticks[i], target))
|
||||
continue;
|
||||
if (IsEntityVectorVisible(target, ticks->hitboxes.at(hb).center))
|
||||
if (IsEntityVectorVisible(target, ticks[i].hitboxes[hb].center))
|
||||
{
|
||||
good_tick = { i, target->m_IDX };
|
||||
break;
|
||||
@ -1216,11 +1226,11 @@ int BestHitbox(CachedEntity *target)
|
||||
auto ticks = bt::headPositions[target->m_IDX];
|
||||
for (int i = 0; i < 66; i++)
|
||||
{
|
||||
if (!ticks->tickcount)
|
||||
if (!ticks[i].tickcount)
|
||||
continue;
|
||||
if (!bt::ValidTick(ticks[i], target))
|
||||
continue;
|
||||
if (IsEntityVectorVisible(target, ticks->hitboxes.at(hb).center))
|
||||
if (IsEntityVectorVisible(target, ticks[i].hitboxes[hb].center))
|
||||
{
|
||||
good_tick = { i, target->m_IDX };
|
||||
break;
|
||||
|
@ -18,6 +18,8 @@ float used_yaw = 0.0f;
|
||||
static settings::Boolean enable{ "antiaim.enable", "0" };
|
||||
static settings::Float yaw{ "antiaim.yaw.static", "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::Int pitch_mode{ "antiaim.pitch.mode", "0" };
|
||||
@ -369,6 +371,14 @@ void ProcessUserCmd(CUserCmd *cmd)
|
||||
static bool bsendflip = true;
|
||||
static float rngyaw = 0.0f;
|
||||
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)
|
||||
{
|
||||
case 1: // FIXED
|
||||
@ -481,8 +491,14 @@ void ProcessUserCmd(CUserCmd *cmd)
|
||||
clamp = false;
|
||||
}
|
||||
break;
|
||||
case 20:
|
||||
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;
|
||||
break;
|
||||
case 19: // Fake left
|
||||
|
@ -611,39 +611,8 @@ void CreateMove()
|
||||
current_user_cmd->buttons |= IN_ATTACK2;
|
||||
}
|
||||
}
|
||||
if (!steamid && !enable)
|
||||
if ((!steamid && !enable) || GetWeaponMode() != weapon_medigun)
|
||||
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;
|
||||
if (steamid)
|
||||
{
|
||||
|
@ -24,6 +24,7 @@ static settings::Int slots{ "backtrack.slots", "0" };
|
||||
settings::Boolean enable{ "backtrack.enable", "false" };
|
||||
settings::Boolean backtrack_chams_glow{ "backtrack.chams_glow", "true" };
|
||||
settings::Int latency{ "backtrack.latency", "0" };
|
||||
settings::Boolean enable_latency_rampup{ "backtrack.latency.rampup", "true" };
|
||||
|
||||
void EmptyBacktrackData(BacktrackData &i);
|
||||
std::pair<int, int> getBestEntBestTick();
|
||||
@ -51,19 +52,14 @@ void UpdateIncomingSequences()
|
||||
sequences.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void AddLatencyToNetchan(INetChannel *ch)
|
||||
{
|
||||
if (!isBacktrackEnabled)
|
||||
return;
|
||||
float Latency = *latency;
|
||||
if (Latency > 1000.0f)
|
||||
Latency = 800.0f;
|
||||
Latency -= getRealLatency();
|
||||
if (Latency < 0.0f)
|
||||
Latency = 0.0f;
|
||||
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_nInSequenceNr = seq.sequencenr;
|
||||
@ -84,13 +80,21 @@ int BestTick = -1;
|
||||
int iBestTarget = -1;
|
||||
bool istickvalid[33][66]{};
|
||||
bool istickinvalid[33][66]{};
|
||||
static float latency_rampup = 0.0f;
|
||||
|
||||
static void Run()
|
||||
{
|
||||
if (!shouldBacktrack())
|
||||
{
|
||||
isBacktrackEnabled = false;
|
||||
latency_rampup = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Limit to 2 ticks
|
||||
latency_rampup += 1.0f / 66.0f;
|
||||
latency_rampup = std::min(latency_rampup, 1.0f);
|
||||
|
||||
UpdateIncomingSequences();
|
||||
isBacktrackEnabled = true;
|
||||
|
||||
@ -341,11 +345,11 @@ float getLatency()
|
||||
if (!ch)
|
||||
return 0;
|
||||
float Latency = *latency;
|
||||
if (Latency > 1000.0f)
|
||||
Latency = 800.0f;
|
||||
Latency = std::min(Latency, 800.0f);
|
||||
Latency -= getRealLatency();
|
||||
if (Latency < 0.0f)
|
||||
Latency = 0.0f;
|
||||
Latency = std::max(Latency, 0.0f);
|
||||
if (enable_latency_rampup)
|
||||
Latency = Latency * latency_rampup;
|
||||
return Latency;
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ IClientEntity *GetActiveTFWeapon_detour(IClientEntity *this_ /* C_TFPlayer * */)
|
||||
QAngle angle = *(QAngle *) &NET_VECTOR(this_, netvar.angEyeAngles);
|
||||
if (isLocal)
|
||||
{
|
||||
g_IEngine->GetViewAngles(angle);
|
||||
angle = VectorToQAngle(current_user_cmd->viewangles);
|
||||
eyePos = g_pLocalPlayer->v_Eye;
|
||||
}
|
||||
Vector forward;
|
||||
|
@ -198,7 +198,7 @@ static bool isValidNearPosition(Vector vec, Vector target, const bot_class_confi
|
||||
float dist = vec.DistTo(target);
|
||||
if (dist < config.min || dist > config.max)
|
||||
return false;
|
||||
if (!IsVectorVisible(vec, target, true))
|
||||
if (!IsVectorVisible(vec, target, true, LOCAL_E, MASK_PLAYERSOLID))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -341,13 +341,12 @@ void createMove()
|
||||
{
|
||||
if (current_index >= source->size())
|
||||
current_index = 0;
|
||||
if (random_order && source->size())
|
||||
if (random_order && source->size() > 1)
|
||||
{
|
||||
current_index = rand() % source->size();
|
||||
int tries = 0;
|
||||
while (current_index == last_index && tries++ < 1000)
|
||||
current_index = UniformRandomInt(0, source->size() - 1);
|
||||
while (current_index == last_index)
|
||||
{
|
||||
current_index = rand() % source->size();
|
||||
current_index = UniformRandomInt(0, source->size() - 1);
|
||||
}
|
||||
}
|
||||
last_index = current_index;
|
||||
|
@ -1177,7 +1177,7 @@ netvar.iHealth));
|
||||
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)
|
||||
@ -1188,7 +1188,7 @@ bool IsVectorVisible(Vector origin, Vector target, bool enviroment_only, CachedE
|
||||
trace::filter_no_player.SetSelf(RAW_ENT(self));
|
||||
ray.Init(origin, target);
|
||||
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);
|
||||
}
|
||||
else
|
||||
@ -1199,7 +1199,7 @@ bool IsVectorVisible(Vector origin, Vector target, bool enviroment_only, CachedE
|
||||
trace::filter_no_entity.SetSelf(RAW_ENT(self));
|
||||
ray.Init(origin, target);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -10,23 +10,17 @@ namespace hooked_methods
|
||||
{
|
||||
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);
|
||||
int in = 0;
|
||||
int state = 0;
|
||||
if (CE_GOOD(LOCAL_E) && ch)
|
||||
{
|
||||
in = ch->m_nInSequenceNr;
|
||||
state = ch->m_nInReliableState;
|
||||
|
||||
int in = ch->m_nInSequenceNr;
|
||||
int state = ch->m_nInReliableState;
|
||||
hacks::shared::backtrack::AddLatencyToNetchan(ch);
|
||||
}
|
||||
|
||||
int ret = original::SendDatagram(ch, buf);
|
||||
if (CE_GOOD(LOCAL_E) && ch)
|
||||
{
|
||||
ch->m_nInSequenceNr = in;
|
||||
ch->m_nInReliableState = state;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
} // namespace hooked_methods
|
||||
|
@ -231,6 +231,9 @@ void UpdateTemporaryData()
|
||||
|
||||
void StoreClientData()
|
||||
{
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
UpdateServerAddress();
|
||||
user_data_s &data = peer->memory->peer_user_data[peer->client_id];
|
||||
data.friendid = g_ISteamUser->GetSteamID().GetAccountID();
|
||||
|
@ -15,11 +15,14 @@ namespace nav
|
||||
static settings::Boolean enabled{ "misc.pathing", "true" };
|
||||
// Whether or not to run vischecks at pathtime
|
||||
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 look{ "misc.pathing.look-at-path", "false" };
|
||||
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
|
||||
{
|
||||
@ -48,72 +51,57 @@ struct ignoredata
|
||||
Timer ignoreTimeout{};
|
||||
};
|
||||
|
||||
CNavArea *getNavArea(Vector &vec)
|
||||
Vector GetClosestCornerToArea(CNavArea *CornerOf, const Vector &target)
|
||||
{
|
||||
for (auto &i : navfile->m_areas)
|
||||
{
|
||||
if (vec == i.m_center)
|
||||
return &i;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
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 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 = &corners[0], *bestVec2 = bestVec;
|
||||
float bestDist = corners[0].DistTo(target), bestDist2 = bestDist;
|
||||
|
||||
Vector bestVec{};
|
||||
float bestDist = FLT_MAX;
|
||||
|
||||
for (size_t i = 0; i < corners.size(); i++)
|
||||
for (size_t i = 1; i < corners.size(); i++)
|
||||
{
|
||||
float dist = corners.at(i).DistTo(Target->m_center);
|
||||
float dist = corners[i].DistTo(target);
|
||||
if (dist < bestDist)
|
||||
{
|
||||
bestVec = corners.at(i);
|
||||
bestVec = &corners[i];
|
||||
bestDist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
Vector bestVec2{};
|
||||
float bestDist2 = FLT_MAX;
|
||||
|
||||
for (size_t i = 0; i < corners.size(); i++)
|
||||
{
|
||||
if (corners.at(i) == bestVec2)
|
||||
if (corners[i] == *bestVec2)
|
||||
continue;
|
||||
float dist = corners.at(i).DistTo(Target->m_center);
|
||||
|
||||
if (dist < bestDist2)
|
||||
{
|
||||
bestVec2 = corners.at(i);
|
||||
bestVec2 = &corners[i];
|
||||
bestDist2 = dist;
|
||||
}
|
||||
}
|
||||
return (bestVec + bestVec2) / 2;
|
||||
return (*bestVec + *bestVec2) / 2;
|
||||
}
|
||||
|
||||
float getZBetweenAreas(CNavArea *start, CNavArea *end)
|
||||
{
|
||||
float z1 = GetClosestCornerToArea(start, end).z;
|
||||
float z2 = GetClosestCornerToArea(end, start).z;
|
||||
float z1 = GetClosestCornerToArea(start, end->m_center).z;
|
||||
float z2 = GetClosestCornerToArea(end, start->m_center).z;
|
||||
|
||||
return z2 - z1;
|
||||
}
|
||||
|
||||
class ignoremanager
|
||||
{
|
||||
|
||||
static std::unordered_map<std::pair<CNavArea *, CNavArea *>, ignoredata, boost::hash<std::pair<CNavArea *, CNavArea *>>> ignores;
|
||||
namespace ignoremanager
|
||||
{
|
||||
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);
|
||||
return IsVectorVisible(first, second, true, LOCAL_E, MASK_PLAYERSOLID);
|
||||
}
|
||||
static ignore_status runIgnoreChecks(CNavArea *begin, CNavArea *end)
|
||||
{
|
||||
@ -197,8 +185,8 @@ class ignoremanager
|
||||
// Vischecks
|
||||
for (size_t i = 0; i < crumbs.size() - 1; i++)
|
||||
{
|
||||
CNavArea *begin = getNavArea(crumbs.at(i));
|
||||
CNavArea *end = getNavArea(crumbs.at(i + 1));
|
||||
CNavArea *begin = crumbs[i];
|
||||
CNavArea *end = crumbs[i + 1];
|
||||
if (!begin || !end)
|
||||
continue;
|
||||
ignoredata &data = ignores[{ begin, end }];
|
||||
@ -218,14 +206,12 @@ class ignoremanager
|
||||
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;
|
||||
ignore_status status = ignores[{ begin, end }].status;
|
||||
if (status == unknown)
|
||||
status = runIgnoreChecks(begin, end);
|
||||
if (status == vischeck_success)
|
||||
@ -235,8 +221,27 @@ public:
|
||||
else
|
||||
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)
|
||||
{
|
||||
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;
|
||||
// Check if connection is already known
|
||||
if (ignores.find({ begin, end }) == ignores.end())
|
||||
@ -247,27 +252,11 @@ public:
|
||||
connection.stucktime += duration_cast<milliseconds>(system_clock::now() - time.last).count();
|
||||
if (connection.stucktime >= *stuck_time)
|
||||
{
|
||||
connection.status = explicit_ignored;
|
||||
connection.ignoreTimeout.update();
|
||||
logging::Info("Ignored Connection %i-%i", begin->m_id, end->m_id);
|
||||
return true;
|
||||
return addTime(connection, explicit_ignored);
|
||||
}
|
||||
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()
|
||||
{
|
||||
ignores.clear();
|
||||
@ -329,21 +318,16 @@ public:
|
||||
{
|
||||
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()
|
||||
{
|
||||
Graph() {
|
||||
pather = std::make_unique<micropather::MicroPather>(this, 3000, 6, true);
|
||||
}
|
||||
~Graph() override
|
||||
{
|
||||
}
|
||||
~Graph() override {}
|
||||
void AdjacentCost(void *state, MP_VECTOR<micropather::StateCost> *adjacent) override
|
||||
{
|
||||
CNavArea *center = static_cast<CNavArea *>(state);
|
||||
@ -354,22 +338,21 @@ struct Graph : public micropather::Graph
|
||||
if (isIgnored == 2)
|
||||
continue;
|
||||
float distance = center->m_center.DistTo(i.area->m_center);
|
||||
if (isIgnored == 1)
|
||||
if (isIgnored == 1) {
|
||||
if (*vischeckBlock)
|
||||
continue;
|
||||
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
|
||||
{
|
||||
CNavArea *start = static_cast<CNavArea *>(stateStart);
|
||||
CNavArea *end = static_cast<CNavArea *>(stateEnd);
|
||||
CNavArea *start = reinterpret_cast<CNavArea *>(stateStart);
|
||||
CNavArea *end = reinterpret_cast<CNavArea *>(stateEnd);
|
||||
return start->m_center.DistTo(end->m_center);
|
||||
}
|
||||
void PrintStateInfo(void *) override
|
||||
{
|
||||
// Uhh no
|
||||
}
|
||||
void PrintStateInfo(void *) override {}
|
||||
};
|
||||
|
||||
// Navfile containing areas
|
||||
@ -414,6 +397,7 @@ void initThread()
|
||||
|
||||
void init()
|
||||
{
|
||||
endPoint.Invalidate();
|
||||
ignoremanager::reset();
|
||||
status = initing;
|
||||
std::thread thread;
|
||||
@ -437,123 +421,100 @@ bool prepare()
|
||||
|
||||
// This prevents the bot from gettings completely stuck in some cases
|
||||
static std::vector<CNavArea *> findClosestNavSquare_localAreas(6);
|
||||
|
||||
// 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());
|
||||
|
||||
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 (i.IsOverlapping(vec))
|
||||
float ovBestDist = FLT_MAX, bestDist = FLT_MAX;
|
||||
// If multiple candidates for LocalNav have been found, pick the closest
|
||||
CNavArea *ovBestSquare = nullptr, *bestSquare = nullptr;
|
||||
for (auto &i : navfile->m_areas)
|
||||
{
|
||||
// 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))
|
||||
overlapping.push_back(&i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (dist < bestDist)
|
||||
{
|
||||
if (std::count(findClosestNavSquare_localAreas.begin(), findClosestNavSquare_localAreas.end(), &i) < 3)
|
||||
{
|
||||
bestDist = dist;
|
||||
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)
|
||||
findClosestNavSquare_localAreas.push_back(bestSquare);
|
||||
return bestSquare;
|
||||
if (!ovBestSquare)
|
||||
ovBestSquare = 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)
|
||||
return {};
|
||||
CNavArea *local = findClosestNavSquare(start);
|
||||
CNavArea *dest = findClosestNavSquare(end);
|
||||
|
||||
if (!local || !dest)
|
||||
CNavArea *local, *dest;
|
||||
if (!(local = findClosestNavSquare(start)) || !(dest = findClosestNavSquare(end)))
|
||||
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;
|
||||
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();
|
||||
std::vector<CNavArea*> pathNodes;
|
||||
|
||||
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);
|
||||
// If no result found, return empty Vector
|
||||
if (result == micropather::MicroPather::NO_SOLUTION)
|
||||
return std::vector<Vector>(0);
|
||||
// Convert (void *) CNavArea * to Vector
|
||||
std::vector<Vector> path;
|
||||
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;
|
||||
return {};
|
||||
|
||||
return pathNodes;
|
||||
}
|
||||
|
||||
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;
|
||||
static Timer inactivity{};
|
||||
int curr_priority = 0;
|
||||
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;
|
||||
if (priority < curr_priority)
|
||||
return false;
|
||||
std::vector<Vector> path = findPath(g_pLocalPlayer->v_Origin, destination);
|
||||
|
||||
auto path = findPath(g_pLocalPlayer->v_Origin, destination);
|
||||
if (path.empty())
|
||||
{
|
||||
crumbs.clear();
|
||||
clearInstructions();
|
||||
return false;
|
||||
}
|
||||
auto crumb = crumbs.begin();
|
||||
if (crumb != crumbs.end())
|
||||
{
|
||||
if (ignoremanager::addTime(last_area, *crumb, inactivity))
|
||||
if (crumb != crumbs.end() && ignoremanager::addTime(last_area, *crumb, inactivity))
|
||||
ResetPather();
|
||||
}
|
||||
|
||||
auto path_it = path.begin();
|
||||
last_area = *path_it;
|
||||
if (!nav_to_local)
|
||||
@ -564,26 +525,33 @@ bool navTo(Vector destination, int priority, bool should_repath, bool nav_to_loc
|
||||
}
|
||||
inactivity.update();
|
||||
if (!is_repath)
|
||||
{
|
||||
findClosestNavSquare_localAreas.clear();
|
||||
}
|
||||
|
||||
ensureArrival = should_repath;
|
||||
ReadyForCommands = false;
|
||||
curr_priority = priority;
|
||||
crumbs = std::move(path);
|
||||
endPoint = destination;
|
||||
return true;
|
||||
}
|
||||
|
||||
void repath()
|
||||
{
|
||||
if (ensureArrival)
|
||||
{
|
||||
Vector last = crumbs.back();
|
||||
crumbs.clear();
|
||||
if (!ensureArrival)
|
||||
return;
|
||||
|
||||
Vector last;
|
||||
if (!crumbs.empty())
|
||||
last = crumbs.back()->m_center;
|
||||
else if (endPoint.IsValid())
|
||||
last = endPoint;
|
||||
else
|
||||
return;
|
||||
|
||||
clearInstructions();
|
||||
ResetPather();
|
||||
navTo(last, curr_priority, true, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
static Timer last_jump{};
|
||||
// Main movement function, gets path from NavTo
|
||||
@ -596,51 +564,82 @@ static void cm()
|
||||
if (!LOCAL_E->m_bAlivePlayer())
|
||||
{
|
||||
// Clear path if player dead
|
||||
crumbs.clear();
|
||||
clearInstructions();
|
||||
return;
|
||||
}
|
||||
ignoremanager::updateIgnores();
|
||||
auto crumb = crumbs.begin();
|
||||
const Vector *crumb_vec;
|
||||
// Crumbs empty, prepare for next instruction
|
||||
if (crumb == crumbs.end())
|
||||
{
|
||||
if (endPoint.IsValid())
|
||||
crumb_vec = &endPoint;
|
||||
else
|
||||
{
|
||||
curr_priority = 0;
|
||||
ReadyForCommands = true;
|
||||
ensureArrival = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
crumb_vec = &(*crumb)->m_center;
|
||||
|
||||
ReadyForCommands = false;
|
||||
// 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;
|
||||
crumbs.erase(crumb);
|
||||
inactivity.update();
|
||||
crumb = crumbs.begin();
|
||||
if (crumb == crumbs.end())
|
||||
{
|
||||
if (!endPoint.IsValid())
|
||||
{
|
||||
logging::Info("navparser.cpp cm -> endPoint.IsValid() == false");
|
||||
return;
|
||||
}
|
||||
crumb_vec = &endPoint;
|
||||
}
|
||||
}
|
||||
if (look && LookAtPathTimer.check(1000))
|
||||
{
|
||||
Vector next = *crumb;
|
||||
next.z = g_pLocalPlayer->v_Eye.z;
|
||||
Vector angle = GetAimAtAngles(g_pLocalPlayer->v_Eye, next);
|
||||
DoSlowAim(angle);
|
||||
current_user_cmd->viewangles = angle;
|
||||
Vector next{crumb_vec->x, crumb_vec->y, g_pLocalPlayer->v_Eye.z};
|
||||
next = GetAimAtAngles(g_pLocalPlayer->v_Eye, next);
|
||||
DoSlowAim(next);
|
||||
current_user_cmd->viewangles = next;
|
||||
}
|
||||
// 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)))
|
||||
current_user_cmd->buttons |= IN_JUMP | IN_DUCK;
|
||||
// If inactive for too long
|
||||
if (inactivity.check(*stuck_time))
|
||||
if ((!(g_pLocalPlayer->holding_sniper_rifle && g_pLocalPlayer->bZoomed) &&
|
||||
crumb_vec->z - g_pLocalPlayer->v_Origin.z > 18 && last_jump.test_and_set(200)) ||
|
||||
(last_jump.test_and_set(200) && inactivity.check(*stuck_time / 2)))
|
||||
{
|
||||
// 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);
|
||||
|
||||
repath();
|
||||
return;
|
||||
}
|
||||
// Walk to next crumb
|
||||
WalkTo(*crumb);
|
||||
}
|
||||
|
||||
#if ENABLE_VISUALS
|
||||
@ -654,16 +653,25 @@ static void drawcrumbs()
|
||||
return;
|
||||
if (crumbs.size() < 2)
|
||||
return;
|
||||
for (size_t i = 0; i < crumbs.size() - 1; i++)
|
||||
for (size_t i = 0; i < crumbs.size(); i++)
|
||||
{
|
||||
Vector wts1, wts2;
|
||||
if (draw::WorldToScreen(crumbs[i], wts1) && draw::WorldToScreen(crumbs[i + 1], wts2))
|
||||
Vector wts1, wts2, *o1, *o2;
|
||||
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);
|
||||
}
|
||||
}
|
||||
Vector wts;
|
||||
if (!draw::WorldToScreen(crumbs[0], wts))
|
||||
if (!draw::WorldToScreen(crumbs[0]->m_center, wts))
|
||||
return;
|
||||
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);
|
||||
@ -688,7 +696,7 @@ bool isSafe(CNavArea *area)
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
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: ";
|
||||
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());
|
||||
});
|
||||
@ -775,6 +783,7 @@ void DoSlowAim(Vector &input_angle)
|
||||
void clearInstructions()
|
||||
{
|
||||
crumbs.clear();
|
||||
endPoint.Invalidate();
|
||||
curr_priority = 0;
|
||||
}
|
||||
static CatCommand nav_stop("nav_cancel", "Cancel Navigation", []() { clearInstructions(); });
|
||||
|
@ -13,7 +13,7 @@ TextFile::TextFile() : lines{}
|
||||
{
|
||||
}
|
||||
|
||||
bool TextFile::TryLoad(std::string name)
|
||||
bool TextFile::TryLoad(const std::string &name)
|
||||
{
|
||||
if (name.length() == 0)
|
||||
return false;
|
||||
@ -30,12 +30,15 @@ bool TextFile::TryLoad(std::string name)
|
||||
line.erase(line.length() - 1, 1);
|
||||
lines.push_back(line);
|
||||
}
|
||||
if (lines.size() > 0 && *lines.rbegin() == "\n")
|
||||
lines.pop_back();
|
||||
|
||||
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);
|
||||
if (file.bad())
|
||||
{
|
||||
|
@ -140,6 +140,9 @@ bool trace::FilterNoEntity::ShouldHitEntity(IHandleEntity *handle, int mask)
|
||||
// Hit doors, carts, etc
|
||||
switch (clazz->m_ClassID)
|
||||
{
|
||||
case CL_CLASS(CWorld):
|
||||
case CL_CLASS(CPhysicsProp):
|
||||
case CL_CLASS(CDynamicProp):
|
||||
case CL_CLASS(CBaseDoor):
|
||||
case CL_CLASS(CBaseEntity):
|
||||
return true;
|
||||
|
Reference in New Issue
Block a user