Merge pull request #553 from TotallyNotElite/master
Navparser and pathing improvements
This commit is contained in:
commit
a9616460b3
@ -3,16 +3,91 @@
|
|||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "micropather.h"
|
#include "micropather.h"
|
||||||
#include "pwd.h"
|
#include "pwd.h"
|
||||||
|
#if ENABLE_VISUALS
|
||||||
|
#include <glez/draw.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace nav
|
namespace nav
|
||||||
{
|
{
|
||||||
extern bool init;
|
extern bool init;
|
||||||
extern bool ReadyForCommands;
|
extern bool ReadyForCommands;
|
||||||
|
extern int priority;
|
||||||
extern std::vector<CNavArea> areas;
|
extern std::vector<CNavArea> areas;
|
||||||
std::vector<Vector> findPath(Vector loc, Vector dest);
|
std::vector<Vector> findPath(Vector loc, Vector dest, int &id_loc,
|
||||||
|
int &id_dest);
|
||||||
bool NavTo(Vector dest, bool navToLocalCenter = true, bool persistent = true,
|
bool NavTo(Vector dest, bool navToLocalCenter = true, bool persistent = true,
|
||||||
int instructionPriority = 5);
|
int instructionPriority = 5);
|
||||||
|
void clearInstructions();
|
||||||
int findClosestNavSquare(Vector vec);
|
int findClosestNavSquare(Vector vec);
|
||||||
bool Prepare();
|
bool Prepare();
|
||||||
void CreateMove();
|
void CreateMove();
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
struct inactivityTracker
|
||||||
|
{
|
||||||
|
// Map for storing inactivity per connection
|
||||||
|
std::map<std::pair<int, int>, unsigned int> inactives;
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
// inactives.clear();
|
||||||
|
}
|
||||||
|
void addTime(std::pair<int, int> connection, Timer &timer,
|
||||||
|
bool &resetPather)
|
||||||
|
{
|
||||||
|
if (inactives.find(connection) == inactives.end())
|
||||||
|
{
|
||||||
|
inactives[connection] = 0;
|
||||||
|
}
|
||||||
|
inactives[connection] =
|
||||||
|
inactives[connection] +
|
||||||
|
(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
std::chrono::system_clock::now() - timer.last)
|
||||||
|
.count());
|
||||||
|
if (inactives[connection] >= 5000)
|
||||||
|
resetPather = true;
|
||||||
|
}
|
||||||
|
void addTime(std::pair<Vector, Vector> connection, Timer &timer,
|
||||||
|
bool &resetPather)
|
||||||
|
{
|
||||||
|
CNavArea *currnode = nullptr;
|
||||||
|
for (size_t i = 0; i < areas.size(); i++)
|
||||||
|
{
|
||||||
|
if (areas.at(i).m_center == connection.first)
|
||||||
|
{
|
||||||
|
currnode = &areas.at(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!currnode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CNavArea *nextnode = nullptr;
|
||||||
|
for (size_t i = 0; i < areas.size(); i++)
|
||||||
|
{
|
||||||
|
if (areas.at(i).m_center == connection.second)
|
||||||
|
{
|
||||||
|
nextnode = &areas.at(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!nextnode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto i : currnode->m_connections)
|
||||||
|
{
|
||||||
|
if (i.area->m_id == nextnode->m_id)
|
||||||
|
{
|
||||||
|
addTime(std::pair{ currnode->m_id, nextnode->m_id }, timer,
|
||||||
|
resetPather);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsigned int getTime(std::pair<int, int> connection)
|
||||||
|
{
|
||||||
|
return inactives[connection];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace nav
|
} // namespace nav
|
||||||
|
@ -4,11 +4,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <glez/color.hpp>
|
|
||||||
|
|
||||||
#include <config.h>
|
#if ENABLE_VISUALS
|
||||||
|
#include <glez/color.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
@ -142,4 +144,4 @@ protected:
|
|||||||
|
|
||||||
#if ENABLE_VISUALS
|
#if ENABLE_VISUALS
|
||||||
#include "Rgba.hpp"
|
#include "Rgba.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
@ -287,11 +287,11 @@ DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time,
|
|||||||
hacks::shared::walkbot::Move();
|
hacks::shared::walkbot::Move();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PROF_SECTION(CM_navbot);
|
PROF_SECTION(CM_navparse);
|
||||||
nav::CreateMove();
|
nav::CreateMove();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PROF_SECTION(CM_NavParse);
|
PROF_SECTION(CM_navbot);
|
||||||
hacks::tf2::NavBot::CreateMove();
|
hacks::tf2::NavBot::CreateMove();
|
||||||
}
|
}
|
||||||
// Walkbot can leave game.
|
// Walkbot can leave game.
|
||||||
|
@ -3,19 +3,19 @@
|
|||||||
namespace nav
|
namespace nav
|
||||||
{
|
{
|
||||||
static CNavFile navfile(nullptr);
|
static CNavFile navfile(nullptr);
|
||||||
|
// Vector containing areas on map
|
||||||
std::vector<CNavArea> areas;
|
std::vector<CNavArea> areas;
|
||||||
// std::vector<CNavArea> SniperAreas;
|
bool init = false;
|
||||||
bool init = false;
|
static bool pathfinding = true;
|
||||||
bool pathfinding = true;
|
bool ReadyForCommands = false;
|
||||||
bool ReadyForCommands = false;
|
inactivityTracker inactiveTracker;
|
||||||
std::vector<std::pair<int, int>> ignoredConnections;
|
|
||||||
|
|
||||||
static settings::Bool enabled{ "misc.pathing", "true" };
|
static settings::Bool enabled{ "misc.pathing", "true" };
|
||||||
|
static settings::Bool draw{ "misc.pathing.draw", "false" };
|
||||||
|
|
||||||
// Todo fix
|
// Todo fix
|
||||||
int FindInVector(int id)
|
size_t FindInVector(size_t id)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < areas.size(); i++)
|
for (size_t i = 0; i < areas.size(); i++)
|
||||||
{
|
{
|
||||||
if (areas.at(i).m_id == id)
|
if (areas.at(i).m_id == id)
|
||||||
return i;
|
return i;
|
||||||
@ -25,16 +25,11 @@ int FindInVector(int id)
|
|||||||
struct MAP : public micropather::Graph
|
struct MAP : public micropather::Graph
|
||||||
{
|
{
|
||||||
std::unique_ptr<micropather::MicroPather> pather;
|
std::unique_ptr<micropather::MicroPather> pather;
|
||||||
bool IsIgnored(int currState, int connectionID)
|
// Function to check if a connection is ignored
|
||||||
|
bool IsIgnored(size_t currState, size_t connectionID)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < ignoredConnections.size(); i++)
|
if (inactiveTracker.getTime({ currState, connectionID }) >= 5000)
|
||||||
{
|
return true;
|
||||||
if (ignoredConnections.at(i).first == currState &&
|
|
||||||
ignoredConnections.at(i).second == connectionID)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Vector GetClosestCornerToArea(CNavArea *CornerOf, CNavArea *Target)
|
Vector GetClosestCornerToArea(CNavArea *CornerOf, CNavArea *Target)
|
||||||
@ -50,7 +45,7 @@ struct MAP : public micropather::Graph
|
|||||||
Vector bestVec;
|
Vector bestVec;
|
||||||
float bestDist = FLT_MAX;
|
float bestDist = FLT_MAX;
|
||||||
|
|
||||||
for (int i = 0; i < corners.size(); i++)
|
for (size_t i = 0; i < corners.size(); i++)
|
||||||
{
|
{
|
||||||
float dist = corners.at(i).DistTo(Target->m_center);
|
float dist = corners.at(i).DistTo(Target->m_center);
|
||||||
if (dist < bestDist)
|
if (dist < bestDist)
|
||||||
@ -63,7 +58,7 @@ struct MAP : public micropather::Graph
|
|||||||
Vector bestVec2;
|
Vector bestVec2;
|
||||||
float bestDist2 = FLT_MAX;
|
float bestDist2 = FLT_MAX;
|
||||||
|
|
||||||
for (int i = 0; i < corners.size(); i++)
|
for (size_t i = 0; i < corners.size(); i++)
|
||||||
{
|
{
|
||||||
if (corners.at(i) == bestVec2)
|
if (corners.at(i) == bestVec2)
|
||||||
continue;
|
continue;
|
||||||
@ -84,6 +79,7 @@ struct MAP : public micropather::Graph
|
|||||||
|
|
||||||
return z2 - z1;
|
return z2 - z1;
|
||||||
}
|
}
|
||||||
|
// Function required by MicroPather for getting an estimated cost
|
||||||
float LeastCostEstimate(void *stateStart, void *stateEnd)
|
float LeastCostEstimate(void *stateStart, void *stateEnd)
|
||||||
{
|
{
|
||||||
CNavArea *start = static_cast<CNavArea *>(stateStart);
|
CNavArea *start = static_cast<CNavArea *>(stateStart);
|
||||||
@ -91,6 +87,8 @@ struct MAP : public micropather::Graph
|
|||||||
float dist = start->m_center.DistTo(end->m_center);
|
float dist = start->m_center.DistTo(end->m_center);
|
||||||
return dist;
|
return dist;
|
||||||
}
|
}
|
||||||
|
// Function required by MicroPather to retrieve neighbours and their
|
||||||
|
// associated costs.
|
||||||
void AdjacentCost(void *state, MP_VECTOR<micropather::StateCost> *adjacent)
|
void AdjacentCost(void *state, MP_VECTOR<micropather::StateCost> *adjacent)
|
||||||
{
|
{
|
||||||
CNavArea *area = static_cast<CNavArea *>(state);
|
CNavArea *area = static_cast<CNavArea *>(state);
|
||||||
@ -110,6 +108,10 @@ struct MAP : public micropather::Graph
|
|||||||
}
|
}
|
||||||
void PrintStateInfo(void *state)
|
void PrintStateInfo(void *state)
|
||||||
{
|
{
|
||||||
|
CNavArea *area = static_cast<CNavArea *>(state);
|
||||||
|
logging::Info(format(area->m_center.x, " ", area->m_center.y, " ",
|
||||||
|
area->m_center.z)
|
||||||
|
.c_str());
|
||||||
}
|
}
|
||||||
MAP(size_t size)
|
MAP(size_t size)
|
||||||
{
|
{
|
||||||
@ -122,14 +124,14 @@ struct MAP : public micropather::Graph
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<MAP> TF2MAP;
|
static std::unique_ptr<MAP> TF2MAP;
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
// TODO: Improve performance
|
// Get NavFile location
|
||||||
std::string lvlname(g_IEngine->GetLevelName());
|
std::string lvlname(g_IEngine->GetLevelName());
|
||||||
int dotpos = lvlname.find('.');
|
size_t dotpos = lvlname.find('.');
|
||||||
lvlname = lvlname.substr(0, dotpos);
|
lvlname = lvlname.substr(0, dotpos);
|
||||||
|
|
||||||
std::string lvldir("/home/");
|
std::string lvldir("/home/");
|
||||||
passwd *pwd = getpwuid(getuid());
|
passwd *pwd = getpwuid(getuid());
|
||||||
@ -140,6 +142,7 @@ void Init()
|
|||||||
logging::Info(format("Pathing: Nav File location: ", lvldir).c_str());
|
logging::Info(format("Pathing: Nav File location: ", lvldir).c_str());
|
||||||
|
|
||||||
areas.clear();
|
areas.clear();
|
||||||
|
// Load the NavFile
|
||||||
navfile = CNavFile(lvldir.c_str());
|
navfile = CNavFile(lvldir.c_str());
|
||||||
if (!navfile.m_isOK)
|
if (!navfile.m_isOK)
|
||||||
logging::Info("Pathing: Invalid Nav File");
|
logging::Info("Pathing: Invalid Nav File");
|
||||||
@ -149,15 +152,20 @@ void Init()
|
|||||||
logging::Info(
|
logging::Info(
|
||||||
format("Pathing: Number of areas to index:", size).c_str());
|
format("Pathing: Number of areas to index:", size).c_str());
|
||||||
areas.reserve(size);
|
areas.reserve(size);
|
||||||
|
// Add areas from CNavFile to our Vector
|
||||||
for (auto i : navfile.m_areas)
|
for (auto i : navfile.m_areas)
|
||||||
areas.push_back(i);
|
areas.push_back(i);
|
||||||
|
// Don't reserve more than 7000 states
|
||||||
if (size > 7000)
|
if (size > 7000)
|
||||||
size = 7000;
|
size = 7000;
|
||||||
|
// Initiate "Map", contains micropather object
|
||||||
TF2MAP = std::make_unique<MAP>(size);
|
TF2MAP = std::make_unique<MAP>(size);
|
||||||
}
|
}
|
||||||
pathfinding = true;
|
pathfinding = true;
|
||||||
}
|
}
|
||||||
std::string lastmap;
|
|
||||||
|
static std::string lastmap;
|
||||||
|
// Function that decides if pathing is possible, and inits pathing if necessary
|
||||||
bool Prepare()
|
bool Prepare()
|
||||||
{
|
{
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
@ -181,24 +189,31 @@ bool Prepare()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> localAreas(6);
|
// This prevents the bot from gettings completely stuck in some cases
|
||||||
|
static std::vector<int> findClosestNavSquare_localAreas(6);
|
||||||
|
// Function for getting closest Area to player, aka "LocalNav"
|
||||||
int findClosestNavSquare(Vector vec)
|
int findClosestNavSquare(Vector vec)
|
||||||
{
|
{
|
||||||
if (localAreas.size() > 5)
|
if (findClosestNavSquare_localAreas.size() > 5)
|
||||||
localAreas.erase(localAreas.begin());
|
findClosestNavSquare_localAreas.erase(
|
||||||
|
findClosestNavSquare_localAreas.begin());
|
||||||
std::vector<std::pair<int, CNavArea *>> overlapping;
|
std::vector<std::pair<int, CNavArea *>> overlapping;
|
||||||
for (int i = 0; i < areas.size(); i++)
|
for (size_t i = 0; i < areas.size(); i++)
|
||||||
{
|
{
|
||||||
|
// Check if we are within x and y bounds of an area
|
||||||
if (areas.at(i).IsOverlapping(vec))
|
if (areas.at(i).IsOverlapping(vec))
|
||||||
{
|
{
|
||||||
if (std::count(localAreas.begin(), localAreas.end(), i) < 2)
|
// Make sure we're not stuck on the same area for too long
|
||||||
|
if (std::count(findClosestNavSquare_localAreas.begin(),
|
||||||
|
findClosestNavSquare_localAreas.end(), i) < 3)
|
||||||
overlapping.push_back({ i, &areas.at(i) });
|
overlapping.push_back({ i, &areas.at(i) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If multiple candidates for LocalNav have been found, pick the closest
|
||||||
float bestDist = FLT_MAX;
|
float bestDist = FLT_MAX;
|
||||||
int bestSquare = -1;
|
int bestSquare = -1;
|
||||||
for (int i = 0; i < overlapping.size(); i++)
|
for (size_t i = 0; i < overlapping.size(); i++)
|
||||||
{
|
{
|
||||||
float dist = overlapping.at(i).second->m_center.DistTo(vec);
|
float dist = overlapping.at(i).second->m_center.DistTo(vec);
|
||||||
if (dist < bestDist)
|
if (dist < bestDist)
|
||||||
@ -210,15 +225,17 @@ int findClosestNavSquare(Vector vec)
|
|||||||
if (bestSquare != -1)
|
if (bestSquare != -1)
|
||||||
{
|
{
|
||||||
if (vec == g_pLocalPlayer->v_Origin)
|
if (vec == g_pLocalPlayer->v_Origin)
|
||||||
localAreas.push_back(bestSquare);
|
findClosestNavSquare_localAreas.push_back(bestSquare);
|
||||||
return bestSquare;
|
return bestSquare;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < areas.size(); i++)
|
// If no LocalNav was found, pick the closest available Area
|
||||||
|
for (size_t i = 0; i < areas.size(); i++)
|
||||||
{
|
{
|
||||||
float dist = areas.at(i).m_center.DistTo(vec);
|
float dist = areas.at(i).m_center.DistTo(vec);
|
||||||
if (dist < bestDist)
|
if (dist < bestDist)
|
||||||
{
|
{
|
||||||
if (std::count(localAreas.begin(), localAreas.end(), i) < 2)
|
if (std::count(findClosestNavSquare_localAreas.begin(),
|
||||||
|
findClosestNavSquare_localAreas.end(), i) < 3)
|
||||||
{
|
{
|
||||||
bestDist = dist;
|
bestDist = dist;
|
||||||
bestSquare = i;
|
bestSquare = i;
|
||||||
@ -226,41 +243,56 @@ int findClosestNavSquare(Vector vec)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vec == g_pLocalPlayer->v_Origin)
|
if (vec == g_pLocalPlayer->v_Origin)
|
||||||
localAreas.push_back(bestSquare);
|
findClosestNavSquare_localAreas.push_back(bestSquare);
|
||||||
return bestSquare;
|
return bestSquare;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Vector> findPath(Vector loc, Vector dest)
|
std::vector<Vector> findPath(Vector loc, Vector dest, int &id_loc, int &id_dest)
|
||||||
{
|
{
|
||||||
if (areas.empty())
|
if (areas.empty())
|
||||||
return std::vector<Vector>(0);
|
return std::vector<Vector>(0);
|
||||||
int id_loc = findClosestNavSquare(loc);
|
// Get areas of Vector loc and dest
|
||||||
int id_dest = findClosestNavSquare(dest);
|
id_loc = findClosestNavSquare(loc);
|
||||||
|
id_dest = findClosestNavSquare(dest);
|
||||||
if (id_loc == -1 || id_dest == -1)
|
if (id_loc == -1 || id_dest == -1)
|
||||||
return std::vector<Vector>(0);
|
return std::vector<Vector>(0);
|
||||||
float cost;
|
float cost;
|
||||||
micropather::MPVector<void *> pathNodes;
|
micropather::MPVector<void *> pathNodes;
|
||||||
|
// Find a solution to get to location
|
||||||
int result = TF2MAP->pather->Solve(static_cast<void *>(&areas.at(id_loc)),
|
int result = TF2MAP->pather->Solve(static_cast<void *>(&areas.at(id_loc)),
|
||||||
static_cast<void *>(&areas.at(id_dest)),
|
static_cast<void *>(&areas.at(id_dest)),
|
||||||
&pathNodes, &cost);
|
&pathNodes, &cost);
|
||||||
logging::Info(format(result).c_str());
|
logging::Info(format(result).c_str());
|
||||||
if (result == 1)
|
// If no result found, return empty Vector
|
||||||
|
if (result == micropather::MicroPather::NO_SOLUTION)
|
||||||
return std::vector<Vector>(0);
|
return std::vector<Vector>(0);
|
||||||
|
// Convert (void *) CNavArea * to Vector
|
||||||
std::vector<Vector> path;
|
std::vector<Vector> path;
|
||||||
for (int i = 0; i < pathNodes.size(); i++)
|
for (size_t i = 0; i < pathNodes.size(); i++)
|
||||||
{
|
{
|
||||||
path.push_back(static_cast<CNavArea *>(pathNodes[i])->m_center);
|
path.push_back(static_cast<CNavArea *>(pathNodes[i])->m_center);
|
||||||
}
|
}
|
||||||
|
// Add our destination to the std::vector
|
||||||
path.push_back(dest);
|
path.push_back(dest);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timer for measuring inactivity, aka time between not reaching a crumb
|
||||||
static Timer inactivity{};
|
static Timer inactivity{};
|
||||||
|
// Time since our last Jump
|
||||||
static Timer lastJump{};
|
static Timer lastJump{};
|
||||||
|
// std::vector containing our path
|
||||||
static std::vector<Vector> crumbs;
|
static std::vector<Vector> crumbs;
|
||||||
|
// Bot will keep trying to get to the target even if it fails a few times
|
||||||
static bool ensureArrival;
|
static bool ensureArrival;
|
||||||
int priority = 0;
|
// Priority value for current instructions, only higher priority can overwrite
|
||||||
|
// itlocalAreas
|
||||||
|
int priority = 0;
|
||||||
|
static Vector lastArea = { 0.0f, 0.0f, 0.0f };
|
||||||
|
|
||||||
|
// dest = Destination, navToLocalCenter = Should bot travel to local center
|
||||||
|
// first before resuming pathing activity? (Increases accuracy) persistent =
|
||||||
|
// ensureArrival above, instructionPriority = priority above
|
||||||
bool NavTo(Vector dest, bool navToLocalCenter, bool persistent,
|
bool NavTo(Vector dest, bool navToLocalCenter, bool persistent,
|
||||||
int instructionPriority)
|
int instructionPriority)
|
||||||
{
|
{
|
||||||
@ -268,73 +300,49 @@ bool NavTo(Vector dest, bool navToLocalCenter, bool persistent,
|
|||||||
return false;
|
return false;
|
||||||
if (!Prepare())
|
if (!Prepare())
|
||||||
return false;
|
return false;
|
||||||
if (instructionPriority <= priority)
|
// Only allow instructions to overwrite others if their priority is higher
|
||||||
|
if (instructionPriority < priority)
|
||||||
return false;
|
return false;
|
||||||
auto path = findPath(g_pLocalPlayer->v_Origin, dest);
|
int locNav, tarNav;
|
||||||
|
auto path = findPath(g_pLocalPlayer->v_Origin, dest, locNav, tarNav);
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
return false;
|
return false;
|
||||||
|
if (!crumbs.empty())
|
||||||
|
{
|
||||||
|
bool reset = false;
|
||||||
|
inactiveTracker.addTime({ lastArea, crumbs.at(0) }, inactivity, reset);
|
||||||
|
if (reset)
|
||||||
|
TF2MAP->pather->Reset();
|
||||||
|
}
|
||||||
crumbs.clear();
|
crumbs.clear();
|
||||||
crumbs = std::move(path);
|
crumbs = std::move(path);
|
||||||
if (!navToLocalCenter)
|
if (!navToLocalCenter)
|
||||||
crumbs.erase(crumbs.begin());
|
crumbs.erase(crumbs.begin());
|
||||||
ensureArrival = persistent;
|
ensureArrival = persistent;
|
||||||
localAreas.clear();
|
findClosestNavSquare_localAreas.clear();
|
||||||
priority = instructionPriority;
|
priority = instructionPriority;
|
||||||
|
inactivity.update();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Vector lastArea = { 0.0f, 0.0f, 0.0f };
|
void clearInstructions()
|
||||||
void ignoreConnection()
|
|
||||||
{
|
{
|
||||||
if (crumbs.size() < 1)
|
crumbs.clear();
|
||||||
return;
|
|
||||||
|
|
||||||
CNavArea *currnode = nullptr;
|
|
||||||
for (int i = 0; i < areas.size(); i++)
|
|
||||||
{
|
|
||||||
if (areas.at(i).m_center == lastArea)
|
|
||||||
{
|
|
||||||
currnode = &areas.at(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!currnode)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CNavArea *nextnode = nullptr;
|
|
||||||
for (int i = 0; i < areas.size(); i++)
|
|
||||||
{
|
|
||||||
if (areas.at(i).m_center == crumbs.at(0))
|
|
||||||
{
|
|
||||||
nextnode = &areas.at(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!nextnode)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (auto i : currnode->m_connections)
|
|
||||||
{
|
|
||||||
if (i.area->m_id == nextnode->m_id)
|
|
||||||
{
|
|
||||||
ignoredConnections.push_back({ currnode->m_id, nextnode->m_id });
|
|
||||||
TF2MAP->pather->Reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Timer ignoreReset{};
|
static Timer ignoreReset{};
|
||||||
|
// Function for removing ignores
|
||||||
void clearIgnores()
|
void clearIgnores()
|
||||||
{
|
{
|
||||||
if (ignoreReset.test_and_set(180000))
|
if (ignoreReset.test_and_set(180000))
|
||||||
{
|
{
|
||||||
ignoredConnections.clear();
|
inactiveTracker.reset();
|
||||||
if (TF2MAP && TF2MAP->pather)
|
if (TF2MAP && TF2MAP->pather)
|
||||||
TF2MAP->pather->Reset();
|
TF2MAP->pather->Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Main movement function, gets path from NavTo
|
||||||
void CreateMove()
|
void CreateMove()
|
||||||
{
|
{
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
@ -343,10 +351,12 @@ void CreateMove()
|
|||||||
return;
|
return;
|
||||||
if (!LOCAL_E->m_bAlivePlayer())
|
if (!LOCAL_E->m_bAlivePlayer())
|
||||||
{
|
{
|
||||||
|
// Clear path if player dead
|
||||||
crumbs.clear();
|
crumbs.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clearIgnores();
|
clearIgnores();
|
||||||
|
// Crumbs empty, prepare for next instruction
|
||||||
if (crumbs.empty())
|
if (crumbs.empty())
|
||||||
{
|
{
|
||||||
priority = 0;
|
priority = 0;
|
||||||
@ -355,6 +365,7 @@ void CreateMove()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ReadyForCommands = false;
|
ReadyForCommands = false;
|
||||||
|
// Remove old crumbs
|
||||||
if (g_pLocalPlayer->v_Origin.DistTo(Vector{ crumbs.at(0).x, crumbs.at(0).y,
|
if (g_pLocalPlayer->v_Origin.DistTo(Vector{ crumbs.at(0).x, crumbs.at(0).y,
|
||||||
g_pLocalPlayer->v_Origin.z }) <
|
g_pLocalPlayer->v_Origin.z }) <
|
||||||
30.0f)
|
30.0f)
|
||||||
@ -365,32 +376,72 @@ void CreateMove()
|
|||||||
}
|
}
|
||||||
if (crumbs.empty())
|
if (crumbs.empty())
|
||||||
return;
|
return;
|
||||||
|
// Detect when jumping is necessary
|
||||||
if (crumbs.at(0).z - g_pLocalPlayer->v_Origin.z > 18 &&
|
if (crumbs.at(0).z - g_pLocalPlayer->v_Origin.z > 18 &&
|
||||||
lastJump.test_and_set(200))
|
lastJump.test_and_set(200))
|
||||||
current_user_cmd->buttons |= IN_JUMP;
|
current_user_cmd->buttons |= IN_JUMP;
|
||||||
if (inactivity.test_and_set(5000))
|
// If inactive for too long
|
||||||
|
if (inactivity.check(5000))
|
||||||
{
|
{
|
||||||
ignoreConnection();
|
// Ignore connection
|
||||||
|
bool i3 = false;
|
||||||
|
inactiveTracker.addTime({ lastArea, crumbs.at(0) }, inactivity, i3);
|
||||||
|
if (i3)
|
||||||
|
TF2MAP->pather->Reset();
|
||||||
if (ensureArrival)
|
if (ensureArrival)
|
||||||
{
|
{
|
||||||
logging::Info("Pathing: NavBot inactive for too long. Ignoring "
|
logging::Info("Pathing: NavBot inactive for too long. Ignoring "
|
||||||
"connection and finding another path...");
|
"connection and finding another path...");
|
||||||
// NavTo(crumbs.back(), true, true);
|
// Find a new path
|
||||||
crumbs = findPath(g_pLocalPlayer->v_Origin, crumbs.back());
|
int i1, i2;
|
||||||
inactivity.update();
|
crumbs = findPath(g_pLocalPlayer->v_Origin, crumbs.back(), i1, i2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logging::Info(
|
logging::Info(
|
||||||
"Pathing: NavBot inactive for too long. Canceling tasks and "
|
"Pathing: NavBot inactive for too long. Canceling tasks and "
|
||||||
"ignoring connection...");
|
"ignoring connection...");
|
||||||
|
// Wait for new instructions
|
||||||
crumbs.clear();
|
crumbs.clear();
|
||||||
}
|
}
|
||||||
|
inactivity.update();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Walk to next crumb
|
||||||
WalkTo(crumbs.at(0));
|
WalkTo(crumbs.at(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Draw()
|
||||||
|
{
|
||||||
|
#if ENABLE_VISUALS
|
||||||
|
if (!enabled || !draw)
|
||||||
|
return;
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
if (CE_BAD(LOCAL_E))
|
||||||
|
return;
|
||||||
|
if (!LOCAL_E->m_bAlivePlayer())
|
||||||
|
return;
|
||||||
|
if (crumbs.size() < 2)
|
||||||
|
return;
|
||||||
|
for (size_t i = 0; i < crumbs.size() - 1; i++)
|
||||||
|
{
|
||||||
|
Vector wts1, wts2;
|
||||||
|
if (draw::WorldToScreen(crumbs[i], wts1) &&
|
||||||
|
draw::WorldToScreen(crumbs[i + 1], wts2))
|
||||||
|
{
|
||||||
|
glez::draw::line(wts1.x, wts1.y, wts2.x - wts1.x, wts2.y - wts1.y,
|
||||||
|
colors::white, 0.1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vector wts;
|
||||||
|
if (!draw::WorldToScreen(crumbs[0], wts))
|
||||||
|
return;
|
||||||
|
glez::draw::rect(wts.x - 4, wts.y - 4, 8, 8, colors::white);
|
||||||
|
glez::draw::rect_outline(wts.x - 4, wts.y - 4, 7, 7, colors::white, 1.0f);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
CatCommand navinit("nav_init", "Debug nav init", [](const CCommand &args) {
|
CatCommand navinit("nav_init", "Debug nav init", [](const CCommand &args) {
|
||||||
lastmap = "";
|
lastmap = "";
|
||||||
init = false;
|
init = false;
|
||||||
@ -407,7 +458,8 @@ CatCommand navprint("nav_print", "Debug nav print", [](const CCommand &args) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
CatCommand navfind("nav_find", "Debug nav find", [](const CCommand &args) {
|
CatCommand navfind("nav_find", "Debug nav find", [](const CCommand &args) {
|
||||||
std::vector<Vector> path = findPath(g_pLocalPlayer->v_Origin, loc);
|
int i1, i2;
|
||||||
|
std::vector<Vector> path = findPath(g_pLocalPlayer->v_Origin, loc, i1, i2);
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
{
|
{
|
||||||
logging::Info("Pathing: No path found");
|
logging::Info("Pathing: No path found");
|
||||||
|
@ -143,6 +143,10 @@ void DrawCheatVisuals()
|
|||||||
PROF_SECTION(DRAW_walkbot);
|
PROF_SECTION(DRAW_walkbot);
|
||||||
hacks::shared::walkbot::Draw();
|
hacks::shared::walkbot::Draw();
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
PROF_SECTION(DRAW_navparse);
|
||||||
|
nav::Draw();
|
||||||
|
}
|
||||||
IF_GAME(IsTF())
|
IF_GAME(IsTF())
|
||||||
{
|
{
|
||||||
PROF_SECTION(PT_antidisguise);
|
PROF_SECTION(PT_antidisguise);
|
||||||
|
Reference in New Issue
Block a user