From 126cd0028ea54933b8689de7a8f4452c9c79476d Mon Sep 17 00:00:00 2001 From: TotallyNotElite <1yourexperiment@protonmail.com> Date: Tue, 21 Aug 2018 17:54:54 +0200 Subject: [PATCH] Type 2 connections for navbot (vischeck) --- include/navparser.hpp | 224 ++++++++++++++++++++++++++++++++++++------ src/navparser.cpp | 223 ++++++++++++++--------------------------- 2 files changed, 269 insertions(+), 178 deletions(-) diff --git a/include/navparser.hpp b/include/navparser.hpp index aa89c629..e02ef230 100644 --- a/include/navparser.hpp +++ b/include/navparser.hpp @@ -24,32 +24,22 @@ bool Prepare(); void CreateMove(); void Draw(); -struct inactivityTracker +size_t FindInVector(size_t id); + +class inactivityTracker { // Map for storing inactivity per connection - std::map, unsigned int> inactives; - - void reset() + std::map, std::pair> inactives; + bool vischeckConnection(std::pair &connection) { - // inactives.clear(); + Vector begin = areas.at(FindInVector(connection.first)).m_center; + Vector end = areas.at(FindInVector(connection.second)).m_center; + begin.z += 72; + end.z += 72; + bool result = IsVectorVisible(begin, end, false); + return result; } - void addTime(std::pair connection, Timer &timer, - bool &resetPather) - { - if (inactives.find(connection) == inactives.end()) - { - inactives[connection] = 0; - } - inactives[connection] = - inactives[connection] + - (std::chrono::duration_cast( - std::chrono::system_clock::now() - timer.last) - .count()); - if (inactives[connection] >= 5000) - resetPather = true; - } - void addTime(std::pair connection, Timer &timer, - bool &resetPather) + std::pair VectorToId(std::pair &connection) { CNavArea *currnode = nullptr; for (size_t i = 0; i < areas.size(); i++) @@ -61,7 +51,7 @@ struct inactivityTracker } } if (!currnode) - return; + return { -1, -1 }; CNavArea *nextnode = nullptr; for (size_t i = 0; i < areas.size(); i++) @@ -73,21 +63,197 @@ struct inactivityTracker } } if (!nextnode) - return; + return { -1, -1 }; 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; + return { currnode->m_id, nextnode->m_id }; } } } - unsigned int getTime(std::pair connection) + +public: + void reset() + { + for (auto i : inactives) + { + // What is this tf + i.second.second = 0; + } + } + bool IsIgnored(std::pair connection) + { + if (inactives.find(connection) == inactives.end()) + { + return false; + } + auto &pair = inactives.at(connection); + if (pair.second >= 5000) + { + pair.first = 1; + return true; + } + if (pair.first == 2 && !vischeckConnection(connection)) + { + logging::Info( + "Ignored a connection due to type 2 connection type."); + return true; + } + return false; + } + + void AddTime(std::pair connection, Timer &timer, + bool &resetPather) + { + if (inactives.find(connection) == inactives.end()) + { + inactives[connection] = { 0, 0 }; + } + auto &pair = inactives.at(connection); + + pair.second = pair.second + + (std::chrono::duration_cast( + std::chrono::system_clock::now() - timer.last) + .count()); + if (pair.second >= 5000) + resetPather = true; + } + void AddTime(std::pair connection, Timer &timer, + bool &resetPather) + { + auto pair = VectorToId(connection); + if (pair.first == -1 || pair.second == -1) + return; + AddTime(pair, timer, resetPather); + } + bool CheckType2(std::pair connection) + { + // Fix calls vischeckConnection too often + if (inactives.find(connection) == inactives.end()) + { + inactives[connection] = { 0, 0 }; + } + auto pair = inactives.at(connection); + switch (pair.first) + { + case 0: + if (!vischeckConnection(connection)) + { + inactives[connection].first = 2; + return true; + } + case 1: + case 2: + return false; + } + } + bool CheckType2(std::pair connection) + { + auto pair = VectorToId(connection); + if (pair.first == -1 || pair.second == -1) + return false; + return CheckType2(pair); + } +}; // namespace nav + +struct MAP : public micropather::Graph +{ + std::unique_ptr pather; + // Maps already utilize dynamic allocation and we don't need a custom + // constructor + inactivityTracker inactiveTracker; + Vector GetClosestCornerToArea(CNavArea *CornerOf, CNavArea *Target) + { + std::array corners; + corners.at(0) = CornerOf->m_nwCorner; // NW + corners.at(1) = CornerOf->m_seCorner; // SE + corners.at(2) = Vector{ CornerOf->m_seCorner.x, CornerOf->m_nwCorner.y, + CornerOf->m_nwCorner.z }; // NE + corners.at(3) = Vector{ CornerOf->m_nwCorner.x, CornerOf->m_seCorner.y, + CornerOf->m_seCorner.z }; // SW + + Vector bestVec; + float bestDist = FLT_MAX; + + for (size_t i = 0; i < corners.size(); i++) + { + float dist = corners.at(i).DistTo(Target->m_center); + if (dist < bestDist) + { + bestVec = corners.at(i); + bestDist = dist; + } + } + + Vector bestVec2; + float bestDist2 = FLT_MAX; + + for (size_t i = 0; i < corners.size(); i++) + { + if (corners.at(i) == bestVec2) + continue; + float dist = corners.at(i).DistTo(Target->m_center); + if (dist < bestDist2) + { + bestVec2 = corners.at(i); + bestDist2 = dist; + } + } + return (bestVec + bestVec2) / 2; + } + + float GetZBetweenAreas(CNavArea *start, CNavArea *end) + { + float z1 = GetClosestCornerToArea(start, end).z; + float z2 = GetClosestCornerToArea(end, start).z; + + return z2 - z1; + } + // Function required by MicroPather for getting an estimated cost + float LeastCostEstimate(void *stateStart, void *stateEnd) + { + CNavArea *start = static_cast(stateStart); + CNavArea *end = static_cast(stateEnd); + float dist = start->m_center.DistTo(end->m_center); + return dist; + } + // Function required by MicroPather to retrieve neighbours and their + // associated costs. + void AdjacentCost(void *state, MP_VECTOR *adjacent) + { + CNavArea *area = static_cast(state); + auto &neighbours = area->m_connections; + for (auto i : neighbours) + { + if (GetZBetweenAreas(area, i.area) > 42) + continue; + if (inactiveTracker.IsIgnored( + std::pair{ area->m_id, i.area->m_id })) + continue; + micropather::StateCost cost; + cost.state = + static_cast(&areas.at(FindInVector(i.area->m_id))); + cost.cost = area->m_center.DistTo(i.area->m_center); + adjacent->push_back(cost); + } + } + void PrintStateInfo(void *state) + { + CNavArea *area = static_cast(state); + logging::Info(format(area->m_center.x, " ", area->m_center.y, " ", + area->m_center.z) + .c_str()); + } + MAP(size_t size) + { + pather = + std::make_unique(this, size, 6, true); + } + + ~MAP() { - return inactives[connection]; } }; diff --git a/src/navparser.cpp b/src/navparser.cpp index 758f5058..9872bfc8 100644 --- a/src/navparser.cpp +++ b/src/navparser.cpp @@ -8,12 +8,15 @@ std::vector areas; bool init = false; static bool pathfinding = true; bool ReadyForCommands = false; -inactivityTracker inactiveTracker; static settings::Bool enabled{ "misc.pathing", "true" }; static settings::Bool draw{ "misc.pathing.draw", "false" }; -static bool threadingFinished = false; +static std::atomic threadingFinished; -// Todo fix +static std::unique_ptr TF2MAP; + +// Function to get place in Vector by connection ID +// Todo: find an alternative for this, maybe a map for storing ptrs to the +// std::vector? size_t FindInVector(size_t id) { for (size_t i = 0; i < areas.size(); i++) @@ -23,110 +26,6 @@ size_t FindInVector(size_t id) } } -struct MAP : public micropather::Graph -{ - std::unique_ptr pather; - // Function to check if a connection is ignored - bool IsIgnored(size_t currState, size_t connectionID) - { - if (inactiveTracker.getTime({ currState, connectionID }) >= 5000) - return true; - return false; - } - Vector GetClosestCornerToArea(CNavArea *CornerOf, CNavArea *Target) - { - std::array corners; - corners.at(0) = CornerOf->m_nwCorner; // NW - corners.at(1) = CornerOf->m_seCorner; // SE - corners.at(2) = Vector{ CornerOf->m_seCorner.x, CornerOf->m_nwCorner.y, - CornerOf->m_nwCorner.z }; // NE - corners.at(3) = Vector{ CornerOf->m_nwCorner.x, CornerOf->m_seCorner.y, - CornerOf->m_seCorner.z }; // SW - - Vector bestVec; - float bestDist = FLT_MAX; - - for (size_t i = 0; i < corners.size(); i++) - { - float dist = corners.at(i).DistTo(Target->m_center); - if (dist < bestDist) - { - bestVec = corners.at(i); - bestDist = dist; - } - } - - Vector bestVec2; - float bestDist2 = FLT_MAX; - - for (size_t i = 0; i < corners.size(); i++) - { - if (corners.at(i) == bestVec2) - continue; - float dist = corners.at(i).DistTo(Target->m_center); - if (dist < bestDist2) - { - bestVec2 = corners.at(i); - bestDist2 = dist; - } - } - return (bestVec + bestVec2) / 2; - } - - float GetZBetweenAreas(CNavArea *start, CNavArea *end) - { - float z1 = GetClosestCornerToArea(start, end).z; - float z2 = GetClosestCornerToArea(end, start).z; - - return z2 - z1; - } - // Function required by MicroPather for getting an estimated cost - float LeastCostEstimate(void *stateStart, void *stateEnd) - { - CNavArea *start = static_cast(stateStart); - CNavArea *end = static_cast(stateEnd); - float dist = start->m_center.DistTo(end->m_center); - return dist; - } - // Function required by MicroPather to retrieve neighbours and their - // associated costs. - void AdjacentCost(void *state, MP_VECTOR *adjacent) - { - CNavArea *area = static_cast(state); - auto &neighbours = area->m_connections; - for (auto i : neighbours) - { - if (GetZBetweenAreas(area, i.area) > 42) - continue; - if (IsIgnored(area->m_id, i.area->m_id)) - continue; - micropather::StateCost cost; - cost.state = - static_cast(&areas.at(FindInVector(i.area->m_id))); - cost.cost = area->m_center.DistTo(i.area->m_center); - adjacent->push_back(cost); - } - } - void PrintStateInfo(void *state) - { - CNavArea *area = static_cast(state); - logging::Info(format(area->m_center.x, " ", area->m_center.y, " ", - area->m_center.z) - .c_str()); - } - MAP(size_t size) - { - pather = - std::make_unique(this, size, 6, true); - } - - ~MAP() - { - } -}; - -static std::unique_ptr TF2MAP; - void Init() { // Get NavFile location @@ -161,10 +60,11 @@ void Init() size = 7000; // Initiate "Map", contains micropather object TF2MAP = std::make_unique(size); + TF2MAP->inactiveTracker.reset(); } if (!areas.empty()) pathfinding = true; - threadingFinished = true; + threadingFinished.store(true); } static std::string lastmap; @@ -175,6 +75,7 @@ bool Prepare() return false; if (!init) { + // Don't reinit if same map if (lastmap == g_IEngine->GetLevelName()) { init = true; @@ -184,12 +85,14 @@ bool Prepare() lastmap = g_IEngine->GetLevelName(); pathfinding = false; init = true; - threadingFinished = false; + threadingFinished.store(false); + // Parsing CNavFile takes time, run it in a seperate thread std::thread initer(Init); + // We need to either detach or join to avoid std::terminate initer.detach(); } } - if (!pathfinding || !threadingFinished) + if (!pathfinding || !threadingFinished.load()) return false; return true; } @@ -211,7 +114,7 @@ int findClosestNavSquare(Vector vec) // Make sure we're not stuck on the same area for too long if (std::count(findClosestNavSquare_localAreas.begin(), findClosestNavSquare_localAreas.end(), i) < 3) - overlapping.emplace_back( i, &areas.at(i) ); + overlapping.emplace_back(i, &areas.at(i)); } } @@ -290,8 +193,8 @@ static Timer lastJump{}; static std::vector crumbs; // Bot will keep trying to get to the target even if it fails a few times static bool ensureArrival; -// Priority value for current instructions, only higher priority can overwrite -// itlocalAreas +// Priority value for current instructions, only higher or equal priorites can +// overwrite it int priority = 0; static Vector lastArea = { 0.0f, 0.0f, 0.0f }; @@ -315,12 +218,13 @@ bool NavTo(Vector dest, bool navToLocalCenter, bool persistent, if (!crumbs.empty()) { bool reset = false; - inactiveTracker.addTime({ lastArea, crumbs.at(0) }, inactivity, reset); + TF2MAP->inactiveTracker.AddTime({ lastArea, crumbs.at(0) }, inactivity, + reset); if (reset) TF2MAP->pather->Reset(); } crumbs.clear(); - crumbs = std::move(path); + crumbs = std::move(path); lastArea = crumbs.at(0); if (!navToLocalCenter && crumbs.size() > 1) crumbs.erase(crumbs.begin()); @@ -337,21 +241,43 @@ void clearInstructions() } static Timer ignoreReset{}; +static Timer patherReset{}; // Function for removing ignores void clearIgnores() { - if (ignoreReset.test_and_set(180000)) + if (!TF2MAP || !TF2MAP->pather) + return; + if (ignoreReset.test_and_set(120000)) + TF2MAP->inactiveTracker.reset(); + if (patherReset.test_and_set(30000)) + TF2MAP->pather->Reset(); +} + +void Repath() +{ + if (ensureArrival) { - inactiveTracker.reset(); - if (TF2MAP && TF2MAP->pather) - TF2MAP->pather->Reset(); + logging::Info("Pathing: NavBot inactive for too long. Ignoring " + "connection and finding another path..."); + // Throwaway int + int i1, i2; + // Find a new path + crumbs = findPath(g_pLocalPlayer->v_Origin, crumbs.back(), i1, i2); + } + else + { + logging::Info( + "Pathing: NavBot inactive for too long. Canceling tasks and " + "ignoring connection..."); + // Wait for new instructions + crumbs.clear(); } } // Main movement function, gets path from NavTo void CreateMove() { - if (!enabled || !threadingFinished) + if (!enabled || !threadingFinished.load()) return; if (CE_BAD(LOCAL_E)) return; @@ -386,30 +312,26 @@ void CreateMove() if (crumbs.at(0).z - g_pLocalPlayer->v_Origin.z > 18 && lastJump.test_and_set(200)) current_user_cmd->buttons |= IN_JUMP; + // Check if were dealing with a type 2 connection + if (inactivity.check(3000) && + TF2MAP->inactiveTracker.CheckType2({ lastArea, crumbs.at(0) })) + { + logging::Info("Pathing: Type 2 connection detected!"); + TF2MAP->pather->Reset(); + Repath(); + inactivity.update(); + return; + } // If inactive for too long if (inactivity.check(5000)) { // Ignore connection - bool i3 = false; - inactiveTracker.addTime({ lastArea, crumbs.at(0) }, inactivity, i3); - if (i3) + bool resetPather = false; + TF2MAP->inactiveTracker.AddTime({ lastArea, crumbs.at(0) }, inactivity, + resetPather); + if (resetPather) TF2MAP->pather->Reset(); - if (ensureArrival) - { - logging::Info("Pathing: NavBot inactive for too long. Ignoring " - "connection and finding another path..."); - // Find a new path - int i1, i2; - crumbs = findPath(g_pLocalPlayer->v_Origin, crumbs.back(), i1, i2); - } - else - { - logging::Info( - "Pathing: NavBot inactive for too long. Canceling tasks and " - "ignoring connection..."); - // Wait for new instructions - crumbs.clear(); - } + Repath(); inactivity.update(); return; } @@ -490,15 +412,18 @@ CatCommand navpath("nav_path", "Debug nav path", [](const CCommand &args) { } }); -CatCommand navpathnolocal("nav_path_nolocal", "Debug nav path", [](const CCommand &args) { - if (NavTo(loc, false, true, 50 + priority)) - { - logging::Info("Pathing: Success! Walking to path..."); - } - else - { - logging::Info("Pathing: Failed!"); - } -}); +// Clang format pls +CatCommand navpathnolocal("nav_path_nolocal", "Debug nav path", + [](const CCommand &args) { + if (NavTo(loc, false, true, 50 + priority)) + { + logging::Info( + "Pathing: Success! Walking to path..."); + } + else + { + logging::Info("Pathing: Failed!"); + } + }); } // namespace nav