diff options
Diffstat (limited to '')
| -rwxr-xr-x | build.sh | 2 | ||||
| -rwxr-xr-x | play.sh | 2 | ||||
| -rw-r--r-- | src/ISURFACE_STATUS.md | 6 | ||||
| -rw-r--r-- | src/esp.cpp | 124 | ||||
| -rw-r--r-- | src/hl2h.cpp | 15 | ||||
| -rw-r--r-- | src/hl2h.h | 25 | ||||
| -rw-r--r-- | src/menu.cpp | 35 | ||||
| -rw-r--r-- | src/netvars.cpp | 56 |
8 files changed, 226 insertions, 39 deletions
| @@ -2,6 +2,6 @@ | |||
| 2 | set -e | 2 | set -e |
| 3 | cd "$(dirname "$0")" | 3 | cd "$(dirname "$0")" |
| 4 | g++ -m32 -O2 -std=c++17 -Wall -Wextra -Werror -fPIC -shared -fvisibility=hidden \ | 4 | g++ -m32 -O2 -std=c++17 -Wall -Wextra -Werror -fPIC -shared -fvisibility=hidden \ |
| 5 | src/hl2h.cpp src/modules.cpp src/cinput.cpp src/netvars.cpp src/menu.cpp \ | 5 | src/hl2h.cpp src/modules.cpp src/cinput.cpp src/netvars.cpp src/menu.cpp src/esp.cpp \ |
| 6 | -ldl | 6 | -ldl |
| 7 | file libhl2hake.so | 7 | file libhl2hake.so |
| @@ -11,4 +11,4 @@ if [ ! -f "$LIB" ]; then | |||
| 11 | fi | 11 | fi |
| 12 | 12 | ||
| 13 | export LD_PRELOAD="$LIB" | 13 | export LD_PRELOAD="$LIB" |
| 14 | exec "$HOME/.steam/steam/ubuntu12_32/steam-runtime/run.sh" -- "$GAME/hl2.sh" -steam -novid -console "$@" | 14 | exec "$HOME/.steam/steam/ubuntu12_32/steam-runtime/run.sh" -- "$GAME/hl2.sh" -steam -novid -console +map d1_town_01 "$@" |
diff --git a/src/ISURFACE_STATUS.md b/src/ISURFACE_STATUS.md index 32a27bb..de952cd 100644 --- a/src/ISURFACE_STATUS.md +++ b/src/ISURFACE_STATUS.md | |||
| @@ -65,13 +65,13 @@ fc-match findings (system fontconfig): | |||
| 65 | 65 | ||
| 66 | ## Menu | 66 | ## Menu |
| 67 | 67 | ||
| 68 | - Tree: HL2hake → Climb/Bunnyhop/ABH, children indented (`g_depth[]`, +12px/level). | 68 | - Tree: HL2hake → Bunnyhop/ABH, children indented (`g_depth[]`, +12px/level). |
| 69 | - Right-aligned state at x=200: `[on]`/`[off]` for Active rows, | 69 | - Right-aligned state at x=200: `[on]`/`[off]` for Active rows, |
| 70 | `[keyname]` for Bind rows, `[press key]` while binding. | 70 | `[keyname]` for Bind rows, `[press key]` while binding. |
| 71 | - Feature gating: `feature_active(int)` (menu.cpp) — active AND | 71 | - Feature gating: `feature_active(int)` (menu.cpp) — active AND |
| 72 | (bind==0 or key held). Called from `do_move` (hl2h.cpp) to gate | 72 | (bind==0 or key held). Called from `do_move` (hl2h.cpp) to gate |
| 73 | climb (middle-mouse) and bhop (jump) branches. | 73 | bhop (jump) and ABH branches. |
| 74 | - Config: INI at `~/.hl2hake.ini` (climb/bhop/abh active+bind). | 74 | - Config: INI at `~/.hl2hake.ini` (bhop/abh active+bind). |
| 75 | 75 | ||
| 76 | ## Build / Run | 76 | ## Build / Run |
| 77 | 77 | ||
diff --git a/src/esp.cpp b/src/esp.cpp new file mode 100644 index 0000000..87d0b80 --- /dev/null +++ b/src/esp.cpp | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | // esp.cpp — ESP drawing + shared world_to_screen / entity gather (aimbot reuses these) | ||
| 2 | #include "hl2h.h" | ||
| 3 | #include <cmath> | ||
| 4 | #include <cstring> | ||
| 5 | #include <cstddef> | ||
| 6 | |||
| 7 | static constexpr float PI_F = 3.14159265358979323846f; | ||
| 8 | |||
| 9 | // ISurface slots (binary = SDK header + 4, disassembly-confirmed) | ||
| 10 | enum SurfSlot { | ||
| 11 | SURF_DrawSetColor = 10, SURF_FilledRect = 12, SURF_OutlinedRect = 14, | ||
| 12 | SURF_GetScreenSize = 38, | ||
| 13 | }; | ||
| 14 | |||
| 15 | struct EspTarget { | ||
| 16 | float sx, sy; // screen pos of feet | ||
| 17 | float h; // box height px | ||
| 18 | float health, maxhealth; | ||
| 19 | int teamnum; | ||
| 20 | char name[48]; | ||
| 21 | }; | ||
| 22 | static EspTarget g_targets[128]; | ||
| 23 | static int g_ntargets = 0; | ||
| 24 | static int g_scr_w = 0, g_scr_h = 0; | ||
| 25 | static bool g_esp_logged = false; | ||
| 26 | |||
| 27 | bool world_to_screen(const Vector &w, float &sx, float &sy) { | ||
| 28 | float pitch = g_cam_view.x * PI_F / 180.0f; | ||
| 29 | float yaw = g_cam_view.y * PI_F / 180.0f; | ||
| 30 | float sp = sinf(pitch), cp = cosf(pitch); | ||
| 31 | float syy = sinf(yaw), cy = cosf(yaw); | ||
| 32 | float fwd[3] = {cp * cy, cp * syy, -sp}; | ||
| 33 | float right[3] = {syy, -cy, 0}; | ||
| 34 | float up[3] = {sp * cy, sp * syy, cp}; | ||
| 35 | float dx = w.x - g_cam_eye.x, dy = w.y - g_cam_eye.y, dz = w.z - g_cam_eye.z; | ||
| 36 | float z = dx * fwd[0] + dy * fwd[1] + dz * fwd[2]; | ||
| 37 | if (z < 1.0f) return false; | ||
| 38 | float x = dx * right[0] + dy * right[1] + dz * right[2]; | ||
| 39 | float y = dx * up[0] + dy * up[1] + dz * up[2]; | ||
| 40 | float tanfov = tanf(75.0f * 0.5f * PI_F / 180.0f); | ||
| 41 | sx = (float)g_scr_w * 0.5f + (x / z) * ((float)g_scr_w * 0.5f / tanfov); | ||
| 42 | sy = (float)g_scr_h * 0.5f - (y / z) * ((float)g_scr_w * 0.5f / tanfov); | ||
| 43 | return true; | ||
| 44 | } | ||
| 45 | |||
| 46 | static void esp_collect(int local_idx) { | ||
| 47 | g_ntargets = 0; | ||
| 48 | using Fn = int (*)(void *); | ||
| 49 | int maxent = vfunc<Fn>(g_iface.entitylist, 5)(g_iface.entitylist); // GetHighestEntityIndex | ||
| 50 | if (maxent < 0 || maxent > 512) maxent = 512; | ||
| 51 | for (int idx = 0; idx <= maxent && g_ntargets < 128; idx++) { | ||
| 52 | if (idx == local_idx) continue; | ||
| 53 | void *ent = entitylist_get(idx); | ||
| 54 | if (!ent) continue; | ||
| 55 | uintptr_t e = (uintptr_t)ent; | ||
| 56 | float hpv = (float)*(int *)(e + g_net.health); // m_iHealth is int | ||
| 57 | if (!(hpv > 0)) continue; | ||
| 58 | Vector origin{*(float *)(e + g_net.origin), *(float *)(e + g_net.origin + 4), | ||
| 59 | *(float *)(e + g_net.origin + 8)}; | ||
| 60 | // ponytail: maxs netvar may be unresolved; fixed 72-unit torso fallback | ||
| 61 | float maxsz = g_net.maxs >= 0 ? *(float *)(e + g_net.maxs) : 72.0f; | ||
| 62 | Vector top{origin.x, origin.y, origin.z + maxsz}; | ||
| 63 | float sx, sy, tx, ty; | ||
| 64 | if (!world_to_screen(origin, sx, sy) || !world_to_screen(top, tx, ty)) | ||
| 65 | continue; | ||
| 66 | float h = sy - ty; | ||
| 67 | if (h < 4.0f || sy < 0 || ty > (float)g_scr_h) continue; // behind / offscreen | ||
| 68 | EspTarget &t = g_targets[g_ntargets++]; | ||
| 69 | t.sx = sx; t.sy = sy; t.h = h; | ||
| 70 | t.health = hpv; | ||
| 71 | t.maxhealth = (float)*(int *)(e + g_net.maxhealth); | ||
| 72 | if (t.maxhealth <= 0) t.maxhealth = hpv; | ||
| 73 | // classname via IClientNetworkable::GetClientClass (slot 2) -> m_pNetworkName @ +8 | ||
| 74 | using CCFn = void *(*)(void *); | ||
| 75 | void *cc = vfunc<CCFn>(ent, 2)(ent); | ||
| 76 | const char *nn = cc ? *(const char **)((uintptr_t)cc + 8) : nullptr; | ||
| 77 | strncpy(t.name, nn ? nn : "?", sizeof(t.name) - 1); | ||
| 78 | t.name[sizeof(t.name) - 1] = 0; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | static void surf_rect(int filled, int x0, int y0, int x1, int y1) { | ||
| 83 | using Fn = void (*)(void *, int, int, int, int); | ||
| 84 | vfunc<Fn>(g_surface, filled ? SURF_FilledRect : SURF_OutlinedRect)(g_surface, x0, y0, x1, y1); | ||
| 85 | } | ||
| 86 | static void surf_color(int r, int g, int b, int a) { | ||
| 87 | using Fn = void (*)(void *, int, int, int, int); | ||
| 88 | vfunc<Fn>(g_surface, SURF_DrawSetColor)(g_surface, r, g, b, a); | ||
| 89 | } | ||
| 90 | |||
| 91 | void esp_draw() { | ||
| 92 | if (!g_surface || !g_iface.entitylist || !g_net.esp_ok()) return; | ||
| 93 | if (!g_scr_w) { | ||
| 94 | using Fn = void (*)(void *, int &, int &); | ||
| 95 | vfunc<Fn>(g_surface, SURF_GetScreenSize)(g_surface, g_scr_w, g_scr_h); | ||
| 96 | logf("ESP: screen %dx%d", g_scr_w, g_scr_h); | ||
| 97 | if (!g_scr_w) return; | ||
| 98 | } | ||
| 99 | esp_collect(engine_get_local_player()); | ||
| 100 | if (g_ntargets && !g_esp_logged) { | ||
| 101 | g_esp_logged = true; | ||
| 102 | logf("ESP: first draw, %d targets", g_ntargets); | ||
| 103 | } | ||
| 104 | for (int i = 0; i < g_ntargets; i++) { | ||
| 105 | const EspTarget &t = g_targets[i]; | ||
| 106 | // team color: 3 combine red, 2 rebels green, else white | ||
| 107 | if (t.teamnum == 3) surf_color(255, 60, 60, 255); | ||
| 108 | else if (t.teamnum == 2) surf_color(60, 255, 60, 255); | ||
| 109 | else surf_color(255, 255, 255, 255); | ||
| 110 | float w = t.h * 0.45f; // ponytail: constant aspect, no OBB width — swap for m_vecMins/maxs span later | ||
| 111 | surf_rect(0, (int)(t.sx - w / 2), (int)(t.sy - t.h), (int)(t.sx + w / 2), (int)t.sy); | ||
| 112 | // health bar under box | ||
| 113 | float frac = t.health / t.maxhealth; | ||
| 114 | if (frac > 1) frac = 1; | ||
| 115 | surf_color(0, 0, 0, 200); | ||
| 116 | surf_rect(1, (int)(t.sx - w / 2), (int)t.sy + 1, (int)(t.sx + w / 2), (int)t.sy + 4); | ||
| 117 | if (frac > 0.5f) surf_color(40, 255, 40, 255); | ||
| 118 | else if (frac > 0.25f) surf_color(255, 255, 0, 255); | ||
| 119 | else surf_color(255, 40, 40, 255); | ||
| 120 | surf_rect(1, (int)(t.sx - w / 2), (int)t.sy + 2, | ||
| 121 | (int)(t.sx - w / 2 + w * frac), (int)t.sy + 3); | ||
| 122 | draw_text_col((int)(t.sx - w / 2), (int)(t.sy - t.h) - 14, t.name, 255, 255, 255); | ||
| 123 | } | ||
| 124 | } | ||
diff --git a/src/hl2h.cpp b/src/hl2h.cpp index c6c0aeb..01fdb0f 100644 --- a/src/hl2h.cpp +++ b/src/hl2h.cpp | |||
| @@ -32,7 +32,8 @@ void logf(const char *fmt, ...) { | |||
| 32 | Module g_client, g_engine; | 32 | Module g_client, g_engine; |
| 33 | GameInterfaces g_iface; | 33 | GameInterfaces g_iface; |
| 34 | NetVars g_net; | 34 | NetVars g_net; |
| 35 | uintptr_t g_input = 0; | 35 | Vector g_cam_eye{0, 0, 0}; |
| 36 | Vector g_cam_view{0, 0, 0}; | ||
| 36 | 37 | ||
| 37 | // --------------------------------------------------------------------------- | 38 | // --------------------------------------------------------------------------- |
| 38 | // vector math | 39 | // vector math |
| @@ -81,7 +82,7 @@ float getfov(const QAngle &my_view, const QAngle &aim_ang) { | |||
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | // --------------------------------------------------------------------------- | 84 | // --------------------------------------------------------------------------- |
| 84 | // feature logic (bhop, ABH, climb) | 85 | // feature logic (bhop, ABH) |
| 85 | // --------------------------------------------------------------------------- | 86 | // --------------------------------------------------------------------------- |
| 86 | 87 | ||
| 87 | static int g_modified_logged = 0; | 88 | static int g_modified_logged = 0; |
| @@ -103,19 +104,16 @@ void note_modified(const CUserCmd *cmd, int flags, const float *vel) { | |||
| 103 | 104 | ||
| 104 | static bool g_logged_local = false; | 105 | static bool g_logged_local = false; |
| 105 | 106 | ||
| 106 | static int engine_get_local_player() { | 107 | int engine_get_local_player() { |
| 107 | using Fn = int (*)(void *); | 108 | using Fn = int (*)(void *); |
| 108 | return vfunc<Fn>(g_iface.engine, 12)(g_iface.engine); | 109 | return vfunc<Fn>(g_iface.engine, 12)(g_iface.engine); |
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | static void *entitylist_get(int idx) { | 112 | void *entitylist_get(int idx) { |
| 112 | using Fn = void *(*)(void *, int); | 113 | using Fn = void *(*)(void *, int); |
| 113 | return vfunc<Fn>(g_iface.entitylist, 3)(g_iface.entitylist, idx); | 114 | return vfunc<Fn>(g_iface.entitylist, 3)(g_iface.entitylist, idx); |
| 114 | } | 115 | } |
| 115 | 116 | ||
| 116 | |||
| 117 | |||
| 118 | |||
| 119 | static void do_move(int seq) { | 117 | static void do_move(int seq) { |
| 120 | static bool g_echo_sent = false; | 118 | static bool g_echo_sent = false; |
| 121 | if (!g_input || !g_net.ok()) | 119 | if (!g_input || !g_net.ok()) |
| @@ -148,6 +146,9 @@ static void do_move(int seq) { | |||
| 148 | return; | 146 | return; |
| 149 | 147 | ||
| 150 | uintptr_t e = (uintptr_t)ent; | 148 | uintptr_t e = (uintptr_t)ent; |
| 149 | g_cam_eye = {*(float *)(e + g_net.origin), *(float *)(e + g_net.origin + 4), *(float *)(e + g_net.origin + 8)}; | ||
| 150 | g_cam_eye.z += *(float *)(e + g_net.viewoffset); | ||
| 151 | g_cam_view = {cmd->viewangles[0], cmd->viewangles[1], cmd->viewangles[2]}; | ||
| 151 | int flags = *(int *)(e + g_net.flags); | 152 | int flags = *(int *)(e + g_net.flags); |
| 152 | bool onground = (flags & FL_ONGROUND) != 0; | 153 | bool onground = (flags & FL_ONGROUND) != 0; |
| 153 | bool inwater = (flags & FL_INWATER) != 0; | 154 | bool inwater = (flags & FL_INWATER) != 0; |
| @@ -59,12 +59,20 @@ template <typename Fn> inline Fn vfunc(void *obj, size_t idx) { | |||
| 59 | // --------------------------------------------------------------------------- | 59 | // --------------------------------------------------------------------------- |
| 60 | // netvars | 60 | // netvars |
| 61 | // --------------------------------------------------------------------------- | 61 | // --------------------------------------------------------------------------- |
| 62 | |||
| 63 | struct NetVars { | 62 | struct NetVars { |
| 64 | int flags = -1; | 63 | int flags = -1; |
| 65 | int velocity = -1; | 64 | int velocity = -1; |
| 66 | int movetype = -1; | 65 | int movetype = -1; |
| 66 | int health = -1; | ||
| 67 | int maxhealth = -1; | ||
| 68 | int teamnum = -1; | ||
| 69 | int origin = -1; | ||
| 70 | int viewoffset = -1; | ||
| 71 | int mins = -1; | ||
| 72 | int maxs = -1; | ||
| 73 | // ponytail: mins/maxs may be absent from some HL2 netvar tables; esp.cpp falls back to h=72 | ||
| 67 | bool ok() const { return flags >= 0 && velocity >= 0 && movetype >= 0; } | 74 | bool ok() const { return flags >= 0 && velocity >= 0 && movetype >= 0; } |
| 75 | bool esp_ok() const { return ok() && health >= 0 && maxhealth >= 0 && teamnum >= 0 && origin >= 0 && viewoffset >= 0; } | ||
| 68 | }; | 76 | }; |
| 69 | extern NetVars g_net; | 77 | extern NetVars g_net; |
| 70 | 78 | ||
| @@ -116,16 +124,15 @@ enum { MOVETYPE_NOCLIP = 8, MOVETYPE_LADDER = 9 }; | |||
| 116 | 124 | ||
| 117 | struct Vector { float x, y, z; }; | 125 | struct Vector { float x, y, z; }; |
| 118 | struct QAngle { float x, y, z; }; | 126 | struct QAngle { float x, y, z; }; |
| 127 | // camera state captured each CreateMove (used by ESP / future aimbot) | ||
| 128 | extern Vector g_cam_eye; | ||
| 129 | extern Vector g_cam_view; | ||
| 119 | QAngle vector_angles(const Vector &forward); | 130 | QAngle vector_angles(const Vector &forward); |
| 120 | Vector angle_forward_vector(const QAngle &angles); | 131 | enum FeatureId { FEAT_BHOP = 0, FEAT_ABH = 1, FEAT_ESP = 2 }; |
| 121 | float getfov(const QAngle &my_view, const QAngle &aim_ang); | ||
| 122 | 132 | ||
| 123 | // --------------------------------------------------------------------------- | 133 | // --------------------------------------------------------------------------- |
| 124 | // cross-file declarations | 134 | // cross-file declarations |
| 125 | // --------------------------------------------------------------------------- | 135 | // --------------------------------------------------------------------------- |
| 126 | |||
| 127 | // feature ids shared by menu (feature_active) and hl2h.cpp (do_move) | ||
| 128 | enum FeatureId { FEAT_BHOP = 0, FEAT_ABH = 1 }; | ||
| 129 | void note_modified(const CUserCmd *cmd, int flags, const float *vel); | 136 | void note_modified(const CUserCmd *cmd, int flags, const float *vel); |
| 130 | CUserCmd *get_usercmd(int seq); | 137 | CUserCmd *get_usercmd(int seq); |
| 131 | void fix_verified_crc(int seq, uint32_t crc); | 138 | void fix_verified_crc(int seq, uint32_t crc); |
| @@ -135,6 +142,12 @@ void resolve_netvars(); | |||
| 135 | void find_modules(); | 142 | void find_modules(); |
| 136 | void init_conmsg(); | 143 | void init_conmsg(); |
| 137 | bool feature_active(int feature); | 144 | bool feature_active(int feature); |
| 145 | void *entitylist_get(int idx); | ||
| 146 | int engine_get_local_player(); | ||
| 147 | void draw_text_col(int x, int y, const char *s, int r, int g, int b); | ||
| 148 | void esp_draw(); | ||
| 149 | bool world_to_screen(const Vector &w, float &sx, float &sy); | ||
| 150 | |||
| 138 | void outer_draw(); | 151 | void outer_draw(); |
| 139 | // raw ISurface slot calls used by the PaintTraverseEx hook (hl2h.cpp) | 152 | // raw ISurface slot calls used by the PaintTraverseEx hook (hl2h.cpp) |
| 140 | using SurfFn = void (*)(void *, ...); | 153 | using SurfFn = void (*)(void *, ...); |
diff --git a/src/menu.cpp b/src/menu.cpp index 6dccf1c..302eab3 100644 --- a/src/menu.cpp +++ b/src/menu.cpp | |||
| @@ -52,29 +52,32 @@ struct FeatureState { | |||
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| 54 | static FeatureState g_bhop{true, 0}; | 54 | static FeatureState g_bhop{true, 0}; |
| 55 | static FeatureState g_abh{true, 0}; | ||
| 56 | 55 | ||
| 56 | static FeatureState g_abh{true, 0}; | ||
| 57 | static FeatureState g_esp{true, 0}; | ||
| 57 | // tree | 58 | // tree |
| 58 | static MenuNode g_root{NODE_ROOT, "HL2hake", true, 0, {}, nullptr, nullptr, nullptr}; | 59 | static MenuNode g_root{NODE_ROOT, "HL2hake", true, 0, {}, nullptr, nullptr, nullptr}; |
| 59 | static MenuNode g_bhop_feat{NODE_FEATURE, "Bunnyhop", true, 1, {}, nullptr, nullptr, nullptr}; | 60 | static MenuNode g_bhop_feat{NODE_FEATURE, "Bunnyhop", true, 1, {}, nullptr, nullptr, nullptr}; |
| 60 | static MenuNode g_bhop_active{NODE_TOGGLE, "Active", false, 0, {}, &g_bhop.active, nullptr, nullptr}; | 61 | static MenuNode g_bhop_active{NODE_TOGGLE, "Active", false, 0, {}, &g_bhop.active, nullptr, nullptr}; |
| 61 | static MenuNode g_abh_feat{NODE_FEATURE, "ABH", true, 1, {}, nullptr, nullptr, nullptr}; | 62 | static MenuNode g_abh_feat{NODE_FEATURE, "ABH", true, 1, {}, nullptr, nullptr, nullptr}; |
| 62 | static MenuNode g_abh_active{NODE_TOGGLE, "Active", false, 0, {}, &g_abh.active, nullptr, nullptr}; | 63 | static MenuNode g_abh_active{NODE_TOGGLE, "Active", false, 0, {}, &g_abh.active, nullptr, nullptr}; |
| 64 | static MenuNode g_esp_feat{NODE_FEATURE, "ESP", true, 1, {}, nullptr, nullptr, nullptr}; | ||
| 65 | static MenuNode g_esp_active{NODE_TOGGLE, "Active", false, 0, {}, &g_esp.active, nullptr, nullptr}; | ||
| 63 | 66 | ||
| 64 | static MenuNode *g_visible[16]; // flattened visible nodes for arrow navigation | 67 | static MenuNode *g_visible[16]; // flattened visible nodes for arrow navigation |
| 65 | static int g_visible_count = 0; | 68 | static int g_visible_count = 0; |
| 66 | static int g_selected = 0; | 69 | static int g_selected = 0; |
| 67 | bool g_menu_open = false; | 70 | bool g_menu_open = false; |
| 68 | 71 | ||
| 69 | // bind-select state | 72 | static bool g_bind_mode = false; |
| 70 | static bool g_bind_mode = false; // true = waiting for key press | ||
| 71 | |||
| 72 | static void build_tree() { | 73 | static void build_tree() { |
| 73 | g_bhop_feat.children[0] = &g_bhop_active; | 74 | g_bhop_feat.children[0] = &g_bhop_active; |
| 74 | g_abh_feat.children[0] = &g_abh_active; | 75 | g_abh_feat.children[0] = &g_abh_active; |
| 76 | g_esp_feat.children[0] = &g_esp_active; | ||
| 75 | g_root.children[0] = &g_bhop_feat; | 77 | g_root.children[0] = &g_bhop_feat; |
| 76 | g_root.children[1] = &g_abh_feat; | 78 | g_root.children[1] = &g_abh_feat; |
| 77 | g_root.child_count = 2; | 79 | g_root.children[2] = &g_esp_feat; |
| 80 | g_root.child_count = 3; | ||
| 78 | } | 81 | } |
| 79 | 82 | ||
| 80 | static int g_depth[16]; // depth of each visible row (for indentation) | 83 | static int g_depth[16]; // depth of each visible row (for indentation) |
| @@ -136,6 +139,7 @@ static void config_save() { | |||
| 136 | return; | 139 | return; |
| 137 | fprintf(f, "[bhop]\nactive=%d\nbind=%d\n", g_bhop.active, g_bhop.bind); | 140 | fprintf(f, "[bhop]\nactive=%d\nbind=%d\n", g_bhop.active, g_bhop.bind); |
| 138 | fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); | 141 | fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); |
| 142 | fprintf(f, "[esp]\nactive=%d\nbind=%d\n", g_esp.active, g_esp.bind); | ||
| 139 | fclose(f); | 143 | fclose(f); |
| 140 | } | 144 | } |
| 141 | 145 | ||
| @@ -152,6 +156,8 @@ static void config_load() { | |||
| 152 | cur = &g_bhop; | 156 | cur = &g_bhop; |
| 153 | else if (strstr(line, "[abh]")) | 157 | else if (strstr(line, "[abh]")) |
| 154 | cur = &g_abh; | 158 | cur = &g_abh; |
| 159 | else if (strstr(line, "[esp]")) | ||
| 160 | cur = &g_esp; | ||
| 155 | else | 161 | else |
| 156 | cur = nullptr; | 162 | cur = nullptr; |
| 157 | } else if (cur) { | 163 | } else if (cur) { |
| @@ -234,6 +240,7 @@ static void poll_mouse() { | |||
| 234 | return; | 240 | return; |
| 235 | int mx, my; | 241 | int mx, my; |
| 236 | unsigned mask = SDL_GetMouseState_real(&mx, &my); | 242 | unsigned mask = SDL_GetMouseState_real(&mx, &my); |
| 243 | |||
| 237 | for (int b = 0; b < 5; b++) { | 244 | for (int b = 0; b < 5; b++) { |
| 238 | bool down = (mask & (1u << b)) != 0; // SDL buttons 1..5 = bits 0..4 | 245 | bool down = (mask & (1u << b)) != 0; // SDL buttons 1..5 = bits 0..4 |
| 239 | int sc = MOUSE_BASE + b; | 246 | int sc = MOUSE_BASE + b; |
| @@ -269,8 +276,8 @@ static bool key_pressed(int sc) { | |||
| 269 | // feature gate queried from hl2h.cpp do_move(): feature must be Active AND | 276 | // feature gate queried from hl2h.cpp do_move(): feature must be Active AND |
| 270 | // its bind key held (always-on when unbound). | 277 | // its bind key held (always-on when unbound). |
| 271 | bool feature_active(int feature) { | 278 | bool feature_active(int feature) { |
| 272 | static FeatureState *feats[2] = {&g_bhop, &g_abh}; | 279 | static FeatureState *feats[3] = {&g_bhop, &g_abh, &g_esp}; |
| 273 | if (feature < 0 || feature > 1) | 280 | if (feature < 0 || feature > 2) |
| 274 | return false; | 281 | return false; |
| 275 | FeatureState *f = feats[feature]; | 282 | FeatureState *f = feats[feature]; |
| 276 | if (!f->active) | 283 | if (!f->active) |
| @@ -456,6 +463,15 @@ static void draw_text(int x, int y, const char *text) { | |||
| 456 | surf_draw_set_text_pos(x, y); | 463 | surf_draw_set_text_pos(x, y); |
| 457 | surf_draw_print_text(wtext, len); | 464 | surf_draw_print_text(wtext, len); |
| 458 | } | 465 | } |
| 466 | void draw_text_col(int x, int y, const char *text, int r, int g, int b) { | ||
| 467 | wchar_t wtext[256]; | ||
| 468 | mbstowcs(wtext, text, 255); | ||
| 469 | wtext[255] = 0; | ||
| 470 | surf_draw_set_text_font(g_font); | ||
| 471 | surf_draw_set_text_color(r, g, b, 255); | ||
| 472 | surf_draw_set_text_pos(x, y); | ||
| 473 | surf_draw_print_text(wtext, (int)wcslen(wtext)); | ||
| 474 | } | ||
| 459 | 475 | ||
| 460 | // Draw overlay. MUST be called from inside the ISurface paint path | 476 | // Draw overlay. MUST be called from inside the ISurface paint path |
| 461 | // (see hkdDrawPrintText hook in hl2h.cpp): we wrap our draws in | 477 | // (see hkdDrawPrintText hook in hl2h.cpp): we wrap our draws in |
| @@ -464,7 +480,8 @@ void outer_draw() { | |||
| 464 | menu_handle_input(); | 480 | menu_handle_input(); |
| 465 | // HL2H_DRAW_TEST=1 draws a probe rect without needing the menu open | 481 | // HL2H_DRAW_TEST=1 draws a probe rect without needing the menu open |
| 466 | static bool draw_test = getenv("HL2H_DRAW_TEST") != nullptr; | 482 | static bool draw_test = getenv("HL2H_DRAW_TEST") != nullptr; |
| 467 | if (!g_surface || (!g_menu_open && !draw_test)) | 483 | bool esp_on = feature_active(FEAT_ESP); |
| 484 | if (!g_surface || (!g_menu_open && !draw_test && !esp_on)) | ||
| 468 | return; | 485 | return; |
| 469 | if (!g_font) { | 486 | if (!g_font) { |
| 470 | g_font = surf_create_font(); | 487 | g_font = surf_create_font(); |
| @@ -485,6 +502,8 @@ void outer_draw() { | |||
| 485 | if (!panel) | 502 | if (!panel) |
| 486 | return; | 503 | return; |
| 487 | surf_push_make_current(panel, false); | 504 | surf_push_make_current(panel, false); |
| 505 | if (esp_on) | ||
| 506 | esp_draw(); | ||
| 488 | if (draw_test) { | 507 | if (draw_test) { |
| 489 | surf_draw_set_color(255, 0, 0, 255); | 508 | surf_draw_set_color(255, 0, 0, 255); |
| 490 | surf_draw_filled_rect(20, 20, 180, 60); | 509 | surf_draw_filled_rect(20, 20, 180, 60); |
diff --git a/src/netvars.cpp b/src/netvars.cpp index 41070c7..5c8c296 100644 --- a/src/netvars.cpp +++ b/src/netvars.cpp | |||
| @@ -82,10 +82,44 @@ static void collect_netvars(uintptr_t table, uintptr_t base_off, int depth) { | |||
| 82 | } else { | 82 | } else { |
| 83 | g_net.velocity = (int)(base_off + (uint32_t)poff); | 83 | g_net.velocity = (int)(base_off + (uint32_t)poff); |
| 84 | } | 84 | } |
| 85 | } else if (strcmp(pname2, "m_iHealth") == 0 && g_net.health < 0) { | ||
| 86 | g_net.health = (int)(base_off + (uint32_t)poff); | ||
| 87 | } else if (strcmp(pname2, "m_iMaxHealth") == 0 && g_net.maxhealth < 0) { | ||
| 88 | g_net.maxhealth = (int)(base_off + (uint32_t)poff); | ||
| 89 | } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) { | ||
| 90 | g_net.teamnum = (int)(base_off + (uint32_t)poff); | ||
| 91 | } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) { | ||
| 92 | if (parray && g_client.contains(parray)) { | ||
| 93 | int32_t eoff = *(int32_t *)(parray + 0x2C); | ||
| 94 | g_net.origin = (int)(base_off + (uint32_t)(eoff ? eoff : poff)); | ||
| 95 | } else { | ||
| 96 | g_net.origin = (int)(base_off + (uint32_t)poff); | ||
| 97 | } | ||
| 98 | } else if (strcmp(pname2, "m_vecViewOffset") == 0 && g_net.viewoffset < 0) { | ||
| 99 | if (parray && g_client.contains(parray)) { | ||
| 100 | int32_t eoff = *(int32_t *)(parray + 0x2C); | ||
| 101 | g_net.viewoffset = (int)(base_off + (uint32_t)(eoff ? eoff : poff)); | ||
| 102 | } else { | ||
| 103 | g_net.viewoffset = (int)(base_off + (uint32_t)poff); | ||
| 104 | } | ||
| 105 | } else if (strcmp(pname2, "m_vecMins") == 0 && g_net.mins < 0) { | ||
| 106 | if (parray && g_client.contains(parray)) { | ||
| 107 | int32_t eoff = *(int32_t *)(parray + 0x2C); | ||
| 108 | g_net.mins = (int)(base_off + (uint32_t)(eoff ? eoff : poff)); | ||
| 109 | } else { | ||
| 110 | g_net.mins = (int)(base_off + (uint32_t)poff); | ||
| 111 | } | ||
| 112 | } else if (strcmp(pname2, "m_vecMaxs") == 0 && g_net.maxs < 0) { | ||
| 113 | if (parray && g_client.contains(parray)) { | ||
| 114 | int32_t eoff = *(int32_t *)(parray + 0x2C); | ||
| 115 | g_net.maxs = (int)(base_off + (uint32_t)(eoff ? eoff : poff)); | ||
| 116 | } else { | ||
| 117 | g_net.maxs = (int)(base_off + (uint32_t)poff); | ||
| 118 | } | ||
| 85 | } | 119 | } |
| 86 | if (g_net.ok()) | 120 | if (g_net.esp_ok()) |
| 87 | return; | 121 | return; |
| 88 | } | 122 | } |
| 89 | } | 123 | } |
| 90 | 124 | ||
| 91 | // prediction datamap scan for m_MoveType (FIELD_CHARACTER, fieldOffset in range) | 125 | // prediction datamap scan for m_MoveType (FIELD_CHARACTER, fieldOffset in range) |
| @@ -161,11 +195,9 @@ void resolve_netvars() { | |||
| 161 | for (uintptr_t cc = head; cc && g_client.contains(cc) && classes < 1024; | 195 | for (uintptr_t cc = head; cc && g_client.contains(cc) && classes < 1024; |
| 162 | cc = *(uintptr_t *)(cc + 0x10)) { | 196 | cc = *(uintptr_t *)(cc + 0x10)) { |
| 163 | classes++; | 197 | classes++; |
| 164 | char name[64]; | ||
| 165 | if (!module_string(*(uintptr_t *)(cc + 0x08), name, sizeof(name))) | ||
| 166 | break; | ||
| 167 | collect_netvars(*(uintptr_t *)(cc + 0x0C), 0, 0); | 198 | collect_netvars(*(uintptr_t *)(cc + 0x0C), 0, 0); |
| 168 | if (g_net.flags >= 0 && g_net.velocity >= 0) | 199 | if (g_net.esp_ok() || (g_net.flags >= 0 && g_net.velocity >= 0 && |
| 200 | g_net.health < 0)) | ||
| 169 | break; | 201 | break; |
| 170 | } | 202 | } |
| 171 | logf("client classes walked: %d", classes); | 203 | logf("client classes walked: %d", classes); |
| @@ -175,11 +207,9 @@ void resolve_netvars() { | |||
| 175 | logf("movetype guard disabled"); | 207 | logf("movetype guard disabled"); |
| 176 | } | 208 | } |
| 177 | 209 | ||
| 178 | if (g_net.ok()) { | 210 | logf("netvars: flags=%d velocity=%d movetype=%d health=%d maxhealth=%d " |
| 179 | logf("netvars: m_fFlags=+0x%X m_vecVelocity[0]=+0x%X m_MoveType=+0x%X", | 211 | "teamnum=%d origin=%d viewoffset=%d mins=%d maxs=%d", |
| 180 | g_net.flags, g_net.velocity, g_net.movetype); | 212 | g_net.flags, g_net.velocity, g_net.movetype, g_net.health, |
| 181 | } else { | 213 | g_net.maxhealth, g_net.teamnum, g_net.origin, g_net.viewoffset, |
| 182 | logf("netvar resolution incomplete: flags=%d velocity=%d movetype=%d", | 214 | g_net.mins, g_net.maxs); |
| 183 | g_net.flags, g_net.velocity, g_net.movetype); | ||
| 184 | } | ||
| 185 | } | 215 | } |
