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

View File

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

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

View File

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

View File

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

View File

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

View File

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

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_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)
@ -189,17 +189,27 @@ static CatCommand get_best_hats("achievement_cathats", "Get and equip the bencat
unlock_achievements_and_accept(bencat_hats);
hacks::shared::misc::generate_schema();
hacks::shared::misc::Schema_Reload();
equip_hats = true;
equip_first_half = true;
equip_hats = 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)
{
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_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");
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)
{
hacks::shared::misc::generate_schema();
hacks::shared::misc::Schema_Reload();
init = true;
}
});
});
} // 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::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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
hacks::shared::backtrack::AddLatencyToNetchan(ch);
}
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;
}
ch->m_nInSequenceNr = in;
ch->m_nInReliableState = state;
return ret;
}
} // namespace hooked_methods

View File

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

View File

@ -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)
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)
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);
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 std::unordered_map<std::pair<CNavArea *, CNavArea *>, ignoredata, boost::hash<std::pair<CNavArea *, CNavArea *>>> ignores;
static bool vischeck(CNavArea *begin, CNavArea *end)
{
Vector first = begin->m_center;
Vector second = end->m_center;
first.z += 42;
second.z += 42;
return IsVectorVisible(first, second, true);
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))
{
// 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 (IsVectorVisible(vec, i.m_center, true))
overlapping.push_back(&i);
}
}
}
float ovBestDist = FLT_MAX, bestDist = FLT_MAX;
// If multiple candidates for LocalNav have been found, pick the closest
float bestDist = FLT_MAX;
CNavArea *bestSquare = nullptr;
for (auto &i : overlapping)
CNavArea *ovBestSquare = nullptr, *bestSquare = nullptr;
for (auto &i : navfile->m_areas)
{
float dist = i->m_center.DistTo(vec);
if (dist < bestDist)
// Make sure we're not stuck on the same area for too long
if (isLocal && std::count(findClosestNavSquare_localAreas.begin(),
findClosestNavSquare_localAreas.end(), &i) >= 3)
{
bestDist = dist;
bestSquare = i;
continue;
}
}
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;
}
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))
ResetPather();
}
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,25 +525,32 @@ 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();
ResetPather();
navTo(last, curr_priority, true, true, true);
}
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{};
@ -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())
{
curr_priority = 0;
ReadyForCommands = true;
ensureArrival = false;
return;
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())
return;
{
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
ignoremanager::addTime(last_area, *crumb, inactivity);
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(); });

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)
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())
{

View File

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