From 99539955d9007b4c607e7c858c463f794ebccbc4 Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Sun, 23 Jul 2017 23:54:48 +0300 Subject: [PATCH 01/12] init walkbot --- src/drawmgr.cpp | 4 +++ src/hack.cpp | 2 +- src/hacks/Walkbot.cpp | 60 ++++++++++++++++++++++++++++++++++++++++ src/hacks/Walkbot.hpp | 16 +++++++++++ src/hooks/CreateMove.cpp | 4 +++ 5 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/hacks/Walkbot.cpp create mode 100644 src/hacks/Walkbot.hpp diff --git a/src/drawmgr.cpp b/src/drawmgr.cpp index c8f20ddf..d6af567e 100644 --- a/src/drawmgr.cpp +++ b/src/drawmgr.cpp @@ -71,6 +71,10 @@ void DrawCheatVisuals() { PROF_SECTION(DRAW_healarrows); hacks::tf2::healarrow::Draw(); } + { + PROF_SECTION(DRAW_walkbot); + hacks::shared::walkbot::Draw(); + } IF_GAME(IsTF()) { PROF_SECTION(PT_antidisguise); SAFE_CALL(hacks::tf2::antidisguise::Draw()); diff --git a/src/hack.cpp b/src/hack.cpp index 5a107fa1..a71cc330 100644 --- a/src/hack.cpp +++ b/src/hack.cpp @@ -276,7 +276,7 @@ void hack::Initialize() { hacks::shared::spam::Init(); backpacktf::init(); logging::Info("Initialized Backpack.TF integration"); - + hacks::shared::walkbot::Initialize(); } void hack::Think() { diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp new file mode 100644 index 00000000..082b56ff --- /dev/null +++ b/src/hacks/Walkbot.cpp @@ -0,0 +1,60 @@ +/* + * Walkbot.cpp + * + * Created on: Jul 23, 2017 + * Author: nullifiedcat + */ + +#include "../common.h" + +namespace hacks { namespace shared { namespace walkbot { + +enum ENodeFlags { + NF_GOOD = (1 << 0), + NF_DUCK = (1 << 1), + NF_JUMP = (1 << 2) +}; + +struct walkbot_node_s { + float x { 0.0f }; // 4 + float y { 0.0f }; // 8 + float z { 0.0f }; // 12 + int flags { 0 }; // 16 + int prev { 0 }; // 20 + int next { 0 }; // 24 +}; // 24 + +enum EWalkbotState { + WB_DISABLED, + WB_RECORDING, + WB_EDITING, + WB_REPLAYING +}; + +EWalkbotState state { WB_DISABLED }; + +CatVar pause_recording(CV_SWITCH, "wb_recording_paused", "0", "Pause recording", "Use BindToggle with this"); +CatVar draw_info(CV_SWITCH, "wb_info", "1", "Walkbot info"); +CatVar draw_path(CV_SWITCH, "wb_path", "1", "Walkbot path"); + +void Initialize() { +} + +void Draw() { + if (state == WB_DISABLED) return; + switch (state) { + case WB_RECORDING: { + + } + case WB_REPLAYING: { + + } + } +} + +void Move() { + if (state == WB_DISABLED) return; + +} + +}}} diff --git a/src/hacks/Walkbot.hpp b/src/hacks/Walkbot.hpp new file mode 100644 index 00000000..59c0e526 --- /dev/null +++ b/src/hacks/Walkbot.hpp @@ -0,0 +1,16 @@ +/* + * Walkbot.hpp + * + * Created on: Jul 23, 2017 + * Author: nullifiedcat + */ + +#pragma once + +namespace hacks { namespace shared { namespace walkbot { + +void Initialize(); +void Draw(); +void Move(); + +}}} diff --git a/src/hooks/CreateMove.cpp b/src/hooks/CreateMove.cpp index 2d922652..eb8b2d94 100644 --- a/src/hooks/CreateMove.cpp +++ b/src/hooks/CreateMove.cpp @@ -267,6 +267,10 @@ bool CreateMove_hook(void* thisptr, float inputSample, CUserCmd* cmd) { SAFE_CALL(hacks::shared::esp::CreateMove()); } if (!g_pLocalPlayer->life_state && CE_GOOD(g_pLocalPlayer->weapon())) { + { + PROF_SECTION(CM_walkbot); + SAFE_CALL(hacks::shared::walkbot::Move()); + } IF_GAME (IsTF()) { PROF_SECTION(CM_uberspam); SAFE_CALL(hacks::tf::uberspam::CreateMove()); From 7cce548c6c349d55cd64b7260a6cff4787bc49e4 Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Mon, 24 Jul 2017 00:06:40 +0300 Subject: [PATCH 02/12] added header --- src/hacks/Walkbot.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index 082b56ff..af451ffd 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -9,19 +9,27 @@ namespace hacks { namespace shared { namespace walkbot { +constexpr unsigned INVALID_NODE = unsigned(-1); + enum ENodeFlags { NF_GOOD = (1 << 0), NF_DUCK = (1 << 1), NF_JUMP = (1 << 2) }; +struct walkbot_header_s { + unsigned version { 1 }; + unsigned node_count { 0 }; + unsigned first_node { 0 }; +}; + struct walkbot_node_s { float x { 0.0f }; // 4 float y { 0.0f }; // 8 float z { 0.0f }; // 12 - int flags { 0 }; // 16 - int prev { 0 }; // 20 - int next { 0 }; // 24 + unsigned flags { 0 }; // 16 + unsigned prev { 0 }; // 20 + unsigned next { 0 }; // 24 }; // 24 enum EWalkbotState { @@ -44,11 +52,17 @@ void Draw() { if (state == WB_DISABLED) return; switch (state) { case WB_RECORDING: { + AddSideString("Walkbot: Recording"); - } + } break; + case WB_EDITING: { + AddSideString("Walkbot: Editing"); + + } break; case WB_REPLAYING: { + AddSideString("Walkbot: Replaying"); - } + } break; } } From 12f333857a21b258f66a3511af31dcb9ffe16462 Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Mon, 24 Jul 2017 08:46:14 +0300 Subject: [PATCH 03/12] drawing functions --- src/hacks/Walkbot.cpp | 130 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 112 insertions(+), 18 deletions(-) diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index af451ffd..8c7794a5 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -9,7 +9,10 @@ namespace hacks { namespace shared { namespace walkbot { -constexpr unsigned INVALID_NODE = unsigned(-1); +using index_t = unsigned; + +constexpr index_t INVALID_NODE = unsigned(-1); +constexpr size_t MAX_CONNECTIONS = 4; enum ENodeFlags { NF_GOOD = (1 << 0), @@ -17,21 +20,6 @@ enum ENodeFlags { NF_JUMP = (1 << 2) }; -struct walkbot_header_s { - unsigned version { 1 }; - unsigned node_count { 0 }; - unsigned first_node { 0 }; -}; - -struct walkbot_node_s { - float x { 0.0f }; // 4 - float y { 0.0f }; // 8 - float z { 0.0f }; // 12 - unsigned flags { 0 }; // 16 - unsigned prev { 0 }; // 20 - unsigned next { 0 }; // 24 -}; // 24 - enum EWalkbotState { WB_DISABLED, WB_RECORDING, @@ -39,18 +27,124 @@ enum EWalkbotState { WB_REPLAYING }; +struct walkbot_header_s { + unsigned version { 1 }; + unsigned node_count { 0 }; +}; + +struct walkbot_node_s { + union { + struct { + float x { 0.0f }; // 4 + float y { 0.0f }; // 8 + float z { 0.0f }; // 12 + }; + Vector xyz { 0, 0, 0 }; + }; + unsigned flags { 0 }; // 16 + size_t connection_count { 0 }; // 20 + index_t connections[MAX_CONNECTIONS]; // 36 +}; // 36 + +namespace state { + +// A vector containing all loaded nodes, used in both recording and replaying +std::vector nodes {}; + +// Target node when replaying, selected node when editing, last node when recording +index_t active_node { INVALID_NODE }; + +// Node closest to your crosshair when editing +index_t closest_node { INVALID_NODE }; + +// Global state EWalkbotState state { WB_DISABLED }; +bool node_good(index_t node) { + return node < nodes.size() && (nodes[node].flags & NF_GOOD); +} + +} + CatVar pause_recording(CV_SWITCH, "wb_recording_paused", "0", "Pause recording", "Use BindToggle with this"); CatVar draw_info(CV_SWITCH, "wb_info", "1", "Walkbot info"); CatVar draw_path(CV_SWITCH, "wb_path", "1", "Walkbot path"); +CatVar draw_nodes(CV_SWITCH, "wb_nodes", "1", "Walkbot nodes"); +CatVar draw_indices(CV_SWITCH, "wb_indices", "1", "Node indices"); void Initialize() { } +// Draws a single colored connection between 2 nodes +void DrawConnection(index_t a, index_t b) { + if (not (state::node_good(a) and state::node_good(b))) + return; + + const auto& a_ = state::nodes[a]; + const auto& b_ = state::nodes[b]; + + Vector wts_a, wts_b; + if (not (draw::WorldToScreen(a_.xyz, wts_a) and draw::WorldToScreen(b_.xyz, wts_b))) + return; + + rgba_t* color = &colors::white; + if ((a_.flags & b_.flags) & NF_JUMP) color = &colors::yellow; + else if ((a_.flags & b_.flags) & NF_DUCK) color = &colors::green; + + drawgl::Line(wts_a.x, wts_a.y, wts_b.x - wts_a.x, wts_b.y - wts_a.y, color->rgba); +} + +// Draws a node and its connections +void DrawNode(index_t node, bool draw_back) { + if (not state::node_good(node)) + return; + + const auto& n = state::nodes[node]; + + for (size_t i = 0; i < n.connection_count && i < MAX_CONNECTIONS; i++) { + index_t connection = n.connections[i]; + // To prevent drawing connections twice in a for loop, we only draw connections to nodes with higher index + if (not draw_back) { + if (connection < node) + continue; + } + DrawConnection(node, connection); + } + + if (draw_nodes) { + rgba_t* color = &colors::white; + if (n.flags & NF_JUMP) color = &colors::yellow; + else if (n.flags & NF_DUCK) color = &colors::green; + + Vector wts; + if (not draw::WorldToScreen(n.xyz, wts)) + return; + + drawgl::Rect(wts.x - 2, wts.y - 2, 4, 4, color->rgba); + } + + if (draw_indices) { + rgba_t* color = &colors::white; + if (n.flags & NF_JUMP) color = &colors::yellow; + else if (n.flags & NF_DUCK) color = &colors::green; + + Vector wts; + if (not draw::WorldToScreen(n.xyz, wts)) + return; + + FTGL_Draw(std::to_string(node), wts.x, wts.y, fonts::ftgl_ESP, *color); + } +} + +void DrawPath() { + for (index_t i = 0; i < state::nodes.size(); i++) { + + } +} + void Draw() { - if (state == WB_DISABLED) return; - switch (state) { + if (state::state == WB_DISABLED) return; + switch (state::state) { case WB_RECORDING: { AddSideString("Walkbot: Recording"); From 95753ce4cc65b04835aa628cd3361fee61bc2fb6 Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Mon, 24 Jul 2017 08:53:56 +0300 Subject: [PATCH 04/12] free_node --- src/hacks/Walkbot.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index 8c7794a5..e3c7e80c 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -60,6 +60,17 @@ index_t closest_node { INVALID_NODE }; // Global state EWalkbotState state { WB_DISABLED }; +// A little bit too expensive function, finds next free node or creates one if no free slots exist +index_t free_node() { + for (index_t i = 0; i < nodes.size(); i++) { + if (not (nodes[i].flags & NF_GOOD)) + return i; + } + + nodes.emplace_back(); + return nodes.size() - 1; +} + bool node_good(index_t node) { return node < nodes.size() && (nodes[node].flags & NF_GOOD); } @@ -138,7 +149,7 @@ void DrawNode(index_t node, bool draw_back) { void DrawPath() { for (index_t i = 0; i < state::nodes.size(); i++) { - + DrawNode(i, false); } } From 9eb782b77ca272182582b28aa765b6316f518256 Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Mon, 24 Jul 2017 09:03:28 +0300 Subject: [PATCH 05/12] UpdateClosestNode --- src/hacks/Walkbot.cpp | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index e3c7e80c..c1e30191 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -86,6 +86,30 @@ CatVar draw_indices(CV_SWITCH, "wb_indices", "1", "Node indices"); void Initialize() { } +void UpdateClosestNode() { + float n_fov = 360.0f; + index_t n_idx = INVALID_NODE; + + for (index_t i = 0; i < state::nodes.size(); i++) { + const auto& node = state::nodes[i]; + + if (not node.flags & NF_GOOD) + continue; + + float fov = GetFov(g_pLocalPlayer->v_OrigViewangles, g_pLocalPlayer->v_Eye, node.xyz); + if (fov < n_fov) { + n_fov = fov; + n_idx = i; + } + } + + // Don't select a node if you don't even look at it + if (n_fov < 10) + state::closest_node = n_idx; + else + state::closest_node = INVALID_NODE; +} + // Draws a single colored connection between 2 nodes void DrawConnection(index_t a, index_t b) { if (not (state::node_good(a) and state::node_good(b))) @@ -131,7 +155,13 @@ void DrawNode(index_t node, bool draw_back) { if (not draw::WorldToScreen(n.xyz, wts)) return; - drawgl::Rect(wts.x - 2, wts.y - 2, 4, 4, color->rgba); + size_t node_size = 2; + if (node == state::closest_node) + node_size = 4; + if (node == state::active_node) + color = &colors::red; + + drawgl::Rect(wts.x - node_size, wts.y - node_size, 2 * node_size, 2 * node_size, color->rgba); } if (draw_indices) { From f3cc9ee4d9fe750f1d3988c51dc4b6540192d50f Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Mon, 24 Jul 2017 10:17:17 +0300 Subject: [PATCH 06/12] create, delete, select --- src/hacks/Walkbot.cpp | 92 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 4 deletions(-) diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index c1e30191..8b5849d2 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -39,12 +39,30 @@ struct walkbot_node_s { float y { 0.0f }; // 8 float z { 0.0f }; // 12 }; - Vector xyz { 0, 0, 0 }; + Vector xyz { 0, 0, 0 }; // 12 }; unsigned flags { 0 }; // 16 size_t connection_count { 0 }; // 20 index_t connections[MAX_CONNECTIONS]; // 36 -}; // 36 + index_t preferred { INVALID_NODE }; // 40 + + void link(index_t node) { + if (connection_count == MAX_CONNECTIONS) { + logging::Info("[wb] Too many connections! Node at (%.2f %.2f %.2f)", x, y, z); + return; + } + connections[connection_count++] = node; + } + + void unlink(index_t node) { + for (size_t i = 0; i < connection_count; i++) { + if (connections[i] == node) { + connections[i] = connections[connection_count]; + connections[connection_count--] = INVALID_NODE; + } + } + } +}; // 40 namespace state { @@ -60,6 +78,9 @@ index_t closest_node { INVALID_NODE }; // Global state EWalkbotState state { WB_DISABLED }; +// g_pUserCmd->buttons state when last node was recorded +int last_node_buttons { 0 }; + // A little bit too expensive function, finds next free node or creates one if no free slots exist index_t free_node() { for (index_t i = 0; i < nodes.size(); i++) { @@ -72,7 +93,7 @@ index_t free_node() { } bool node_good(index_t node) { - return node < nodes.size() && (nodes[node].flags & NF_GOOD); + return node != INVALID_NODE && node < nodes.size() && (nodes[node].flags & NF_GOOD); } } @@ -83,6 +104,59 @@ CatVar draw_path(CV_SWITCH, "wb_path", "1", "Walkbot path"); CatVar draw_nodes(CV_SWITCH, "wb_nodes", "1", "Walkbot nodes"); CatVar draw_indices(CV_SWITCH, "wb_indices", "1", "Node indices"); +// Selects closest node, clears selection if node is selected +CatCommand c_select_node("wb_select", "Select node", []() { + if (state::active_node == state::closest_node) { + state::active_node = INVALID_NODE; + } else { + state::active_node = state::closest_node; + } +}); +// Deletes closest node and its connections +CatCommand c_delete_node("wb_delete", "Delete node", []() { + if (not state::node_good(state::closest_node)) + return; + logging::Info("[wb] Deleting node %u", state::closest_node); + auto& n = state::nodes[state::closest_node]; + for (size_t i = 0; i < n.connection_count && i < MAX_CONNECTIONS; i++) { + if (state::node_good(n.connections[i])) { + logging::Info("[wb] Unlinking %u from %u", state::closest_node, n.connections[i]); + state::nodes[n.connections[i]].unlink(state::closest_node); + } + } + memset(&n, 0, sizeof(walkbot_node_s)); +}); +// Creates a new node under your feet and connects it to closest node to your crosshair +CatCommand c_create_node("wb_create", "Create node", []() { + const Vector& origin = LOCAL_E->m_vecOrigin; + index_t node = state::free_node(); + logging::Info("[wb] Creating node %u at (%.2f %.2f %.2f)", node, origin.x, origin.y, origin.z); + auto& n = state::nodes[node]; + n.xyz = origin; + n.preferred = INVALID_NODE; + n.connection_count = 0; + n.flags |= NF_GOOD; + if (g_pUserCmd->buttons & IN_DUCK) + n.flags |= NF_DUCK; + if (state::node_good(state::closest_node)) { + n.link(state::closest_node); + state::nodes[state::closest_node].link(node); + } +}); +// Connects selected node to closest one +CatCommand c_connect_node("wb_connect", "Connect node", []() { + +}); +// Updates flags on region of nodes (selected to closest) +// Updates a single closest node if no node is selected +CatCommand c_update_flags("wb_flags", "Update flags", []() { + +}); +// Sets the closest node as preferred path for the selected node +CatCommand c_set_preferred("wb_prefer", "Set preferred node", []() { + +}); + void Initialize() { } @@ -202,8 +276,18 @@ void Draw() { } void Move() { - if (state == WB_DISABLED) return; + if (state::state == WB_DISABLED) return; + switch (state::state) { + case WB_RECORDING: { + } break; + case WB_EDITING: { + UpdateClosestNode(); + } break; + case WB_REPLAYING: { + + } break; + } } }}} From f8a1926a23112b94e20ab8cfc69e288161f4631a Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Mon, 24 Jul 2017 10:35:40 +0300 Subject: [PATCH 07/12] all commands done --- src/hacks/Walkbot.cpp | 88 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 5 deletions(-) diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index 8b5849d2..19c4a93e 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -139,22 +139,97 @@ CatCommand c_create_node("wb_create", "Create node", []() { if (g_pUserCmd->buttons & IN_DUCK) n.flags |= NF_DUCK; if (state::node_good(state::closest_node)) { + auto& c = state::nodes[state::closest_node]; n.link(state::closest_node); - state::nodes[state::closest_node].link(node); + c.link(node); + logging::Info("[wb] Node %u linked to node %u at (%.2f %.2f %.2f)", node, state::closest_node, c.x, c.y, c.z); } }); // Connects selected node to closest one CatCommand c_connect_node("wb_connect", "Connect node", []() { + if (not (state::node_good(state::active_node) and state::node_good(state::closest_node))) + return; + // Don't link a node to itself, idiot + if (state::active_node == state::closest_node) + return; + auto& a = state::nodes[state::active_node]; + auto& b = state::nodes[state::closest_node]; + + a.link(state::closest_node); + b.link(state::active_node); }); -// Updates flags on region of nodes (selected to closest) +// Updates duck flag on region of nodes (selected to closest) // Updates a single closest node if no node is selected -CatCommand c_update_flags("wb_flags", "Update flags", []() { +CatCommand c_update_duck("wb_duck", "Update duck flags", []() { + index_t a = state::active_node; + index_t b = state::closest_node; + if (not (state::node_good(a) and state::node_good(b))) + return; + + index_t current = state::closest_node; + + do { + auto& n = state::nodes[current]; + if (g_pUserCmd->buttons & IN_DUCK) + n.flags |= NF_DUCK; + else + n.flags &= ~NF_DUCK; + if (n.connection_count > 2) { + logging::Info("[wb] More than 2 connections on a node - instructions unclear, got my duck stuck in 'if' block"); + return; + } + bool found_next = false; + for (size_t i = 0; i < 2; i++) { + if (n.connections[i] != current) { + current = n.connections[i]; + found_next = true; + break; + } + } + if (not found_next) { + logging::Info("[wb] Dead end? Can't find next node after %u", current); + break; + } + } while (state::node_good(current) and (current != a)); }); -// Sets the closest node as preferred path for the selected node -CatCommand c_set_preferred("wb_prefer", "Set preferred node", []() { +// Toggles jump flag on closest node +CatCommand c_update_jump("wb_jump", "Toggle jump flag", []() { + if (not state::node_good(state::closest_node)) + return; + auto& n = state::nodes[state::closest_node]; + + if (n.flags & NF_JUMP) + n.flags &= ~NF_JUMP; + else + n.flags |= NF_JUMP; +}); +// Sets the closest node as preferred path for the selected node (or disable it) +CatCommand c_set_preferred("wb_prefer", "Set preferred node", []() { + index_t a = state::active_node; + index_t b = state::closest_node; + + if (not (state::node_good(a) and state::node_good(b))) + return; + + auto& n = state::nodes[a]; + if (n.preferred == b) { + n.preferred = INVALID_NODE; + return; + } + + bool found = false; + for (size_t i = 0; i < n.connection_count; i++) { + if (n.connections[i] == b) { + if (found) { + logging::Info("[wb] WARNING!!! Duplicate connection to %u on node %u!!!", a, b); + } + found = true; + } + } + n.preferred = b; }); void Initialize() { @@ -200,6 +275,9 @@ void DrawConnection(index_t a, index_t b) { if ((a_.flags & b_.flags) & NF_JUMP) color = &colors::yellow; else if ((a_.flags & b_.flags) & NF_DUCK) color = &colors::green; + if (a_.preferred == b or b_.preferred == a) + color = &colors::pink; + drawgl::Line(wts_a.x, wts_a.y, wts_b.x - wts_a.x, wts_b.y - wts_a.y, color->rgba); } From 0e64c1e02407c0eea58b27d2b42915d1768d2a3a Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Mon, 24 Jul 2017 11:05:32 +0300 Subject: [PATCH 08/12] fix compile errors (non-trivial Vector in union) --- src/hacks/Walkbot.cpp | 96 ++++++++++++++++++++++++++++++++----------- src/hacks/hacklist.h | 1 + 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index 19c4a93e..3c4beb03 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -33,19 +33,20 @@ struct walkbot_header_s { }; struct walkbot_node_s { - union { - struct { - float x { 0.0f }; // 4 - float y { 0.0f }; // 8 - float z { 0.0f }; // 12 - }; - Vector xyz { 0, 0, 0 }; // 12 + struct { + float x { 0 }; // 4 + float y { 0 }; // 8 + float z { 0 }; // 12 }; unsigned flags { 0 }; // 16 size_t connection_count { 0 }; // 20 index_t connections[MAX_CONNECTIONS]; // 36 index_t preferred { INVALID_NODE }; // 40 + Vector& xyz() { + return *reinterpret_cast(&x); + } + void link(index_t node) { if (connection_count == MAX_CONNECTIONS) { logging::Info("[wb] Too many connections! Node at (%.2f %.2f %.2f)", x, y, z); @@ -98,11 +99,28 @@ bool node_good(index_t node) { } -CatVar pause_recording(CV_SWITCH, "wb_recording_paused", "0", "Pause recording", "Use BindToggle with this"); +index_t CreateNode(const Vector& xyz) { + index_t node = state::free_node(); + logging::Info("[wb] Creating node %u at (%.2f %.2f %.2f)", node, xyz.x, xyz.y, xyz.z); + auto& n = state::nodes[node]; + n.xyz() = xyz; + n.preferred = INVALID_NODE; + n.connection_count = 0; + n.flags |= NF_GOOD; + return node; +} + +CatVar active_recording(CV_SWITCH, "wb_recording", "0", "Do recording", "Use BindToggle with this"); CatVar draw_info(CV_SWITCH, "wb_info", "1", "Walkbot info"); CatVar draw_path(CV_SWITCH, "wb_path", "1", "Walkbot path"); CatVar draw_nodes(CV_SWITCH, "wb_nodes", "1", "Walkbot nodes"); CatVar draw_indices(CV_SWITCH, "wb_indices", "1", "Node indices"); +CatVar spawn_distance(CV_FLOAT, "wb_node_spawn_distance", "32", "Node spawn distance"); + +CatCommand c_start_recording("wb_record", "Start recording", []() { state::state = WB_RECORDING; }); +CatCommand c_start_editing("wb_edit", "Start editing", []() { state::state = WB_EDITING; }); +CatCommand c_start_replaying("wb_replay", "Start replaying", []() { state::state = WB_REPLAYING; }); +CatCommand c_exit("wb_exit", "Exit", []() { state::state = WB_DISABLED; }); // Selects closest node, clears selection if node is selected CatCommand c_select_node("wb_select", "Select node", []() { @@ -128,14 +146,8 @@ CatCommand c_delete_node("wb_delete", "Delete node", []() { }); // Creates a new node under your feet and connects it to closest node to your crosshair CatCommand c_create_node("wb_create", "Create node", []() { - const Vector& origin = LOCAL_E->m_vecOrigin; - index_t node = state::free_node(); - logging::Info("[wb] Creating node %u at (%.2f %.2f %.2f)", node, origin.x, origin.y, origin.z); + index_t node = CreateNode(g_pLocalPlayer->v_Origin); auto& n = state::nodes[node]; - n.xyz = origin; - n.preferred = INVALID_NODE; - n.connection_count = 0; - n.flags |= NF_GOOD; if (g_pUserCmd->buttons & IN_DUCK) n.flags |= NF_DUCK; if (state::node_good(state::closest_node)) { @@ -245,7 +257,7 @@ void UpdateClosestNode() { if (not node.flags & NF_GOOD) continue; - float fov = GetFov(g_pLocalPlayer->v_OrigViewangles, g_pLocalPlayer->v_Eye, node.xyz); + float fov = GetFov(g_pLocalPlayer->v_OrigViewangles, g_pLocalPlayer->v_Eye, node.xyz()); if (fov < n_fov) { n_fov = fov; n_idx = i; @@ -268,7 +280,7 @@ void DrawConnection(index_t a, index_t b) { const auto& b_ = state::nodes[b]; Vector wts_a, wts_b; - if (not (draw::WorldToScreen(a_.xyz, wts_a) and draw::WorldToScreen(b_.xyz, wts_b))) + if (not (draw::WorldToScreen(a_.xyz(), wts_a) and draw::WorldToScreen(b_.xyz(), wts_b))) return; rgba_t* color = &colors::white; @@ -304,7 +316,7 @@ void DrawNode(index_t node, bool draw_back) { else if (n.flags & NF_DUCK) color = &colors::green; Vector wts; - if (not draw::WorldToScreen(n.xyz, wts)) + if (not draw::WorldToScreen(n.xyz(), wts)) return; size_t node_size = 2; @@ -322,13 +334,50 @@ void DrawNode(index_t node, bool draw_back) { else if (n.flags & NF_DUCK) color = &colors::green; Vector wts; - if (not draw::WorldToScreen(n.xyz, wts)) + if (not draw::WorldToScreen(n.xyz(), wts)) return; FTGL_Draw(std::to_string(node), wts.x, wts.y, fonts::ftgl_ESP, *color); } } +bool ShouldSpawnNode() { + if (not state::node_good(state::active_node)) + return true; + + bool was_jumping = state::last_node_buttons & IN_JUMP; + bool is_jumping = g_pUserCmd->buttons & IN_JUMP; + + if (was_jumping != is_jumping and is_jumping) + return true; + + if ((state::last_node_buttons & IN_DUCK) != (g_pUserCmd->buttons & IN_DUCK)) + return true; + + auto& node = state::nodes[state::active_node]; + + if (node.xyz().DistTo(g_pLocalPlayer->v_Origin) > float(spawn_distance)) { + return true; + } + + return false; +} + +void RecordNode() { + index_t node = CreateNode(g_pLocalPlayer->v_Origin); + auto& n = state::nodes[node]; + if (g_pUserCmd->buttons & IN_DUCK) + n.flags |= NF_DUCK; + if (state::node_good(state::active_node)) { + auto& c = state::nodes[state::active_node]; + n.link(state::active_node); + c.link(node); + logging::Info("[wb] Node %u auto-linked to node %u at (%.2f %.2f %.2f)", node, state::active_node, c.x, c.y, c.z); + } + state::last_node_buttons = g_pUserCmd->buttons; + state::active_node = node; +} + void DrawPath() { for (index_t i = 0; i < state::nodes.size(); i++) { DrawNode(i, false); @@ -340,24 +389,25 @@ void Draw() { switch (state::state) { case WB_RECORDING: { AddSideString("Walkbot: Recording"); - } break; case WB_EDITING: { AddSideString("Walkbot: Editing"); - } break; case WB_REPLAYING: { AddSideString("Walkbot: Replaying"); - } break; } + if (draw_path) + DrawPath(); } void Move() { if (state::state == WB_DISABLED) return; switch (state::state) { case WB_RECORDING: { - + if (active_recording and ShouldSpawnNode()) { + RecordNode(); + } } break; case WB_EDITING: { UpdateClosestNode(); diff --git a/src/hacks/hacklist.h b/src/hacks/hacklist.h index ad061db0..8dcaffbb 100644 --- a/src/hacks/hacklist.h +++ b/src/hacks/hacklist.h @@ -18,6 +18,7 @@ #include "Bunnyhop.h" #include "ESP.h" #include "LagExploit.hpp" +#include "Walkbot.hpp" #include "AntiBackstab.hpp" #include "AutoBackstab.hpp" #include "FollowBot.h" From 2bdc478b85f2f0c2be8818e6d63dbb3f1e6bbc53 Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Mon, 24 Jul 2017 11:55:44 +0300 Subject: [PATCH 09/12] walking? --- src/hacks/Walkbot.cpp | 176 ++++++++++++++++++++++++++++++++++++++---- src/helpers.cpp | 22 ++++++ src/helpers.h | 3 + 3 files changed, 187 insertions(+), 14 deletions(-) diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index 3c4beb03..e0a0657b 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -73,6 +73,9 @@ std::vector nodes {}; // Target node when replaying, selected node when editing, last node when recording index_t active_node { INVALID_NODE }; +// Last reached node when replaying +index_t last_node { INVALID_NODE }; + // Node closest to your crosshair when editing index_t closest_node { INVALID_NODE }; @@ -82,6 +85,9 @@ EWalkbotState state { WB_DISABLED }; // g_pUserCmd->buttons state when last node was recorded int last_node_buttons { 0 }; +// Set to true when bot is moving to nearest node after dying/losing its active node +bool recovery { true }; + // A little bit too expensive function, finds next free node or creates one if no free slots exist index_t free_node() { for (index_t i = 0; i < nodes.size(); i++) { @@ -99,6 +105,19 @@ bool node_good(index_t node) { } +void DeleteNode(index_t node) { + if (not state::node_good(node)) + return; + logging::Info("[wb] Deleting node %u", node); + auto& n = state::nodes[node]; + for (size_t i = 0; i < n.connection_count && i < MAX_CONNECTIONS; i++) { + if (state::node_good(n.connections[i])) { + state::nodes[n.connections[i]].unlink(state::closest_node); + } + } + memset(&n, 0, sizeof(walkbot_node_s)); +} + index_t CreateNode(const Vector& xyz) { index_t node = state::free_node(); logging::Info("[wb] Creating node %u at (%.2f %.2f %.2f)", node, xyz.x, xyz.y, xyz.z); @@ -116,6 +135,8 @@ CatVar draw_path(CV_SWITCH, "wb_path", "1", "Walkbot path"); CatVar draw_nodes(CV_SWITCH, "wb_nodes", "1", "Walkbot nodes"); CatVar draw_indices(CV_SWITCH, "wb_indices", "1", "Node indices"); CatVar spawn_distance(CV_FLOAT, "wb_node_spawn_distance", "32", "Node spawn distance"); +CatVar max_distance(CV_FLOAT, "wb_replay_max_distance", "80", "Max distance to node when replaying"); +CatVar reach_distance(CV_FLOAT, "wb_replay_reach_distance", "16", "Distance where bot can be considered 'stepping' on the node"); CatCommand c_start_recording("wb_record", "Start recording", []() { state::state = WB_RECORDING; }); CatCommand c_start_editing("wb_edit", "Start editing", []() { state::state = WB_EDITING; }); @@ -132,17 +153,7 @@ CatCommand c_select_node("wb_select", "Select node", []() { }); // Deletes closest node and its connections CatCommand c_delete_node("wb_delete", "Delete node", []() { - if (not state::node_good(state::closest_node)) - return; - logging::Info("[wb] Deleting node %u", state::closest_node); - auto& n = state::nodes[state::closest_node]; - for (size_t i = 0; i < n.connection_count && i < MAX_CONNECTIONS; i++) { - if (state::node_good(n.connections[i])) { - logging::Info("[wb] Unlinking %u from %u", state::closest_node, n.connections[i]); - state::nodes[n.connections[i]].unlink(state::closest_node); - } - } - memset(&n, 0, sizeof(walkbot_node_s)); + DeleteNode(state::closest_node); }); // Creates a new node under your feet and connects it to closest node to your crosshair CatCommand c_create_node("wb_create", "Create node", []() { @@ -243,6 +254,68 @@ CatCommand c_set_preferred("wb_prefer", "Set preferred node", []() { } n.preferred = b; }); +// Displays all info about closest node +CatCommand c_info("wb_info", "Show info", []() { + if (not state::node_good(state::closest_node)) + return; + + auto& n = state::nodes[state::closest_node]; + + logging::Info("[wb] Info about node %u", state::closest_node); + logging::Info("[wb] FLAGS: Duck: %d, Jump: %d, Raw: %u", n.flags & NF_DUCK, n.flags & NF_JUMP, n.flags); + logging::Info("[wb] X: %.2f | Y: %.2f | Z: %.2f", n.x, n.y, n.z); + logging::Info("[wb] CONNECTIONS: %d/%d", n.connection_count, MAX_CONNECTIONS); + for (size_t i = 0; i < n.connection_count; i++) { + logging::Info("[wb] %u <-> %u", state::closest_node, n.connections[i]); + auto& c = state::nodes[n.connections[i]]; + bool found = false; + for (size_t j = 0; j < c.connection_count; j++) { + if (c.connections[j] == state::closest_node) { + if (found) { + logging::Info("[wb] DUPLICATE CONNECTION: %u <-> %u", i, state::closest_node); + } + found = true; + } + } + if (not found) { + logging::Info("[wb] CONNECTION IS SINGLE-DIRECTIONAL (BROKEN)! (%u)", i); + } + } +}); +// Deletes a whole region of nodes +// Deletes a single closest node if no node is selected +CatCommand c_delete_region("wb_delete_region", "Delete region of nodes", []() { + index_t a = state::active_node; + index_t b = state::closest_node; + + if (not (state::node_good(a) and state::node_good(b))) + return; + + index_t current = state::closest_node; + index_t next = INVALID_NODE; + + do { + auto& n = state::nodes[current]; + + if (n.connection_count > 2) { + logging::Info("[wb] More than 2 connections on a node! Quitting."); + return; + } + bool found_next = false; + for (size_t i = 0; i < 2; i++) { + if (n.connections[i] != current) { + next = n.connections[i]; + found_next = true; + } + } + DeleteNode(current); + current = next; + if (not found_next) { + logging::Info("[wb] Dead end? Can't find next node after %u", current); + break; + } + } while (state::node_good(current) and (current != a)); +}); void Initialize() { } @@ -271,6 +344,79 @@ void UpdateClosestNode() { state::closest_node = INVALID_NODE; } +// Finds nearest node by position, not FOV +// Not to be confused with FindClosestNode +index_t FindNearestNode() { + index_t r_node { INVALID_NODE }; + float r_dist { 65536.0f }; + + for (index_t i = 0; i < state::nodes.size(); i++) { + if (state::node_good(i)) { + auto& n = state::nodes[i]; + float dist = g_pLocalPlayer->v_Origin.DistTo(n.xyz()); + if (dist < r_dist) { + r_dist = dist; + r_node = i; + } + } + } + + return r_node; +} + +index_t SelectNextNode() { + if (not state::node_good(state::active_node)) { + return FindNearestNode(); + } + auto& n = state::nodes[state::active_node]; + if (n.connection_count > 2) { + if (state::node_good(n.preferred)) { + return n.preferred; + } else { + std::vector chance {}; + for (index_t i = 0; i < n.connection_count && i < MAX_CONNECTIONS; i++) { + if (n.connections[i] != state::active_node && state::node_good(n.connections[i])) { + chance.push_back(n.connections[i]); + } + } + if (not chance.empty()) { + return chance.at(rand() % chance.size()); + } else { + return INVALID_NODE; + } + } + } + for (index_t i = 0; i < n.connection_count && i < MAX_CONNECTIONS; i++) { + if (n.connections[i] != state::active_node && state::node_good(n.connections[i])) { + return n.connections[i]; + } + } + return INVALID_NODE; +} + +void UpdateWalker() { + if (not state::node_good(state::active_node)) { + state::active_node = FindNearestNode(); + state::recovery = true; + } + auto& n = state::nodes[state::active_node]; + WalkTo(n.xyz()); + float dist = n.xyz().DistTo(g_pLocalPlayer->v_Origin); + if (dist > float(max_distance)) { + state::recovery = true; + } + if (dist < float(reach_distance)) { + state::recovery = false; + state::last_node = state::active_node; + state::active_node = SelectNextNode(); + logging::Info("[wb] Reached node %u, moving to %u", state::last_node, state::active_node); + if (not state::node_good(state::active_node) and not state::recovery) { + logging::Info("[wb] FATAL: Next node is bad"); + state::recovery = true; + } + } +} + // Draws a single colored connection between 2 nodes void DrawConnection(index_t a, index_t b) { if (not (state::node_good(a) and state::node_good(b))) @@ -321,11 +467,11 @@ void DrawNode(index_t node, bool draw_back) { size_t node_size = 2; if (node == state::closest_node) - node_size = 4; + node_size = 6; if (node == state::active_node) color = &colors::red; - drawgl::Rect(wts.x - node_size, wts.y - node_size, 2 * node_size, 2 * node_size, color->rgba); + drawgl::FilledRect(wts.x - node_size, wts.y - node_size, 2 * node_size, 2 * node_size, color->rgba); } if (draw_indices) { @@ -368,6 +514,8 @@ void RecordNode() { auto& n = state::nodes[node]; if (g_pUserCmd->buttons & IN_DUCK) n.flags |= NF_DUCK; + if (g_pUserCmd->buttons & IN_JUMP) + n.flags |= NF_JUMP; if (state::node_good(state::active_node)) { auto& c = state::nodes[state::active_node]; n.link(state::active_node); @@ -413,7 +561,7 @@ void Move() { UpdateClosestNode(); } break; case WB_REPLAYING: { - + UpdateWalker(); } break; } } diff --git a/src/helpers.cpp b/src/helpers.cpp index 74398d80..691854ad 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -73,6 +73,28 @@ ConVar* CreateConVar(std::string name, std::string value, std::string help) { return ret; } +// Function for when you want to goto a vector +void WalkTo(const Vector& vector) { + // Calculate how to get to a vector + auto result = ComputeMove(LOCAL_E->m_vecOrigin, vector); + // Push our move to usercmd + g_pUserCmd->forwardmove = result.first; + g_pUserCmd->sidemove = result.second; +} + +std::pair ComputeMove(const Vector& a, const Vector& b) { + Vector diff = (b - a); + if (diff.Length() == 0) return { 0, 0 }; + const float x = diff.x; + const float y = diff.y; + Vector vsilent(x, y, 0); + float speed = sqrt(vsilent.x * vsilent.x + vsilent.y * vsilent.y); + Vector ang; + VectorAngles(vsilent, ang); + float yaw = DEG2RAD(ang.y - g_pUserCmd->viewangles.y); + return { cos(yaw) * 450, -sin(yaw) * 450 }; +} + ConCommand* CreateConCommand(const char* name, FnCommandCallback_t callback, const char* help) { ConCommand* ret = new ConCommand(name, callback, help); g_ICvar->RegisterConCommand(ret); diff --git a/src/helpers.h b/src/helpers.h index 60db8fc8..d56b51dc 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -139,6 +139,9 @@ float GetFov(Vector ang, Vector src, Vector dst); void ReplaceString(std::string& input, const std::string& what, const std::string& with_what); +std::pair ComputeMove(const Vector& a, const Vector& b); +void WalkTo(const Vector& vector); + void format_internal(std::stringstream& stream); template void format_internal(std::stringstream& stream, T value, Targs... args) { From 9936e3303a1fb6d59d9b3450637a69961f541a30 Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Mon, 24 Jul 2017 12:14:52 +0300 Subject: [PATCH 10/12] walking improved --- src/hacks/Walkbot.cpp | 76 ++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index e0a0657b..344975d9 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -65,6 +65,12 @@ struct walkbot_node_s { } }; // 40 +float distance_2d(Vector& xyz) { + float dx = xyz.x - g_pLocalPlayer->v_Origin.x; + float dy = xyz.y - g_pLocalPlayer->v_Origin.y; + return sqrt(dx * dx + dy * dy); +} + namespace state { // A vector containing all loaded nodes, used in both recording and replaying @@ -140,7 +146,11 @@ CatVar reach_distance(CV_FLOAT, "wb_replay_reach_distance", "16", "Distance wher CatCommand c_start_recording("wb_record", "Start recording", []() { state::state = WB_RECORDING; }); CatCommand c_start_editing("wb_edit", "Start editing", []() { state::state = WB_EDITING; }); -CatCommand c_start_replaying("wb_replay", "Start replaying", []() { state::state = WB_REPLAYING; }); +CatCommand c_start_replaying("wb_replay", "Start replaying", []() { + state::last_node = state::active_node; + state::active_node = state::closest_node; + state::state = WB_REPLAYING; +}); CatCommand c_exit("wb_exit", "Exit", []() { state::state = WB_DISABLED; }); // Selects closest node, clears selection if node is selected @@ -255,7 +265,7 @@ CatCommand c_set_preferred("wb_prefer", "Set preferred node", []() { n.preferred = b; }); // Displays all info about closest node -CatCommand c_info("wb_info", "Show info", []() { +CatCommand c_info("wb_dump", "Show info", []() { if (not state::node_good(state::closest_node)) return; @@ -316,6 +326,10 @@ CatCommand c_delete_region("wb_delete_region", "Delete region of nodes", []() { } } while (state::node_good(current) and (current != a)); }); +// Clears the state +CatCommand c_clear("wb_clear", "Removes all nodes", []() { + state::nodes.clear(); +}); void Initialize() { } @@ -353,7 +367,7 @@ index_t FindNearestNode() { for (index_t i = 0; i < state::nodes.size(); i++) { if (state::node_good(i)) { auto& n = state::nodes[i]; - float dist = g_pLocalPlayer->v_Origin.DistTo(n.xyz()); + float dist = distance_2d(n.xyz()); if (dist < r_dist) { r_dist = dist; r_node = i; @@ -375,7 +389,7 @@ index_t SelectNextNode() { } else { std::vector chance {}; for (index_t i = 0; i < n.connection_count && i < MAX_CONNECTIONS; i++) { - if (n.connections[i] != state::active_node && state::node_good(n.connections[i])) { + if (n.connections[i] != state::active_node && n.connections[i] != state::last_node && state::node_good(n.connections[i])) { chance.push_back(n.connections[i]); } } @@ -387,7 +401,7 @@ index_t SelectNextNode() { } } for (index_t i = 0; i < n.connection_count && i < MAX_CONNECTIONS; i++) { - if (n.connections[i] != state::active_node && state::node_good(n.connections[i])) { + if (n.connections[i] != state::active_node && n.connections[i] != state::last_node && state::node_good(n.connections[i])) { return n.connections[i]; } } @@ -395,26 +409,44 @@ index_t SelectNextNode() { } void UpdateWalker() { - if (not state::node_good(state::active_node)) { - state::active_node = FindNearestNode(); - state::recovery = true; - } - auto& n = state::nodes[state::active_node]; - WalkTo(n.xyz()); - float dist = n.xyz().DistTo(g_pLocalPlayer->v_Origin); - if (dist > float(max_distance)) { - state::recovery = true; - } - if (dist < float(reach_distance)) { - state::recovery = false; - state::last_node = state::active_node; - state::active_node = SelectNextNode(); - logging::Info("[wb] Reached node %u, moving to %u", state::last_node, state::active_node); - if (not state::node_good(state::active_node) and not state::recovery) { + static int jump_ticks = 0; + if (jump_ticks > 0) { + g_pUserCmd->buttons |= IN_JUMP; + jump_ticks--; + } + if (not state::node_good(state::active_node)) { + state::active_node = FindNearestNode(); + state::recovery = true; + } + auto& n = state::nodes[state::active_node]; + WalkTo(n.xyz()); + if (state::node_good(state::last_node)) { + auto& l = state::nodes[state::last_node]; + if (l.flags & NF_DUCK) + g_pUserCmd->buttons |= IN_DUCK; + } + float dist = distance_2d(n.xyz()); + if (dist > float(max_distance)) { + state::recovery = true; + } + if (dist < float(reach_distance)) { + state::recovery = false; + index_t last = state::active_node; + state::active_node = SelectNextNode(); + state::last_node = last; + logging::Info("[wb] Reached node %u, moving to %u", state::last_node, state::active_node); + if (state::node_good(state::active_node)) { + if (state::nodes[state::active_node].flags & NF_JUMP) { + g_pUserCmd->buttons |= IN_JUMP; + jump_ticks = 6; + } + } else { + if (not state::recovery) { logging::Info("[wb] FATAL: Next node is bad"); state::recovery = true; } } + } } // Draws a single colored connection between 2 nodes @@ -502,7 +534,7 @@ bool ShouldSpawnNode() { auto& node = state::nodes[state::active_node]; - if (node.xyz().DistTo(g_pLocalPlayer->v_Origin) > float(spawn_distance)) { + if (distance_2d(node.xyz()) > float(spawn_distance)) { return true; } From 43cfeb86ba4c371dd9fb8db963083fa3b0f885c6 Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Mon, 24 Jul 2017 13:02:48 +0300 Subject: [PATCH 11/12] saving/loading (broken) --- src/hacks/Walkbot.cpp | 140 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 115 insertions(+), 25 deletions(-) diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index 344975d9..6a5d4df6 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -7,6 +7,10 @@ #include "../common.h" + +#include +#include + namespace hacks { namespace shared { namespace walkbot { using index_t = unsigned; @@ -124,6 +128,91 @@ void DeleteNode(index_t node) { memset(&n, 0, sizeof(walkbot_node_s)); } +#define BINARY_FILE_WRITE(handle, data) handle.write(reinterpret_cast(&data), sizeof(data)) +#define BINARY_FILE_READ(handle, data) handle.read(reinterpret_cast(&data), sizeof(data)) + +void Save(std::string filename) { + { + DIR* walkbot_dir = opendir("cathook/walkbot"); + if (!walkbot_dir) { + logging::Info("Walkbot directory doesn't exist, creating one!"); + mkdir("cathook/walkbot", S_IRWXU | S_IRWXG); + } else closedir(walkbot_dir); + } + std::string path = format("cathook/walkbot/", g_IEngine->GetLevelName()); + { + DIR* level_dir = opendir(path.c_str()); + if (!level_dir) { + logging::Info("Walkbot directory for %s doesn't exist, creating one!", g_IEngine->GetLevelName()); + mkdir(path.c_str(), S_IRWXU | S_IRWXG); + } else closedir(level_dir); + } + + try { + std::ofstream file(format(path, "/", filename), std::ios::out | std::ios::binary); + walkbot_header_s header; + header.node_count = state::nodes.size(); + BINARY_FILE_WRITE(file, header); + file.write(reinterpret_cast(state::nodes.data()), sizeof(walkbot_node_s) * header.node_count); + file.close(); + logging::Info("Writing successful"); + } catch (std::exception& e) { + logging::Info("Writing unsuccessful: %s", e.what()); + } +} + +void Load(std::string filename) { + { + DIR* walkbot_dir = opendir("cathook/walkbot"); + if (!walkbot_dir) { + logging::Info("Walkbot directory doesn't exist, creating one!"); + mkdir("cathook/walkbot", S_IRWXU | S_IRWXG); + } else closedir(walkbot_dir); + } + std::string path = format("cathook/walkbot/", g_IEngine->GetLevelName()); + { + DIR* level_dir = opendir(path.c_str()); + if (!level_dir) { + logging::Info("Walkbot directory for %s doesn't exist, creating one!", g_IEngine->GetLevelName()); + mkdir(path.c_str(), S_IRWXU | S_IRWXG); + } else closedir(level_dir); + } + try { + std::ifstream file(format(path, "/", filename), std::ios::in | std::ios::binary); + walkbot_header_s header; + BINARY_FILE_READ(file, header); + // FIXME magic number: 1 + if (header.version != 1) { + logging::Info("Outdated/corrupted walkbot file! Cannot load this."); + file.close(); + return; + } + state::nodes.clear(); + logging::Info("Reading %i entries...", header.node_count); + state::nodes.resize(header.node_count); + file.read(reinterpret_cast(state::nodes.data()), sizeof(walkbot_node_s) * header.node_count); + file.close(); + logging::Info("Reading successful! Result: %i entries.", state::nodes.size()); + } catch (std::exception& e) { + logging::Info("Reading unsuccessful: %s", e.what()); + } +} + +static CatCommand save("wb_save", "Save", [](const CCommand& args) { + std::string filename = "default"; + if (args.ArgC() > 1) { + filename = args.Arg(1); + } + Save(filename); +}); +static CatCommand load("wb_load", "Load", [](const CCommand& args) { + std::string filename = "default"; + if (args.ArgC() > 1) { + filename = args.Arg(1); + } + Load(filename); +}); + index_t CreateNode(const Vector& xyz) { index_t node = state::free_node(); logging::Info("[wb] Creating node %u at (%.2f %.2f %.2f)", node, xyz.x, xyz.y, xyz.z); @@ -140,8 +229,8 @@ CatVar draw_info(CV_SWITCH, "wb_info", "1", "Walkbot info"); CatVar draw_path(CV_SWITCH, "wb_path", "1", "Walkbot path"); CatVar draw_nodes(CV_SWITCH, "wb_nodes", "1", "Walkbot nodes"); CatVar draw_indices(CV_SWITCH, "wb_indices", "1", "Node indices"); -CatVar spawn_distance(CV_FLOAT, "wb_node_spawn_distance", "32", "Node spawn distance"); -CatVar max_distance(CV_FLOAT, "wb_replay_max_distance", "80", "Max distance to node when replaying"); +CatVar spawn_distance(CV_FLOAT, "wb_node_spawn_distance", "48", "Node spawn distance"); +CatVar max_distance(CV_FLOAT, "wb_replay_max_distance", "100", "Max distance to node when replaying"); CatVar reach_distance(CV_FLOAT, "wb_replay_reach_distance", "16", "Distance where bot can be considered 'stepping' on the node"); CatCommand c_start_recording("wb_record", "Start recording", []() { state::state = WB_RECORDING; }); @@ -343,7 +432,7 @@ void UpdateClosestNode() { if (not node.flags & NF_GOOD) continue; - + // Eclipse shits itself when it sees Vector& beung used as Vector in GetFov float fov = GetFov(g_pLocalPlayer->v_OrigViewangles, g_pLocalPlayer->v_Eye, node.xyz()); if (fov < n_fov) { n_fov = fov; @@ -415,37 +504,38 @@ void UpdateWalker() { jump_ticks--; } if (not state::node_good(state::active_node)) { - state::active_node = FindNearestNode(); - state::recovery = true; + state::active_node = FindNearestNode(); + state::recovery = true; } auto& n = state::nodes[state::active_node]; WalkTo(n.xyz()); if (state::node_good(state::last_node)) { - auto& l = state::nodes[state::last_node]; - if (l.flags & NF_DUCK) - g_pUserCmd->buttons |= IN_DUCK; + auto& l = state::nodes[state::last_node]; + if (l.flags & NF_DUCK) + g_pUserCmd->buttons |= IN_DUCK; } float dist = distance_2d(n.xyz()); if (dist > float(max_distance)) { - state::recovery = true; + state::active_node = FindNearestNode(); + state::recovery = true; } if (dist < float(reach_distance)) { - state::recovery = false; - index_t last = state::active_node; - state::active_node = SelectNextNode(); - state::last_node = last; - logging::Info("[wb] Reached node %u, moving to %u", state::last_node, state::active_node); - if (state::node_good(state::active_node)) { - if (state::nodes[state::active_node].flags & NF_JUMP) { - g_pUserCmd->buttons |= IN_JUMP; - jump_ticks = 6; - } - } else { - if (not state::recovery) { - logging::Info("[wb] FATAL: Next node is bad"); - state::recovery = true; - } - } + state::recovery = false; + index_t last = state::active_node; + state::active_node = SelectNextNode(); + state::last_node = last; + logging::Info("[wb] Reached node %u, moving to %u", state::last_node, state::active_node); + if (state::node_good(state::active_node)) { + if (state::nodes[state::active_node].flags & NF_JUMP) { + g_pUserCmd->buttons |= IN_JUMP; + jump_ticks = 6; + } + } else { + if (not state::recovery) { + logging::Info("[wb] FATAL: Next node is bad"); + state::recovery = true; + } + } } } From fe4c22a5e84d9d980b5eb78e30a3c9d64290eb9c Mon Sep 17 00:00:00 2001 From: nullifiedcat Date: Mon, 24 Jul 2017 13:37:00 +0300 Subject: [PATCH 12/12] Fixed saving --- src/hacks/Walkbot.cpp | 52 +++++++++++++++++++++++++------------------ src/helpers.cpp | 10 +++++++++ src/helpers.h | 2 ++ 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/hacks/Walkbot.cpp b/src/hacks/Walkbot.cpp index 6a5d4df6..641f5023 100644 --- a/src/hacks/Walkbot.cpp +++ b/src/hacks/Walkbot.cpp @@ -98,6 +98,9 @@ int last_node_buttons { 0 }; // Set to true when bot is moving to nearest node after dying/losing its active node bool recovery { true }; +// Time when bot started to move towards next point +std::chrono::system_clock::time_point time {}; + // A little bit too expensive function, finds next free node or creates one if no free slots exist index_t free_node() { for (index_t i = 0; i < nodes.size(); i++) { @@ -139,17 +142,21 @@ void Save(std::string filename) { mkdir("cathook/walkbot", S_IRWXU | S_IRWXG); } else closedir(walkbot_dir); } - std::string path = format("cathook/walkbot/", g_IEngine->GetLevelName()); + std::string path = format("cathook/walkbot/", GetLevelName()); { DIR* level_dir = opendir(path.c_str()); if (!level_dir) { - logging::Info("Walkbot directory for %s doesn't exist, creating one!", g_IEngine->GetLevelName()); + logging::Info("Walkbot directory for %s doesn't exist, creating one!", GetLevelName().c_str()); mkdir(path.c_str(), S_IRWXU | S_IRWXG); } else closedir(level_dir); } - + logging::Info("Saving in %s", format(path, "/", filename).c_str()); try { std::ofstream file(format(path, "/", filename), std::ios::out | std::ios::binary); + if (not file) { + logging::Info("Could not open file!"); + return; + } walkbot_header_s header; header.node_count = state::nodes.size(); BINARY_FILE_WRITE(file, header); @@ -169,11 +176,11 @@ void Load(std::string filename) { mkdir("cathook/walkbot", S_IRWXU | S_IRWXG); } else closedir(walkbot_dir); } - std::string path = format("cathook/walkbot/", g_IEngine->GetLevelName()); + std::string path = format("cathook/walkbot/", GetLevelName()); { DIR* level_dir = opendir(path.c_str()); if (!level_dir) { - logging::Info("Walkbot directory for %s doesn't exist, creating one!", g_IEngine->GetLevelName()); + logging::Info("Walkbot directory for %s doesn't exist, creating one!", GetLevelName()); mkdir(path.c_str(), S_IRWXU | S_IRWXG); } else closedir(level_dir); } @@ -199,6 +206,7 @@ void Load(std::string filename) { } static CatCommand save("wb_save", "Save", [](const CCommand& args) { + logging::Info("Saving"); std::string filename = "default"; if (args.ArgC() > 1) { filename = args.Arg(1); @@ -206,6 +214,7 @@ static CatCommand save("wb_save", "Save", [](const CCommand& args) { Save(filename); }); static CatCommand load("wb_load", "Load", [](const CCommand& args) { + logging::Info("Loading"); std::string filename = "default"; if (args.ArgC() > 1) { filename = args.Arg(1); @@ -377,7 +386,7 @@ CatCommand c_info("wb_dump", "Show info", []() { } } if (not found) { - logging::Info("[wb] CONNECTION IS SINGLE-DIRECTIONAL (BROKEN)! (%u)", i); + logging::Info("[wb] One-directional connection! (%u)", i); } } }); @@ -428,7 +437,7 @@ void UpdateClosestNode() { index_t n_idx = INVALID_NODE; for (index_t i = 0; i < state::nodes.size(); i++) { - const auto& node = state::nodes[i]; + auto& node = state::nodes[i]; if (not node.flags & NF_GOOD) continue; @@ -472,7 +481,7 @@ index_t SelectNextNode() { return FindNearestNode(); } auto& n = state::nodes[state::active_node]; - if (n.connection_count > 2) { + if (n.connection_count) { if (state::node_good(n.preferred)) { return n.preferred; } else { @@ -489,11 +498,6 @@ index_t SelectNextNode() { } } } - for (index_t i = 0; i < n.connection_count && i < MAX_CONNECTIONS; i++) { - if (n.connections[i] != state::active_node && n.connections[i] != state::last_node && state::node_good(n.connections[i])) { - return n.connections[i]; - } - } return INVALID_NODE; } @@ -503,7 +507,8 @@ void UpdateWalker() { g_pUserCmd->buttons |= IN_JUMP; jump_ticks--; } - if (not state::node_good(state::active_node)) { + bool timeout = std::chrono::duration_cast(std::chrono::system_clock::now() - state::time).count() > 2; + if (not state::node_good(state::active_node) or timeout) { state::active_node = FindNearestNode(); state::recovery = true; } @@ -524,6 +529,7 @@ void UpdateWalker() { index_t last = state::active_node; state::active_node = SelectNextNode(); state::last_node = last; + state::time = std::chrono::system_clock::now(); logging::Info("[wb] Reached node %u, moving to %u", state::last_node, state::active_node); if (state::node_good(state::active_node)) { if (state::nodes[state::active_node].flags & NF_JUMP) { @@ -544,21 +550,23 @@ void DrawConnection(index_t a, index_t b) { if (not (state::node_good(a) and state::node_good(b))) return; - const auto& a_ = state::nodes[a]; - const auto& b_ = state::nodes[b]; + auto& a_ = state::nodes[a]; + auto& b_ = state::nodes[b]; - Vector wts_a, wts_b; - if (not (draw::WorldToScreen(a_.xyz(), wts_a) and draw::WorldToScreen(b_.xyz(), wts_b))) + Vector center = (a_.xyz() + b_.xyz()) / 2; + + Vector wts_a, wts_c; + if (not (draw::WorldToScreen(a_.xyz(), wts_a) and draw::WorldToScreen(center, wts_c))) return; rgba_t* color = &colors::white; if ((a_.flags & b_.flags) & NF_JUMP) color = &colors::yellow; else if ((a_.flags & b_.flags) & NF_DUCK) color = &colors::green; - if (a_.preferred == b or b_.preferred == a) + if (a_.preferred == b) color = &colors::pink; - drawgl::Line(wts_a.x, wts_a.y, wts_b.x - wts_a.x, wts_b.y - wts_a.y, color->rgba); + drawgl::Line(wts_a.x, wts_a.y, wts_c.x - wts_a.x, wts_c.y - wts_a.y, color->rgba); } // Draws a node and its connections @@ -566,7 +574,7 @@ void DrawNode(index_t node, bool draw_back) { if (not state::node_good(node)) return; - const auto& n = state::nodes[node]; + auto& n = state::nodes[node]; for (size_t i = 0; i < n.connection_count && i < MAX_CONNECTIONS; i++) { index_t connection = n.connections[i]; @@ -650,7 +658,7 @@ void RecordNode() { void DrawPath() { for (index_t i = 0; i < state::nodes.size(); i++) { - DrawNode(i, false); + DrawNode(i, true); } } diff --git a/src/helpers.cpp b/src/helpers.cpp index 691854ad..559c0347 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -82,6 +82,16 @@ void WalkTo(const Vector& vector) { g_pUserCmd->sidemove = result.second; } + +std::string GetLevelName() { + + std::string name(g_IEngine->GetLevelName()); + size_t slash = name.find('/'); + if (slash == std::string::npos) slash = 0; + else slash++; + return name.substr(slash, name.length() - 4); +} + std::pair ComputeMove(const Vector& a, const Vector& b) { Vector diff = (b - a); if (diff.Length() == 0) return { 0, 0 }; diff --git a/src/helpers.h b/src/helpers.h index d56b51dc..81bddce3 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -142,6 +142,8 @@ void ReplaceString(std::string& input, const std::string& what, const std::strin std::pair ComputeMove(const Vector& a, const Vector& b); void WalkTo(const Vector& vector); +std::string GetLevelName(); + void format_internal(std::stringstream& stream); template void format_internal(std::stringstream& stream, T value, Targs... args) {