From fd731bae1257d68d118d533ce79c9b6b5e433b07 Mon Sep 17 00:00:00 2001 From: julianacat Date: Thu, 17 Aug 2017 17:45:45 -0500 Subject: [PATCH 1/5] ESP Collision cache and seperation --- src/hacks/ESP.cpp | 393 ++++++++++++++++++++++++++----------------- src/hacks/ESP.h | 7 +- src/hacks/Misc.cpp | 2 - src/hooks/others.cpp | 2 +- 4 files changed, 242 insertions(+), 162 deletions(-) diff --git a/src/hacks/ESP.cpp b/src/hacks/ESP.cpp index 35ecea51..9a518518 100644 --- a/src/hacks/ESP.cpp +++ b/src/hacks/ESP.cpp @@ -50,15 +50,15 @@ CatVar proj_esp(CV_SWITCH, "esp_proj", "1", "Projectile ESP", "Projectile ESP"); CatVar entity_model(CV_SWITCH, "esp_model_name", "0", "Model name ESP", "Model name esp (DEBUG ONLY)"); CatVar item_weapon_spawners(CV_SWITCH, "esp_weapon_spawners", "1", "Show weapon spawners", "TF2C deathmatch weapon spawners"); CatVar item_adrenaline(CV_SWITCH, "esp_item_adrenaline", "0", "Show Adrenaline", "TF2C adrenaline pills"); -static CatVar box_healthbar(CV_SWITCH, "esp_box_healthbar", "1", "Box Healthbar"); -static CatVar draw_bones(CV_SWITCH, "esp_bones", "0", "Draw Bone ID's"); -static CatVar box_corner_size(CV_INT, "esp_box_corner_size", "10", "Corner Size"); -static CatEnum esp_box_text_position_enum({"TOP RIGHT", "BOTTOM RIGHT", "CENTER", "ABOVE", "BELOW" }); -static CatVar esp_box_text_position(esp_box_text_position_enum, "esp_box_text_position", "0", "Text position", "Defines text position"); -static CatVar box_nodraw(CV_SWITCH, "esp_box_nodraw", "0", "Invisible 2D Box", "Don't draw 2D box"); -static CatVar box_expand(CV_INT, "esp_box_expand", "0", "Expand 2D Box", "Expand 2D box by N units"); -static CatVar box_corners(CV_SWITCH, "esp_box_corners", "1", "Box Corners"); -static CatVar powerup_esp(CV_SWITCH, "esp_powerups", "1", "Powerup ESP"); +CatVar box_healthbar(CV_SWITCH, "esp_box_healthbar", "1", "Box Healthbar"); +CatVar draw_bones(CV_SWITCH, "esp_bones", "0", "Draw Bone ID's"); +CatVar box_corner_size(CV_INT, "esp_box_corner_size", "10", "Corner Size"); +CatEnum esp_box_text_position_enum({"TOP RIGHT", "BOTTOM RIGHT", "CENTER", "ABOVE", "BELOW" }); +CatVar esp_box_text_position(esp_box_text_position_enum, "esp_box_text_position", "0", "Text position", "Defines text position"); +CatVar box_nodraw(CV_SWITCH, "esp_box_nodraw", "0", "Invisible 2D Box", "Don't draw 2D box"); +CatVar box_expand(CV_INT, "esp_box_expand", "0", "Expand 2D Box", "Expand 2D box by N units"); +CatVar box_corners(CV_SWITCH, "esp_box_corners", "1", "Box Corners"); +CatVar powerup_esp(CV_SWITCH, "esp_powerups", "1", "Powerup ESP"); // Storage arrays for keeping strings and other data std::mutex threadsafe_mutex; @@ -77,6 +77,85 @@ void ResetEntityStrings() { } } +// Used for caching collidable bounds +bool GetCollide(CachedEntity* ent) { + + // Null + Dormant check to prevent crashing + if (CE_BAD(ent)) return false; + + // Grab esp data + ESPData& ent_data = data[ent->m_IDX]; + + // If entity has cached collides, return it. Otherwise generate new bounds + if (!ent_data.has_collide) { + + // Get collision center, max, and mins + const Vector& origin = RAW_ENT(ent)->GetCollideable()->GetCollisionOrigin(); + Vector mins = RAW_ENT(ent)->GetCollideable()->OBBMins() + origin; + Vector maxs = RAW_ENT(ent)->GetCollideable()->OBBMaxs() + origin; + + // Create a array for storing box points + Vector points_r[8]; // World vectors + Vector points[8]; // Screen vectors + + // If user setting for box expnad is true, spread the max and mins + if (box_expand) { + const float& exp = (float)box_expand; + maxs.x += exp; + maxs.y += exp; + maxs.z += exp; + mins.x -= exp; + mins.y -= exp; + mins.z -= exp; + } + + // Create points for the box based on max and mins + float x = maxs.x - mins.x; + float y = maxs.y - mins.y; + float z = maxs.z - mins.z; + points_r[0] = mins; + points_r[1] = mins + Vector(x, 0, 0); + points_r[2] = mins + Vector(x, y, 0); + points_r[3] = mins + Vector(0, y, 0); + points_r[4] = mins + Vector(0, 0, z); + points_r[5] = mins + Vector(x, 0, z); + points_r[6] = mins + Vector(x, y, z); + points_r[7] = mins + Vector(0, y, z); + + // Check if any point of the box isnt on the screen + bool success = true; + for (int i = 0; i < 8; i++) { + if (!draw::WorldToScreen(points_r[i], points[i])) success = false; + } + // If a point isnt on the screen, return here + if (!success) return false; + + // Get max and min of the box using the newly created screen vector + int max_x = -1; + int max_y = -1; + int min_x = 65536; + int min_y = 65536; + for (int i = 0; i < 8; i++) { + if (points[i].x > max_x) max_x = points[i].x; + if (points[i].y > max_y) max_y = points[i].y; + if (points[i].x < min_x) min_x = points[i].x; + if (points[i].y < min_y) min_y = points[i].y; + } + + // Save the info to the esp data and notify cached that we cached info. + ent_data.collide_max = Vector(max_x, max_y, 0); + ent_data.collide_min = Vector(min_x, min_y, 0); + ent_data.has_collide = true; + + return true; + } else { + // We already have collidable so return true. + return true; + } + // Impossible error, return false + return false; +} + // Sets an entitys esp color void SetEntityColor(CachedEntity* entity, const rgba_t& color) { data[entity->m_IDX].color = color; @@ -97,6 +176,7 @@ void AddEntityString(CachedEntity* entity, const std::string& string, const rgba void BoxCorners(int minx, int miny, int maxx, int maxy, const rgba_t& color, bool transparent) { const rgba_t& black = transparent ? colors::Transparent(colors::black) : colors::black; const int size = box_corner_size; + // Black corners // Top Left drawgl::FilledRect(minx, miny, size, 3, black); @@ -182,117 +262,34 @@ void Draw() { } } - -// TODO, Unknown, find what this does -const Vector dims_player[] = { { -16, -16, -4 }, { 16, 16, 72 } }; - // Draw a box around a player -void _FASTCALL DrawBox(CachedEntity* ent, const rgba_t& clr, bool healthbar, int health, int healthmax) { +void _FASTCALL DrawBox(CachedEntity* ent, const rgba_t& clr) { PROF_SECTION(PT_esp_drawbox); // Unknown - // Potentially un-used vars - //Vector so, omin, omax, smin, smax; - //float height, width; - // Check if ent is bad to prevent crashes if (CE_BAD(ent)) return; - // Get collision center, max, and mins - const Vector& origin = RAW_ENT(ent)->GetCollideable()->GetCollisionOrigin(); - Vector mins = RAW_ENT(ent)->GetCollideable()->OBBMins() + origin; - Vector maxs = RAW_ENT(ent)->GetCollideable()->OBBMaxs() + origin; - - // Unknown - data.at(ent->m_IDX).esp_origin.Zero(); - - // Create a array for storing box points - Vector points_r[8]; // World vectors - Vector points[8]; // Screen vectors - - // If user setting for box expnad is true, spread the max and mins - if (box_expand) { - const float& exp = (float)box_expand; - maxs.x += exp; - maxs.y += exp; - maxs.z += exp; - mins.x -= exp; - mins.y -= exp; - mins.z -= exp; - } - - // Create points for the box based on max and mins - float x = maxs.x - mins.x; - float y = maxs.y - mins.y; - float z = maxs.z - mins.z; - points_r[0] = mins; - points_r[1] = mins + Vector(x, 0, 0); - points_r[2] = mins + Vector(x, y, 0); - points_r[3] = mins + Vector(0, y, 0); - points_r[4] = mins + Vector(0, 0, z); - points_r[5] = mins + Vector(x, 0, z); - points_r[6] = mins + Vector(x, y, z); - points_r[7] = mins + Vector(0, y, z); + // Get our collidable bounds + if (!GetCollide(ent)) return; - // Check if any point of the box isnt on the screen - bool success = true; - for (int i = 0; i < 8; i++) { - if (!draw::WorldToScreen(points_r[i], points[i])) success = false; - } - // If a point isnt on the screen, return here - if (!success) return; - - // Get max and min of the box using the newly created screen vector - int max_x = -1; - int max_y = -1; - int min_x = 65536; - int min_y = 65536; - for (int i = 0; i < 8; i++) { - if (points[i].x > max_x) max_x = points[i].x; - if (points[i].y > max_y) max_y = points[i].y; - if (points[i].x < min_x) min_x = points[i].x; - if (points[i].y < min_y) min_y = points[i].y; - } - - // Put Text on the position with a switch - switch ((int)esp_box_text_position) { - case 0: { // TOP RIGHT - data.at(ent->m_IDX).esp_origin = Vector(max_x + 2, min_y, 0); - } break; - case 1: { // BOTTOM RIGHT - data.at(ent->m_IDX).esp_origin = Vector(max_x + 2, max_y - data.at(ent->m_IDX).string_count * ((int)fonts::ftgl_ESP->height), 0); - } break; - case 2: { // CENTER - } break; - case 3: { // ABOVE - data.at(ent->m_IDX).esp_origin = Vector(min_x, min_y - data.at(ent->m_IDX).string_count * ((int)fonts::ftgl_ESP->height), 0); - } break; - case 4: { // BELOW - data.at(ent->m_IDX).esp_origin = Vector(min_x, max_y, 0); - } - } + // Pull the cached collide info + ESPData& ent_data = data[ent->m_IDX]; + int max_x = ent_data.collide_max.x; + int max_y = ent_data.collide_max.y; + int min_x = ent_data.collide_min.x; + int min_y = ent_data.collide_min.y; // Depending on whether the player is cloaked, we change the color acordingly - rgba_t border = ((ent->m_iClassID == RCC_PLAYER) && IsPlayerInvisible(ent)) ? colors::FromRGBA8(160, 160, 160, clr.a * 255.0f) : colors::Transparent(colors::black, clr.a); + rgba_t border = ((ent->m_iClassID == RCC_PLAYER) && IsPlayerInvisible(ent)) ? colors::FromRGBA8(160, 160, 160, clr.a * 255.0f) : colors::Transparent(colors::black , clr.a); - // If box nodraw isnt true, we can draw our box - if (!box_nodraw) { - // With box corners, we draw differently - if (box_corners) - BoxCorners(min_x, min_y, max_x, max_y, clr, (clr.a != 1.0f)); - // Otherwise, we just do simple draw funcs - else { - drawgl::Rect(min_x, min_y, max_x - min_x, max_y - min_y, border); - drawgl::Rect(min_x + 1, min_y + 1, max_x - min_x - 2, max_y - min_y - 2, clr); - drawgl::Rect(min_x + 2, min_y + 2, max_x - min_x - 4, max_y - min_y - 4, border); - } - } - - // If healthbar is enabled, create one here - if (healthbar) { - rgba_t hp = colors::Transparent(colors::Health(health, healthmax), clr.a); - int hbh = (max_y - min_y - 2) * min((float)health / (float)healthmax, 1.0f); - drawgl::Rect(min_x - 7, min_y, 7, max_y - min_y, border); - drawgl::FilledRect(min_x - 6, max_y - hbh - 1, 5, hbh, hp); + // With box corners, we draw differently + if (box_corners) + BoxCorners(min_x, min_y, max_x, max_y, clr, (clr.a != 1.0f)); + // Otherwise, we just do simple draw funcs + else { + drawgl::Rect(min_x, min_y, max_x - min_x, max_y - min_y, border); + drawgl::Rect(min_x + 1, min_y + 1, max_x - min_x - 2, max_y - min_y - 2, clr); + drawgl::Rect(min_x + 2, min_y + 2, max_x - min_x - 4, max_y - min_y - 4, border); } } @@ -701,7 +698,6 @@ CatVar emoji_min_size(CV_INT, "esp_emoji_min_size", "20", "Emoji ESP min size", textures::AtlasTexture joy_texture(64 * 4, textures::atlas_height - 64 * 4, 64, 64); textures::AtlasTexture thinking_texture(64 * 5, textures::atlas_height - 64 * 4, 64, 64); - //CatVar draw_hitbox(CV_SWITCH, "esp_hitbox", "1", "Draw Hitbox"); @@ -724,8 +720,8 @@ void _FASTCALL ProcessEntityPT(CachedEntity* ent) { Vector screen, origin_screen; if (!draw::EntityCenterToScreen(ent, screen) && !draw::WorldToScreen(ent->m_vecOrigin, origin_screen)) return; - // Unknown - ent_data.esp_origin.Zero(); + // Reset the collide cache + ent_data.has_collide = false; // Get if ent should be transparent bool transparent = false; @@ -781,6 +777,134 @@ void _FASTCALL ProcessEntityPT(CachedEntity* ent) { } } } + + // Box esp + if (box_esp) { + switch (ent->m_Type) { + case ENTITY_PLAYER: + if (vischeck && !ent->IsVisible()) transparent = true; + if (!fg) fg = colors::EntityF(ent); + if (transparent) fg = colors::Transparent(fg); + DrawBox(ent, fg); + break; + case ENTITY_BUILDING: + if (CE_INT(ent, netvar.iTeamNum) == g_pLocalPlayer->team && !teammates) break; + if (!transparent && vischeck && !ent->IsVisible()) transparent = true; + if (!fg) fg = colors::EntityF(ent); + if (transparent) fg = colors::Transparent(fg); + DrawBox(ent, fg); + break; + } + } + + // Healthbar + if (box_healthbar) { + + // We only want health bars on players and buildings + if (ent->m_Type == ENTITY_PLAYER || ent->m_Type == ENTITY_BUILDING) { + + // Get collidable from the cache + if (GetCollide(ent)) { + + // Pull the cached collide info + int max_x = ent_data.collide_max.x; + int max_y = ent_data.collide_max.y; + int min_x = ent_data.collide_min.x; + int min_y = ent_data.collide_min.y; + + // Get health values + int health = 0; + int healthmax = 0; + switch (ent->m_Type) { + case ENTITY_PLAYER: + health = CE_INT(ent, netvar.iHealth); + healthmax = ent->m_iMaxHealth; + break; + case ENTITY_BUILDING: + health = CE_INT(ent, netvar.iBuildingHealth); + healthmax = CE_INT(ent, netvar.iBuildingMaxHealth); + break; + } + + // Get Colors + rgba_t hp = colors::Transparent(colors::Health(health, healthmax), fg.a); + rgba_t border = ((ent->m_iClassID == RCC_PLAYER) && IsPlayerInvisible(ent)) ? colors::FromRGBA8(160, 160, 160, fg.a * 255.0f) : colors::Transparent(colors::black, fg.a); + // Get bar height + int hbh = (max_y - min_y - 2) * min((float)health / (float)healthmax, 1.0f); + + // Draw + drawgl::Rect(min_x - 7, min_y, 7, max_y - min_y, border); + drawgl::FilledRect(min_x - 6, max_y - hbh - 1, 5, hbh, hp); + } + } + } + + // Check if entity has strings to draw + if (ent_data.string_count) { + PROF_SECTION(PT_esp_drawstrings); // WHY IS PROF SECTION NEEDED HERE... WHYYYY + + // Create our initial point at the center of the entity + Vector draw_point = screen; + bool origin_is_zero = true; + + // Get collidable from the cache + if (GetCollide(ent)) { + + // Origin could change so we set to false + origin_is_zero = false; + + // Pull the cached collide info + int max_x = ent_data.collide_max.x; + int max_y = ent_data.collide_max.y; + int min_x = ent_data.collide_min.x; + int min_y = ent_data.collide_min.y; + + // Change the position of the draw point depending on the user settings + switch ((int)esp_box_text_position) { + case 0: { // TOP RIGHT + draw_point = Vector(max_x + 2, min_y, 0); + } break; + case 1: { // BOTTOM RIGHT + draw_point = Vector(max_x + 2, max_y - data.at(ent->m_IDX).string_count * ((int)fonts::ftgl_ESP->height), 0); + } break; + case 2: { // CENTER + origin_is_zero = true; // origin is still zero so we set to true + } break; + case 3: { // ABOVE + draw_point = Vector(min_x, min_y - data.at(ent->m_IDX).string_count * ((int)fonts::ftgl_ESP->height), 0); + } break; + case 4: { // BELOW + draw_point = Vector(min_x, max_y, 0); + } + } + } + + // if user setting allows vis check and ent isnt visable, make transparent + if (vischeck && !ent->IsVisible()) transparent = true; + + // Loop through strings + for (int j = 0; j < ent_data.string_count; j++) { + + // Pull string from the entity's cached string array + const ESPString& string = ent_data.strings[j]; + + // If string has a color assined to it, apply that otherwise use entities color + rgba_t color = string.color ? string.color : ent_data.color; + if (transparent) color = colors::Transparent(color); // Apply transparency if needed + + // If the origin is centered, we use one method. if not, the other + if (!origin_is_zero) { + FTGL_Draw(string.data, draw_point.x, draw_point.y, fonts::ftgl_ESP, color); + } else { + int size_x; + FTGL_StringLength(string.data, fonts::ftgl_ESP, &size_x); + FTGL_Draw(string.data, draw_point.x - size_x / 2, draw_point.y, fonts::ftgl_ESP, color); + } + + // Add to the y due to their being text in that spot + draw_point.y += (int)fonts::ftgl_ESP->height - 1; + } + } // TODO Add Rotation matix // TODO Currently crashes, needs null check somewhere @@ -826,49 +950,6 @@ void _FASTCALL ProcessEntityPT(CachedEntity* ent) { } } }*/ - - // Box esp - if (box_esp) { - switch (ent->m_Type) { - case ENTITY_PLAYER: - if (vischeck && !ent->IsVisible()) transparent = true; - if (!fg) fg = colors::EntityF(ent); - if (transparent) fg = colors::Transparent(fg); - DrawBox(ent, fg, static_cast(box_healthbar), CE_INT(ent, netvar.iHealth), ent->m_iMaxHealth); - break; - case ENTITY_BUILDING: - if (CE_INT(ent, netvar.iTeamNum) == g_pLocalPlayer->team && !teammates) break; - if (!transparent && vischeck && !ent->IsVisible()) transparent = true; - if (!fg) fg = colors::EntityF(ent); - if (transparent) fg = colors::Transparent(fg); - DrawBox(ent, fg, static_cast(box_healthbar), CE_INT(ent, netvar.iBuildingHealth), CE_INT(ent, netvar.iBuildingMaxHealth)); - break; - } - } - - // Draw strings ??? - // TODO reverse this - bool origin_is_zero = !box_esp || ent_data.esp_origin.IsZero(1.0f); - if (origin_is_zero) ent_data.esp_origin = screen; - if (ent_data.string_count) { - PROF_SECTION(PT_esp_drawstrings); - if (vischeck && !ent->IsVisible()) transparent = true; - Vector draw_point = origin_is_zero ? screen : ent_data.esp_origin; - for (int j = 0; j < ent_data.string_count; j++) { - const ESPString& string = ent_data.strings[j]; - rgba_t color = string.color ? string.color : ent_data.color; - if (transparent) color = colors::Transparent(color); - if (!origin_is_zero) { - FTGL_Draw(string.data, draw_point.x, draw_point.y, fonts::ftgl_ESP, color); - draw_point.y += (int)fonts::ftgl_ESP->height - 1; - } else { - int size_x; - FTGL_StringLength(string.data, fonts::ftgl_ESP, &size_x); - FTGL_Draw(string.data, draw_point.x - size_x / 2, draw_point.y, fonts::ftgl_ESP, color); - draw_point.y += (int)fonts::ftgl_ESP->height - 1; - } - } - } } }}} diff --git a/src/hacks/ESP.h b/src/hacks/ESP.h index fc0e9f66..f00b63d0 100644 --- a/src/hacks/ESP.h +++ b/src/hacks/ESP.h @@ -63,12 +63,13 @@ public: class ESPData { public: - rgba_t color { colors::empty }; int string_count { 0 }; std::array strings {}; - Vector esp_origin { 0, 0, 0 }; - Vector last_origin { 0, 0, 0 }; + rgba_t color { colors::empty }; bool needs_paint { false }; + bool has_collide { false }; + Vector collide_max { 0, 0, 0 }; + Vector collide_min { 0, 0, 0 }; }; extern std::array data; diff --git a/src/hacks/Misc.cpp b/src/hacks/Misc.cpp index 82a67464..29c26497 100644 --- a/src/hacks/Misc.cpp +++ b/src/hacks/Misc.cpp @@ -30,8 +30,6 @@ namespace hacks { namespace shared { namespace misc { -//static CatVar remove_conditions(CV_SWITCH, "remove_conditions", "0", "Remove conditions"); - static CatVar render_zoomed(CV_SWITCH, "render_zoomed", "0", "Render model when zoomed-in", "Renders player model while being zoomed in as Sniper"); void* C_TFPlayer__ShouldDraw_original = nullptr; diff --git a/src/hooks/others.cpp b/src/hooks/others.cpp index d3649112..2b5d0870 100644 --- a/src/hooks/others.cpp +++ b/src/hooks/others.cpp @@ -259,7 +259,7 @@ CatVar namesteal(namesteal_enum, "name_stealer", "0", "Name Stealer", "Attemt to static std::string stolen_name; -// Func to get a new entity to steal name from +// Func to get a new entity to steal name from and returns true if a target has been found bool StolenName(){ // Array to store potential namestealer targets with a bookkeeper to tell how full it is From 1ad88b38c7bb865f3625769f771048cce51959db Mon Sep 17 00:00:00 2001 From: julianacat Date: Thu, 17 Aug 2017 19:23:49 -0500 Subject: [PATCH 2/5] Menu Restructure --- data/menu.json | 47 ++++++------- src/hacks/ESP.cpp | 173 +++++++++++++++++++++++++--------------------- 2 files changed, 115 insertions(+), 105 deletions(-) diff --git a/data/menu.json b/data/menu.json index 3da12337..2eae323a 100644 --- a/data/menu.json +++ b/data/menu.json @@ -156,34 +156,31 @@ "name": "ESP", "list": [ "esp_enabled", - "esp_bones", - "esp_conds", - "esp_class", - "esp_name", - "esp_distance", - "esp_ubercharge", "esp_box", - "esp_box_text_position", - "esp_box_nodraw", - "esp_box_expand", - "esp_box_healthbar", - "esp_box_corners", "esp_box_corner_size", - "esp_legit", - "esp_health_num", - "esp_weapon_spawners", - "esp_model_name", - "esp_weapon", - "esp_vischeck", - "esp_show_tank", - "esp_entity_id", - "esp_followbot_id", - "esp_teammates", - "esp_entity", - "esp_buildings", - "esp_local", - "esp_powerups", + "esp_health", + "esp_expand", "esp_tracers", + "esp_text_position", + "esp_legit", + "esp_vischeck", + "esp_bones", + "esp_buildings", + "esp_teammates", + "esp_name", + "esp_class", + "esp_distance", + "esp_conds", + "esp_ubercharge", + "esp_weapon", + "esp_powerups", + "esp_show_tank", + "esp_weapon_spawners", + "esp_followbot_id", + "esp_local", + "esp_entity", + "esp_model_name", + "esp_entity_id", { "type": "list", "name": "Emoji ESP", diff --git a/src/hacks/ESP.cpp b/src/hacks/ESP.cpp index 9a518518..6b3bd263 100644 --- a/src/hacks/ESP.cpp +++ b/src/hacks/ESP.cpp @@ -11,57 +11,72 @@ #include "../sdk.h" namespace hacks { namespace shared { namespace esp { - -CatVar show_weapon(CV_SWITCH, "esp_weapon", "1", "Show weapon name", "Show which weapon does the enemy use"); + +// Main Switch +CatVar enabled(CV_SWITCH, "esp_enabled", "0", "ESP", "Master ESP switch"); +// Box esp + Options +CatEnum box_esp_enum({ "None", "Normal", "Corners" }); +CatVar box_esp(box_esp_enum, "esp_box", "2", "Box", "Draw a 2D box"); +CatVar box_corner_size(CV_INT, "esp_box_corner_size", "10", "Corner Size"); +// Tracers CatEnum tracers_enum({ "OFF", "CENTER", "BOTTOM" }); CatVar tracers(tracers_enum, "esp_tracers", "0", "Tracers", "SDraws a line from the player to a position on your screen"); +// Emoji Esp +CatEnum emoji_esp_enum({ "None", "Joy", "Thinking" }); +CatVar emoji_esp(emoji_esp_enum, "esp_emoji", "0", "Emoji ESP", "Draw emoji on peopels head"); +CatVar emoji_esp_size(CV_FLOAT, "esp_emoji_size", "32", "Emoji ESP Size"); +CatVar emoji_esp_scaling(CV_SWITCH, "esp_emoji_scaling", "1", "Emoji ESP Scaling"); +CatVar emoji_min_size(CV_INT, "esp_emoji_min_size", "20", "Emoji ESP min size", "Minimum size for an emoji when you use auto scaling"); +// Other esp options +CatEnum show_health_enum({ "None", "Text", "Healthbar", "Both" }); +CatVar show_health(show_health_enum, "esp_health", "3", "Health ESP", "Show enemy health"); +CatVar draw_bones(CV_SWITCH, "esp_bones", "0", "Draw Bones"); +CatEnum esp_text_position_enum({"TOP RIGHT", "BOTTOM RIGHT", "CENTER", "ABOVE", "BELOW" }); +CatVar esp_text_position(esp_text_position_enum, "esp_text_position", "0", "Text position", "Defines text position"); +CatVar esp_expand(CV_INT, "esp_expand", "0", "Expand Esp", "Spreads out Box, health bar, and text from center"); // Note, check if this should be int, it is being used by casting as float +CatVar vischeck(CV_SWITCH, "esp_vischeck", "1", "VisCheck", "ESP visibility check - makes enemy info behind walls darker, disable this if you get FPS drops"); +CatVar legit(CV_SWITCH, "esp_legit", "0", "Legit Mode", "Don't show invisible enemies\nHides invisable enemies with visibility enabled"); +// Selective esp options CatVar local_esp(CV_SWITCH, "esp_local", "1", "ESP Local Player", "Shows local player ESP in thirdperson"); CatVar buildings(CV_SWITCH, "esp_buildings", "1", "Building ESP", "Show buildings"); -CatVar enabled(CV_SWITCH, "esp_enabled", "0", "ESP", "Master ESP switch"); -CatVar entity_info(CV_SWITCH, "esp_entity", "0", "Entity ESP", "Show entity info (debug)"); CatVar teammates(CV_SWITCH, "esp_teammates", "0", "ESP Teammates", "Teammate ESP"); -CatVar item_esp(CV_SWITCH, "esp_item", "1", "Item ESP", "Master Item ESP switch (health packs, etc.)"); -CatVar show_bot_id(CV_SWITCH, "esp_followbot_id", "1", "Followbot ESP", "Show followbot ID"); -CatVar item_dropped_weapons(CV_SWITCH, "esp_item_weapons", "0", "Dropped weapons", "Show dropped weapons"); -CatVar item_ammo_packs(CV_SWITCH, "esp_item_ammo", "0", "Ammo packs", "Show ammo packs"); -CatVar item_health_packs(CV_SWITCH, "esp_item_health", "1", "Health packs", "Show health packs"); -CatVar item_powerups(CV_SWITCH, "esp_item_powerups", "1", "Powerups", "Show powerups"); -CatVar item_money(CV_SWITCH, "esp_money", "1", "MvM money", "Show MvM money"); -CatVar item_money_red(CV_SWITCH, "esp_money_red", "1", "Red MvM money", "Show red MvM money"); -CatVar item_spellbooks(CV_SWITCH, "esp_spellbooks", "1", "Spellbooks", "Spell Books"); -CatVar entity_id(CV_SWITCH, "esp_entity_id", "1", "Entity ID", "Used with Entity ESP. Shows entityID"); -CatVar tank(CV_SWITCH, "esp_show_tank", "1", "Show tank", "Show tank"); -CatVar box_esp(CV_SWITCH, "esp_box", "1", "Box", "Draw 2D box with healthbar. fancy."); +CatVar tank(CV_SWITCH, "esp_show_tank", "1", "Show tank", "Show tanks in mvm"); +// Text Esps +CatVar show_weapon(CV_SWITCH, "esp_weapon", "1", "Show weapon name", "Show which weapon the enemy is using"); CatVar show_distance(CV_SWITCH, "esp_distance", "1", "Distance ESP", "Show distance to target"); CatVar show_name(CV_SWITCH, "esp_name", "1", "Name ESP", "Show name"); CatVar show_class(CV_SWITCH, "esp_class", "1", "Class ESP", "Show class"); CatVar show_conditions(CV_SWITCH, "esp_conds", "1", "Conditions ESP", "Show conditions"); CatVar show_ubercharge(CV_SWITCH, "esp_ubercharge", "1", "Ubercharge ESP", "Show ubercharge percentage while players medigun is out"); -CatVar vischeck(CV_SWITCH, "esp_vischeck", "1", "VisCheck", "ESP visibility check - makes enemy info behind walls darker, disable this if you get FPS drops"); -CatVar legit(CV_SWITCH, "esp_legit", "0", "Legit Mode", "Don't show invisible enemies"); -CatVar show_health(CV_SWITCH, "esp_health_num", "1", "Health numbers", "Show health in numbers"); +CatVar show_bot_id(CV_SWITCH, "esp_followbot_id", "1", "Followbot ESP", "Show followbot ID"); +CatVar powerup_esp(CV_SWITCH, "esp_powerups", "1", "Powerup ESP", "Shows powerups a player is using"); +// Item esp +CatVar item_esp(CV_SWITCH, "esp_item", "1", "Item ESP", "Master Item ESP switch (health packs, etc.)"); +CatVar item_dropped_weapons(CV_SWITCH, "esp_item_weapons", "0", "Dropped weapons", "Show dropped weapons"); +CatVar item_ammo_packs(CV_SWITCH, "esp_item_ammo", "0", "Ammo packs", "Show ammo packs"); +CatVar item_health_packs(CV_SWITCH, "esp_item_health", "1", "Health packs", "Show health packs"); +CatVar item_powerups(CV_SWITCH, "esp_item_powerups", "1", "Powerups", "Shows powerups in the world"); +CatVar item_money(CV_SWITCH, "esp_money", "1", "MvM money", "Show MvM money"); +CatVar item_money_red(CV_SWITCH, "esp_money_red", "1", "Red MvM money", "Show red MvM money"); +CatVar item_spellbooks(CV_SWITCH, "esp_spellbooks", "1", "Spellbooks", "Spell Books"); +CatVar item_weapon_spawners(CV_SWITCH, "esp_weapon_spawners", "1", "Show weapon spawners", "TF2C deathmatch weapon spawners"); +CatVar item_adrenaline(CV_SWITCH, "esp_item_adrenaline", "0", "Show Adrenaline", "TF2C adrenaline pills"); +// Projectile esp +CatVar proj_esp(CV_SWITCH, "esp_proj", "1", "Projectile ESP", "Projectile ESP"); CatEnum proj_esp_enum({ "OFF", "ALL", "CRIT" }); CatVar proj_rockets(proj_esp_enum, "esp_proj_rockets", "1", "Rockets", "Rockets"); CatVar proj_arrows(proj_esp_enum, "esp_proj_arrows", "1", "Arrows", "Arrows"); CatVar proj_pipes(proj_esp_enum, "esp_proj_pipes", "1", "Pipes", "Pipebombs"); CatVar proj_stickies(proj_esp_enum, "esp_proj_stickies", "1", "Stickies", "Stickybombs"); CatVar proj_enemy(CV_SWITCH, "esp_proj_enemy", "1", "Only enemy projectiles", "Don't show friendly projectiles"); -CatVar proj_esp(CV_SWITCH, "esp_proj", "1", "Projectile ESP", "Projectile ESP"); +// Debug +CatVar entity_info(CV_SWITCH, "esp_entity", "0", "Entity ESP", "Show entity info (debug)"); CatVar entity_model(CV_SWITCH, "esp_model_name", "0", "Model name ESP", "Model name esp (DEBUG ONLY)"); -CatVar item_weapon_spawners(CV_SWITCH, "esp_weapon_spawners", "1", "Show weapon spawners", "TF2C deathmatch weapon spawners"); -CatVar item_adrenaline(CV_SWITCH, "esp_item_adrenaline", "0", "Show Adrenaline", "TF2C adrenaline pills"); -CatVar box_healthbar(CV_SWITCH, "esp_box_healthbar", "1", "Box Healthbar"); -CatVar draw_bones(CV_SWITCH, "esp_bones", "0", "Draw Bone ID's"); -CatVar box_corner_size(CV_INT, "esp_box_corner_size", "10", "Corner Size"); -CatEnum esp_box_text_position_enum({"TOP RIGHT", "BOTTOM RIGHT", "CENTER", "ABOVE", "BELOW" }); -CatVar esp_box_text_position(esp_box_text_position_enum, "esp_box_text_position", "0", "Text position", "Defines text position"); -CatVar box_nodraw(CV_SWITCH, "esp_box_nodraw", "0", "Invisible 2D Box", "Don't draw 2D box"); -CatVar box_expand(CV_INT, "esp_box_expand", "0", "Expand 2D Box", "Expand 2D box by N units"); -CatVar box_corners(CV_SWITCH, "esp_box_corners", "1", "Box Corners"); -CatVar powerup_esp(CV_SWITCH, "esp_powerups", "1", "Powerup ESP"); +CatVar entity_id(CV_SWITCH, "esp_entity_id", "1", "Entity ID", "Used with Entity ESP. Shows entityID"); -// Storage arrays for keeping strings and other data +// Unknown std::mutex threadsafe_mutex; +// Storage array for keeping strings and other data std::array data; // Storage vars for entities that need to be re-drawn @@ -99,8 +114,8 @@ bool GetCollide(CachedEntity* ent) { Vector points[8]; // Screen vectors // If user setting for box expnad is true, spread the max and mins - if (box_expand) { - const float& exp = (float)box_expand; + if (esp_expand) { + const float& exp = (float)esp_expand; maxs.x += exp; maxs.y += exp; maxs.z += exp; @@ -280,10 +295,10 @@ void _FASTCALL DrawBox(CachedEntity* ent, const rgba_t& clr) { int min_y = ent_data.collide_min.y; // Depending on whether the player is cloaked, we change the color acordingly - rgba_t border = ((ent->m_iClassID == RCC_PLAYER) && IsPlayerInvisible(ent)) ? colors::FromRGBA8(160, 160, 160, clr.a * 255.0f) : colors::Transparent(colors::black , clr.a); + rgba_t border = ((ent->m_iClassID == RCC_PLAYER) && IsPlayerInvisible(ent)) ? colors::FromRGBA8(160, 160, 160, clr.a * 255.0f) : colors::Transparent(colors::black, clr.a); // With box corners, we draw differently - if (box_corners) + if ((int)box_esp == 2) BoxCorners(min_x, min_y, max_x, max_y, clr, (clr.a != 1.0f)); // Otherwise, we just do simple draw funcs else { @@ -445,8 +460,8 @@ void _FASTCALL ProcessEntity(CachedEntity* ent) { int level = CE_INT(ent, netvar.iUpgradeLevel); AddEntityString(ent, format("LV ", level, ' ', name)); } - // If show health is true, then add a string with the health - if (show_health) { + // If text health is true, then add a string with the health + if ((int)show_health == 1 || (int)show_health == 3) { AddEntityString(ent, format(ent->m_iHealth, '/', ent->m_iMaxHealth, " HP"), colors::Health(ent->m_iHealth, ent->m_iMaxHealth)); } // Set the entity to repaint @@ -508,7 +523,7 @@ void _FASTCALL ProcessEntity(CachedEntity* ent) { } #endif // Health esp - if (show_health) { + if ((int)show_health == 1 || (int)show_health == 3) { AddEntityString(ent, format(ent->m_iHealth, '/', ent->m_iMaxHealth, " HP"), colors::Health(ent->m_iHealth, ent->m_iMaxHealth)); } IF_GAME (IsTF()) { @@ -686,17 +701,7 @@ struct bonelist_s { std::unordered_map bonelist_map {}; -/* - * According to profiler, this function is the most time-consuming (and gets called up to 200K times a second) - */ -CatEnum emoji_esp_enum({ "None", "Joy", "Thinking" }); -CatVar emoji_esp(emoji_esp_enum, "esp_emoji", "0", "Emoji ESP", "Draw emoji on peopels head"); -CatVar emoji_esp_size(CV_FLOAT, "esp_emoji_size", "32", "Emoji ESP Size"); -CatVar emoji_esp_scaling(CV_SWITCH, "esp_emoji_scaling", "1", "Emoji ESP Scaling"); -CatVar emoji_min_size(CV_INT, "esp_emoji_min_size", "20", "Emoji ESP min size", "Minimum size for an emoji when you use auto scaling"); -textures::AtlasTexture joy_texture(64 * 4, textures::atlas_height - 64 * 4, 64, 64); -textures::AtlasTexture thinking_texture(64 * 5, textures::atlas_height - 64 * 4, 64, 64); //CatVar draw_hitbox(CV_SWITCH, "esp_hitbox", "1", "Draw Hitbox"); @@ -757,8 +762,12 @@ void _FASTCALL ProcessEntityPT(CachedEntity* ent) { } // Emoji esp - if (ent->m_Type == ENTITY_PLAYER) { - if (emoji_esp) { + if (emoji_esp) { + if (ent->m_Type == ENTITY_PLAYER) { + // Positions in the atlas for the textures + static textures::AtlasTexture joy_texture(64 * 4, textures::atlas_height - 64 * 4, 64, 64); + static textures::AtlasTexture thinking_texture(64 * 5, textures::atlas_height - 64 * 4, 64, 64); + auto hb = ent->hitboxes.GetHitbox(0); Vector hbm, hbx; if (draw::WorldToScreen(hb->min, hbm) && draw::WorldToScreen(hb->max, hbx)) { @@ -798,7 +807,7 @@ void _FASTCALL ProcessEntityPT(CachedEntity* ent) { } // Healthbar - if (box_healthbar) { + if ((int)show_health >= 2) { // We only want health bars on players and buildings if (ent->m_Type == ENTITY_PLAYER || ent->m_Type == ENTITY_BUILDING) { @@ -847,35 +856,39 @@ void _FASTCALL ProcessEntityPT(CachedEntity* ent) { Vector draw_point = screen; bool origin_is_zero = true; - // Get collidable from the cache - if (GetCollide(ent)) { + // Only get collidable for players and buildings + if (ent->m_Type == ENTITY_PLAYER || ent->m_Type == ENTITY_BUILDING) { - // Origin could change so we set to false - origin_is_zero = false; - - // Pull the cached collide info - int max_x = ent_data.collide_max.x; - int max_y = ent_data.collide_max.y; - int min_x = ent_data.collide_min.x; - int min_y = ent_data.collide_min.y; - - // Change the position of the draw point depending on the user settings - switch ((int)esp_box_text_position) { - case 0: { // TOP RIGHT - draw_point = Vector(max_x + 2, min_y, 0); - } break; - case 1: { // BOTTOM RIGHT - draw_point = Vector(max_x + 2, max_y - data.at(ent->m_IDX).string_count * ((int)fonts::ftgl_ESP->height), 0); - } break; - case 2: { // CENTER - origin_is_zero = true; // origin is still zero so we set to true - } break; - case 3: { // ABOVE - draw_point = Vector(min_x, min_y - data.at(ent->m_IDX).string_count * ((int)fonts::ftgl_ESP->height), 0); - } break; - case 4: { // BELOW - draw_point = Vector(min_x, max_y, 0); - } + // Get collidable from the cache + if (GetCollide(ent)) { + + // Origin could change so we set to false + origin_is_zero = false; + + // Pull the cached collide info + int max_x = ent_data.collide_max.x; + int max_y = ent_data.collide_max.y; + int min_x = ent_data.collide_min.x; + int min_y = ent_data.collide_min.y; + + // Change the position of the draw point depending on the user settings + switch ((int)esp_text_position) { + case 0: { // TOP RIGHT + draw_point = Vector(max_x + 2, min_y, 0); + } break; + case 1: { // BOTTOM RIGHT + draw_point = Vector(max_x + 2, max_y - data.at(ent->m_IDX).string_count * ((int)fonts::ftgl_ESP->height), 0); + } break; + case 2: { // CENTER + origin_is_zero = true; // origin is still zero so we set to true + } break; + case 3: { // ABOVE + draw_point = Vector(min_x, min_y - data.at(ent->m_IDX).string_count * ((int)fonts::ftgl_ESP->height), 0); + } break; + case 4: { // BELOW + draw_point = Vector(min_x, max_y, 0); + } + } } } From f1d060c5348ca82c1d9e06a6acf728dfe4379bcd Mon Sep 17 00:00:00 2001 From: julianacat Date: Thu, 17 Aug 2017 20:00:03 -0500 Subject: [PATCH 3/5] esp file organization --- src/hacks/ESP.cpp | 1020 ++++++++++++++++++++++----------------------- src/hacks/ESP.h | 55 +-- 2 files changed, 525 insertions(+), 550 deletions(-) diff --git a/src/hacks/ESP.cpp b/src/hacks/ESP.cpp index 6b3bd263..4a27c2bb 100644 --- a/src/hacks/ESP.cpp +++ b/src/hacks/ESP.cpp @@ -73,6 +73,8 @@ CatVar proj_enemy(CV_SWITCH, "esp_proj_enemy", "1", "Only enemy projectiles", "D CatVar entity_info(CV_SWITCH, "esp_entity", "0", "Entity ESP", "Show entity info (debug)"); CatVar entity_model(CV_SWITCH, "esp_model_name", "0", "Model name ESP", "Model name esp (DEBUG ONLY)"); CatVar entity_id(CV_SWITCH, "esp_entity_id", "1", "Entity ID", "Used with Entity ESP. Shows entityID"); + +//CatVar draw_hitbox(CV_SWITCH, "esp_hitbox", "1", "Draw Hitbox"); // Unknown std::mutex threadsafe_mutex; @@ -83,142 +85,118 @@ std::array data; std::vector entities_need_repaint {}; std::mutex entities_need_repaint_mutex {}; -// Function to reset entitys strings -void ResetEntityStrings() { - for (auto& i : data) { - i.string_count = 0; - i.color = colors::empty; - i.needs_paint = false; +// :b:one stuff needs to be up here as puting it in the header for sorting would be a pain. + +// Vars to store what bones connect to what +const std::string bonenames_leg_r[] = { "bip_foot_R", "bip_knee_R", "bip_hip_R" }; +const std::string bonenames_leg_l[] = { "bip_foot_L", "bip_knee_L", "bip_hip_L" }; +const std::string bonenames_bottom[] = { "bip_hip_R", "bip_pelvis", "bip_hip_L" }; +const std::string bonenames_spine[] = { "bip_pelvis", "bip_spine_0", "bip_spine_1", "bip_spine_2", "bip_spine_3", "bip_neck", "bip_head" }; +const std::string bonenames_arm_r[] = { "bip_upperArm_R", "bip_lowerArm_R", "bip_hand_R" }; +const std::string bonenames_arm_l[] = { "bip_upperArm_L", "bip_lowerArm_L", "bip_hand_L" }; +const std::string bonenames_up[] = { "bip_upperArm_R", "bip_spine_3", "bip_upperArm_L" }; + +// Dont fully understand struct but a guess is a group of something. +// I will return once I have enough knowlage to reverse this. +// NOTE: No idea on why we cant just use gethitbox and use the displacement on that insted of having all this extra code. Shouldnt gethitbox use cached hitboxes, if so it should be nicer on performance +struct bonelist_s { + bool setup { false }; + bool success { false }; + int leg_r[3] { 0 }; + int leg_l[3] { 0 }; + int bottom[3] { 0 }; + int spine[7] { 0 }; + int arm_r[3] { 0 }; + int arm_l[3] { 0 }; + int up[3] { 0 }; + + void Setup(const studiohdr_t* hdr) { + if (!hdr) { + setup = true; + return; + } + std::unordered_map bones {}; + for (int i = 0; i < hdr->numbones; i++) { + bones[std::string(hdr->pBone(i)->pszName())] = i; + } + try { + for (int i = 0; i < 3; i++) leg_r[i] = bones.at(bonenames_leg_r[i]); + for (int i = 0; i < 3; i++) leg_l[i] = bones.at(bonenames_leg_l[i]); + for (int i = 0; i < 3; i++) bottom[i] = bones.at(bonenames_bottom[i]); + for (int i = 0; i < 7; i++) spine[i] = bones.at(bonenames_spine[i]); + for (int i = 0; i < 3; i++) arm_r[i] = bones.at(bonenames_arm_r[i]); + for (int i = 0; i < 3; i++) arm_l[i] = bones.at(bonenames_arm_l[i]); + for (int i = 0; i < 3; i++) up[i] = bones.at(bonenames_up[i]); + success = true; + } catch (std::exception& ex) { + logging::Info("Bone list exception: %s", ex.what()); + } + setup = true; } -} -// Used for caching collidable bounds -bool GetCollide(CachedEntity* ent) { - - // Null + Dormant check to prevent crashing - if (CE_BAD(ent)) return false; - - // Grab esp data - ESPData& ent_data = data[ent->m_IDX]; - - // If entity has cached collides, return it. Otherwise generate new bounds - if (!ent_data.has_collide) { - - // Get collision center, max, and mins - const Vector& origin = RAW_ENT(ent)->GetCollideable()->GetCollisionOrigin(); - Vector mins = RAW_ENT(ent)->GetCollideable()->OBBMins() + origin; - Vector maxs = RAW_ENT(ent)->GetCollideable()->OBBMaxs() + origin; + void DrawBoneList(const matrix3x4_t* bones, int* in, int size, const rgba_t& color, const Vector& displacement) { + Vector last_screen; + Vector current_screen; + for (int i = 0; i < size; i++) { + Vector position(bones[in[i]][0][3], bones[in[i]][1][3], bones[in[i]][2][3]); + position += displacement; + if (!draw::WorldToScreen(position, current_screen)) { + return; + } + if (i > 0) { + drawgl::Line(last_screen.x, last_screen.y, current_screen.x - last_screen.x, current_screen.y - last_screen.y, color); + } + last_screen = current_screen; + } + } - // Create a array for storing box points - Vector points_r[8]; // World vectors - Vector points[8]; // Screen vectors - - // If user setting for box expnad is true, spread the max and mins - if (esp_expand) { - const float& exp = (float)esp_expand; - maxs.x += exp; - maxs.y += exp; - maxs.z += exp; - mins.x -= exp; - mins.y -= exp; - mins.z -= exp; + void Draw(CachedEntity* ent, const rgba_t& color) { + const model_t* model = RAW_ENT(ent)->GetModel(); + if (not model) { + return; } - // Create points for the box based on max and mins - float x = maxs.x - mins.x; - float y = maxs.y - mins.y; - float z = maxs.z - mins.z; - points_r[0] = mins; - points_r[1] = mins + Vector(x, 0, 0); - points_r[2] = mins + Vector(x, y, 0); - points_r[3] = mins + Vector(0, y, 0); - points_r[4] = mins + Vector(0, 0, z); - points_r[5] = mins + Vector(x, 0, z); - points_r[6] = mins + Vector(x, y, z); - points_r[7] = mins + Vector(0, y, z); + studiohdr_t* hdr = g_IModelInfo->GetStudiomodel(model); - // Check if any point of the box isnt on the screen - bool success = true; - for (int i = 0; i < 8; i++) { - if (!draw::WorldToScreen(points_r[i], points[i])) success = false; + if (!setup) { + Setup(hdr); } - // If a point isnt on the screen, return here - if (!success) return false; + if (!success) return; - // Get max and min of the box using the newly created screen vector - int max_x = -1; - int max_y = -1; - int min_x = 65536; - int min_y = 65536; - for (int i = 0; i < 8; i++) { - if (points[i].x > max_x) max_x = points[i].x; - if (points[i].y > max_y) max_y = points[i].y; - if (points[i].x < min_x) min_x = points[i].x; - if (points[i].y < min_y) min_y = points[i].y; - } - - // Save the info to the esp data and notify cached that we cached info. - ent_data.collide_max = Vector(max_x, max_y, 0); - ent_data.collide_min = Vector(min_x, min_y, 0); - ent_data.has_collide = true; - - return true; - } else { - // We already have collidable so return true. - return true; - } - // Impossible error, return false - return false; -} - -// Sets an entitys esp color -void SetEntityColor(CachedEntity* entity, const rgba_t& color) { - data[entity->m_IDX].color = color; -} + //ent->m_bBonesSetup = false; + Vector displacement = RAW_ENT(ent)->GetAbsOrigin() - ent->m_vecOrigin; + const auto& bones = ent->hitboxes.GetBones(); + DrawBoneList(bones, leg_r, 3, color, displacement); + DrawBoneList(bones, leg_l, 3, color, displacement); + DrawBoneList(bones, bottom, 3, color, displacement); + DrawBoneList(bones, spine, 7, color, displacement); + DrawBoneList(bones, arm_r, 3, color, displacement); + DrawBoneList(bones, arm_l, 3, color, displacement); + DrawBoneList(bones, up, 3, color, displacement); + /*for (int i = 0; i < hdr->numbones; i++) { + const auto& bone = ent->GetBones()[i]; + Vector pos(bone[0][3], bone[1][3], bone[2][3]); + //pos += orig; + Vector screen; + if (draw::WorldToScreen(pos, screen)) { + if (hdr->pBone(i)->pszName()) { + draw::FString(fonts::ESP, screen.x, screen.y, fg, 2, "%s [%d]", hdr->pBone(i)->pszName(), i); + } else + draw::FString(fonts::ESP, screen.x, screen.y, fg, 2, "%d", i); + } + }*/ + } +}; -// Use to add a esp string to an entity -void AddEntityString(CachedEntity* entity, const std::string& string, const rgba_t& color) { - ESPData& entity_data = data[entity->m_IDX]; - if (entity_data.string_count >= 15) return; - entity_data.strings[entity_data.string_count].data = string; - entity_data.strings[entity_data.string_count].color = color; - entity_data.string_count++; - entity_data.needs_paint = true; -} +std::unordered_map bonelist_map {}; - -// Function to draw box corners -void BoxCorners(int minx, int miny, int maxx, int maxy, const rgba_t& color, bool transparent) { - const rgba_t& black = transparent ? colors::Transparent(colors::black) : colors::black; - const int size = box_corner_size; - - // Black corners - // Top Left - drawgl::FilledRect(minx, miny, size, 3, black); - drawgl::FilledRect(minx, miny + 3, 3, size - 3, black); - // Top Right - drawgl::FilledRect(maxx - size + 1, miny, size, 3, black); - drawgl::FilledRect(maxx - 3 + 1, miny + 3, 3, size - 3, black); - // Bottom Left - drawgl::FilledRect(minx, maxy - 3, size, 3, black); - drawgl::FilledRect(minx, maxy - size, 3, size - 3, black); - // Bottom Right - drawgl::FilledRect(maxx - size + 1, maxy - 3, size, 3, black); - drawgl::FilledRect(maxx - 2, maxy - size, 3, size - 3, black); - - // Colored corners - // Top Left - drawgl::Line(minx + 1, miny + 1, size - 2, 0, color); - drawgl::Line(minx + 1, miny + 1, 0, size - 2, color); - // Top Right - drawgl::Line(maxx - 1, miny + 1, -(size - 2), 0, color); - drawgl::Line(maxx - 1, miny + 1, 0, size - 2, color); - // Bottom Left - drawgl::Line(minx + 1, maxy - 2, size - 2, 0, color); - drawgl::Line(minx + 1, maxy - 2, 0, -(size - 2), color); - // Bottom Right - drawgl::Line(maxx - 1, maxy - 2, -(size - 2), 0, color); - drawgl::Line(maxx - 1, maxy - 2, 0, -(size - 2), color); +// Function called on draw +void Draw() { + std::lock_guard esp_lock(threadsafe_mutex); + if (!enabled) return; + for (auto& i : entities_need_repaint) { + ProcessEntityPT(ENTITY(i)); + } } // Function called on create move @@ -267,47 +245,266 @@ void CreateMove() { } } } - -// Function called on draw -void Draw() { - std::lock_guard esp_lock(threadsafe_mutex); - if (!enabled) return; - for (auto& i : entities_need_repaint) { - ProcessEntityPT(ENTITY(i)); - } -} - -// Draw a box around a player -void _FASTCALL DrawBox(CachedEntity* ent, const rgba_t& clr) { - PROF_SECTION(PT_esp_drawbox); // Unknown - // Check if ent is bad to prevent crashes +// Used when processing entitys with cached data from createmove in draw +void _FASTCALL ProcessEntityPT(CachedEntity* ent) { + PROF_SECTION(PT_esp_process_entity); + + // Check to prevent crashes if (CE_BAD(ent)) return; - // Get our collidable bounds - if (!GetCollide(ent)) return; - - // Pull the cached collide info + // Grab esp data ESPData& ent_data = data[ent->m_IDX]; - int max_x = ent_data.collide_max.x; - int max_y = ent_data.collide_max.y; - int min_x = ent_data.collide_min.x; - int min_y = ent_data.collide_min.y; + + // Get color of entity + // TODO, check if we can move this after world to screen check + rgba_t fg = ent_data.color; + if (!fg || fg.a == 0.0f) fg = ent_data.color = colors::EntityF(ent); - // Depending on whether the player is cloaked, we change the color acordingly - rgba_t border = ((ent->m_iClassID == RCC_PLAYER) && IsPlayerInvisible(ent)) ? colors::FromRGBA8(160, 160, 160, clr.a * 255.0f) : colors::Transparent(colors::black, clr.a); - - // With box corners, we draw differently - if ((int)box_esp == 2) - BoxCorners(min_x, min_y, max_x, max_y, clr, (clr.a != 1.0f)); - // Otherwise, we just do simple draw funcs - else { - drawgl::Rect(min_x, min_y, max_x - min_x, max_y - min_y, border); - drawgl::Rect(min_x + 1, min_y + 1, max_x - min_x - 2, max_y - min_y - 2, clr); - drawgl::Rect(min_x + 2, min_y + 2, max_x - min_x - 4, max_y - min_y - 4, border); + // Check if entity is on screen, then save screen position if true + Vector screen, origin_screen; + if (!draw::EntityCenterToScreen(ent, screen) && !draw::WorldToScreen(ent->m_vecOrigin, origin_screen)) return; + + // Reset the collide cache + ent_data.has_collide = false; + + // Get if ent should be transparent + bool transparent = false; + if (vischeck && !ent->IsVisible()) transparent = true; + + // Bone esp + if (draw_bones && ent->m_Type == ENTITY_PLAYER) { + const model_t* model = RAW_ENT(ent)->GetModel(); + if (model) { + auto hdr = g_IModelInfo->GetStudiomodel(model); + bonelist_map[hdr].Draw(ent, fg); + } + } + + // Tracers + if (tracers && ent->m_Type == ENTITY_PLAYER) { + + // Grab the screen resolution and save to some vars + int width, height; + g_IEngine->GetScreenSize(width, height); + + // Center values on screen + width = width / 2; + // Only center height if we are using center mode + if ((int)tracers == 1) height = height / 2; + + // Get world to screen + Vector scn; + draw::WorldToScreen(ent->m_vecOrigin, scn); + + // Draw a line + drawgl::Line(scn.x, scn.y, width - scn.x, height - scn.y, fg); } -} + // Emoji esp + if (emoji_esp) { + if (ent->m_Type == ENTITY_PLAYER) { + // Positions in the atlas for the textures + static textures::AtlasTexture joy_texture(64 * 4, textures::atlas_height - 64 * 4, 64, 64); + static textures::AtlasTexture thinking_texture(64 * 5, textures::atlas_height - 64 * 4, 64, 64); + + auto hb = ent->hitboxes.GetHitbox(0); + Vector hbm, hbx; + if (draw::WorldToScreen(hb->min, hbm) && draw::WorldToScreen(hb->max, hbx)) { + Vector head_scr; + if (draw::WorldToScreen(hb->center, head_scr)) { + float size = emoji_esp_scaling ? fabs(hbm.y - hbx.y) : float(emoji_esp_size); + if (emoji_esp_scaling && (size < float(emoji_min_size))) { + size = float(emoji_min_size); + } + textures::AtlasTexture* tx = nullptr; + if (int(emoji_esp) == 1) tx = &joy_texture; + if (int(emoji_esp) == 2) tx = &thinking_texture; + if (tx) + tx->Draw(head_scr.x - size / 2, head_scr.y - size / 2, size, size); + } + } + } + } + + // Box esp + if (box_esp) { + switch (ent->m_Type) { + case ENTITY_PLAYER: + if (vischeck && !ent->IsVisible()) transparent = true; + if (!fg) fg = colors::EntityF(ent); + if (transparent) fg = colors::Transparent(fg); + DrawBox(ent, fg); + break; + case ENTITY_BUILDING: + if (CE_INT(ent, netvar.iTeamNum) == g_pLocalPlayer->team && !teammates) break; + if (!transparent && vischeck && !ent->IsVisible()) transparent = true; + if (!fg) fg = colors::EntityF(ent); + if (transparent) fg = colors::Transparent(fg); + DrawBox(ent, fg); + break; + } + } + + // Healthbar + if ((int)show_health >= 2) { + + // We only want health bars on players and buildings + if (ent->m_Type == ENTITY_PLAYER || ent->m_Type == ENTITY_BUILDING) { + + // Get collidable from the cache + if (GetCollide(ent)) { + + // Pull the cached collide info + int max_x = ent_data.collide_max.x; + int max_y = ent_data.collide_max.y; + int min_x = ent_data.collide_min.x; + int min_y = ent_data.collide_min.y; + + // Get health values + int health = 0; + int healthmax = 0; + switch (ent->m_Type) { + case ENTITY_PLAYER: + health = CE_INT(ent, netvar.iHealth); + healthmax = ent->m_iMaxHealth; + break; + case ENTITY_BUILDING: + health = CE_INT(ent, netvar.iBuildingHealth); + healthmax = CE_INT(ent, netvar.iBuildingMaxHealth); + break; + } + + // Get Colors + rgba_t hp = colors::Transparent(colors::Health(health, healthmax), fg.a); + rgba_t border = ((ent->m_iClassID == RCC_PLAYER) && IsPlayerInvisible(ent)) ? colors::FromRGBA8(160, 160, 160, fg.a * 255.0f) : colors::Transparent(colors::black, fg.a); + // Get bar height + int hbh = (max_y - min_y - 2) * min((float)health / (float)healthmax, 1.0f); + + // Draw + drawgl::Rect(min_x - 7, min_y, 7, max_y - min_y, border); + drawgl::FilledRect(min_x - 6, max_y - hbh - 1, 5, hbh, hp); + } + } + } + + // Check if entity has strings to draw + if (ent_data.string_count) { + PROF_SECTION(PT_esp_drawstrings); // WHY IS PROF SECTION NEEDED HERE... WHYYYY + + // Create our initial point at the center of the entity + Vector draw_point = screen; + bool origin_is_zero = true; + + // Only get collidable for players and buildings + if (ent->m_Type == ENTITY_PLAYER || ent->m_Type == ENTITY_BUILDING) { + + // Get collidable from the cache + if (GetCollide(ent)) { + + // Origin could change so we set to false + origin_is_zero = false; + + // Pull the cached collide info + int max_x = ent_data.collide_max.x; + int max_y = ent_data.collide_max.y; + int min_x = ent_data.collide_min.x; + int min_y = ent_data.collide_min.y; + + // Change the position of the draw point depending on the user settings + switch ((int)esp_text_position) { + case 0: { // TOP RIGHT + draw_point = Vector(max_x + 2, min_y, 0); + } break; + case 1: { // BOTTOM RIGHT + draw_point = Vector(max_x + 2, max_y - data.at(ent->m_IDX).string_count * ((int)fonts::ftgl_ESP->height), 0); + } break; + case 2: { // CENTER + origin_is_zero = true; // origin is still zero so we set to true + } break; + case 3: { // ABOVE + draw_point = Vector(min_x, min_y - data.at(ent->m_IDX).string_count * ((int)fonts::ftgl_ESP->height), 0); + } break; + case 4: { // BELOW + draw_point = Vector(min_x, max_y, 0); + } + } + } + } + + // if user setting allows vis check and ent isnt visable, make transparent + if (vischeck && !ent->IsVisible()) transparent = true; + + // Loop through strings + for (int j = 0; j < ent_data.string_count; j++) { + + // Pull string from the entity's cached string array + const ESPString& string = ent_data.strings[j]; + + // If string has a color assined to it, apply that otherwise use entities color + rgba_t color = string.color ? string.color : ent_data.color; + if (transparent) color = colors::Transparent(color); // Apply transparency if needed + + // If the origin is centered, we use one method. if not, the other + if (!origin_is_zero) { + FTGL_Draw(string.data, draw_point.x, draw_point.y, fonts::ftgl_ESP, color); + } else { + int size_x; + FTGL_StringLength(string.data, fonts::ftgl_ESP, &size_x); + FTGL_Draw(string.data, draw_point.x - size_x / 2, draw_point.y, fonts::ftgl_ESP, color); + } + + // Add to the y due to their being text in that spot + draw_point.y += (int)fonts::ftgl_ESP->height - 1; + } + } + + // TODO Add Rotation matix + // TODO Currently crashes, needs null check somewhere + // Draw Hitboxes + /*if (draw_hitbox && ent->m_Type == ENTITY_PLAYER) { + + // Loop through hitboxes + for (int i = 0; i <= 17; i++) { // I should probs get how many hitboxes instead of using a fixed number... + + // Get a hitbox from the entity + hitbox_cache::CachedHitbox* hb = ent->hitboxes.GetHitbox(i); + + // Create more points from min + max + Vector box_points[8]; + Vector vec_tmp; + for (int ii = 0; ii <= 8; ii++) { // 8 points to the box + + // logic le paste from sdk + vec_tmp[0] = ( ii & 0x1 ) ? hb->max[0] : hb->min[0]; + vec_tmp[1] = ( ii & 0x2 ) ? hb->max[1] : hb->min[1]; + vec_tmp[2] = ( ii & 0x4 ) ? hb->max[2] : hb->min[2]; + + // save to points array + box_points[ii] = vec_tmp; + } + + // Draw box from points + // Draws a point to every other point. Ineffient, use now fix later... + Vector scn1, scn2; // to screen + for (int ii = 0; ii < 8; ii++) { + + // Get first point + if (!draw::WorldToScreen(box_points[ii], scn1)) continue; + + for (int iii = 0; iii < 8; iii++) { + + // Get second point + if (!draw::WorldToScreen(box_points[iii], scn2)) continue; + + // Draw between points + drawgl::Line(scn1.x, scn1.y, scn2.x - scn1.x, scn2.y - scn1.y, fg); + } + } + } + }*/ +} + // Used to process entities from CreateMove void _FASTCALL ProcessEntity(CachedEntity* ent) { if (!enabled) return; // Esp enable check @@ -598,371 +795,172 @@ void _FASTCALL ProcessEntity(CachedEntity* ent) { } } -// Vars to store what bones connect to what -const std::string bonenames_leg_r[] = { "bip_foot_R", "bip_knee_R", "bip_hip_R" }; -const std::string bonenames_leg_l[] = { "bip_foot_L", "bip_knee_L", "bip_hip_L" }; -const std::string bonenames_bottom[] = { "bip_hip_R", "bip_pelvis", "bip_hip_L" }; -const std::string bonenames_spine[] = { "bip_pelvis", "bip_spine_0", "bip_spine_1", "bip_spine_2", "bip_spine_3", "bip_neck", "bip_head" }; -const std::string bonenames_arm_r[] = { "bip_upperArm_R", "bip_lowerArm_R", "bip_hand_R" }; -const std::string bonenames_arm_l[] = { "bip_upperArm_L", "bip_lowerArm_L", "bip_hand_L" }; -const std::string bonenames_up[] = { "bip_upperArm_R", "bip_spine_3", "bip_upperArm_L" }; - -// Dont fully understand struct but a guess is a group of something. -// I will return once I have enough knowlage to reverse this. -// NOTE: No idea on why we cant just use gethitbox and use the displacement on that insted of having all this extra code. Shouldnt gethitbox use cached hitboxes, if so it should be nicer on performance -struct bonelist_s { - bool setup { false }; - bool success { false }; - int leg_r[3] { 0 }; - int leg_l[3] { 0 }; - int bottom[3] { 0 }; - int spine[7] { 0 }; - int arm_r[3] { 0 }; - int arm_l[3] { 0 }; - int up[3] { 0 }; - - void Setup(const studiohdr_t* hdr) { - if (!hdr) { - setup = true; - return; - } - std::unordered_map bones {}; - for (int i = 0; i < hdr->numbones; i++) { - bones[std::string(hdr->pBone(i)->pszName())] = i; - } - try { - for (int i = 0; i < 3; i++) leg_r[i] = bones.at(bonenames_leg_r[i]); - for (int i = 0; i < 3; i++) leg_l[i] = bones.at(bonenames_leg_l[i]); - for (int i = 0; i < 3; i++) bottom[i] = bones.at(bonenames_bottom[i]); - for (int i = 0; i < 7; i++) spine[i] = bones.at(bonenames_spine[i]); - for (int i = 0; i < 3; i++) arm_r[i] = bones.at(bonenames_arm_r[i]); - for (int i = 0; i < 3; i++) arm_l[i] = bones.at(bonenames_arm_l[i]); - for (int i = 0; i < 3; i++) up[i] = bones.at(bonenames_up[i]); - success = true; - } catch (std::exception& ex) { - logging::Info("Bone list exception: %s", ex.what()); - } - setup = true; - } - - void DrawBoneList(const matrix3x4_t* bones, int* in, int size, const rgba_t& color, const Vector& displacement) { - Vector last_screen; - Vector current_screen; - for (int i = 0; i < size; i++) { - Vector position(bones[in[i]][0][3], bones[in[i]][1][3], bones[in[i]][2][3]); - position += displacement; - if (!draw::WorldToScreen(position, current_screen)) { - return; - } - if (i > 0) { - drawgl::Line(last_screen.x, last_screen.y, current_screen.x - last_screen.x, current_screen.y - last_screen.y, color); - } - last_screen = current_screen; - } - } - - void Draw(CachedEntity* ent, const rgba_t& color) { - const model_t* model = RAW_ENT(ent)->GetModel(); - if (not model) { - return; - } - - studiohdr_t* hdr = g_IModelInfo->GetStudiomodel(model); - - if (!setup) { - Setup(hdr); - } - if (!success) return; - - //ent->m_bBonesSetup = false; - Vector displacement = RAW_ENT(ent)->GetAbsOrigin() - ent->m_vecOrigin; - const auto& bones = ent->hitboxes.GetBones(); - DrawBoneList(bones, leg_r, 3, color, displacement); - DrawBoneList(bones, leg_l, 3, color, displacement); - DrawBoneList(bones, bottom, 3, color, displacement); - DrawBoneList(bones, spine, 7, color, displacement); - DrawBoneList(bones, arm_r, 3, color, displacement); - DrawBoneList(bones, arm_l, 3, color, displacement); - DrawBoneList(bones, up, 3, color, displacement); - /*for (int i = 0; i < hdr->numbones; i++) { - const auto& bone = ent->GetBones()[i]; - Vector pos(bone[0][3], bone[1][3], bone[2][3]); - //pos += orig; - Vector screen; - if (draw::WorldToScreen(pos, screen)) { - if (hdr->pBone(i)->pszName()) { - draw::FString(fonts::ESP, screen.x, screen.y, fg, 2, "%s [%d]", hdr->pBone(i)->pszName(), i); - } else - draw::FString(fonts::ESP, screen.x, screen.y, fg, 2, "%d", i); - } - }*/ - } -}; - -std::unordered_map bonelist_map {}; - - +// Draw a box around a player +void _FASTCALL DrawBox(CachedEntity* ent, const rgba_t& clr) { + PROF_SECTION(PT_esp_drawbox); // Unknown -//CatVar draw_hitbox(CV_SWITCH, "esp_hitbox", "1", "Draw Hitbox"); - - -// Used when processing entitys with cached data from createmove -void _FASTCALL ProcessEntityPT(CachedEntity* ent) { - PROF_SECTION(PT_esp_process_entity); - - // Check to prevent crashes + // Check if ent is bad to prevent crashes if (CE_BAD(ent)) return; + // Get our collidable bounds + if (!GetCollide(ent)) return; + + // Pull the cached collide info + ESPData& ent_data = data[ent->m_IDX]; + int max_x = ent_data.collide_max.x; + int max_y = ent_data.collide_max.y; + int min_x = ent_data.collide_min.x; + int min_y = ent_data.collide_min.y; + + // Depending on whether the player is cloaked, we change the color acordingly + rgba_t border = ((ent->m_iClassID == RCC_PLAYER) && IsPlayerInvisible(ent)) ? colors::FromRGBA8(160, 160, 160, clr.a * 255.0f) : colors::Transparent(colors::black, clr.a); + + // With box corners, we draw differently + if ((int)box_esp == 2) + BoxCorners(min_x, min_y, max_x, max_y, clr, (clr.a != 1.0f)); + // Otherwise, we just do simple draw funcs + else { + drawgl::Rect(min_x, min_y, max_x - min_x, max_y - min_y, border); + drawgl::Rect(min_x + 1, min_y + 1, max_x - min_x - 2, max_y - min_y - 2, clr); + drawgl::Rect(min_x + 2, min_y + 2, max_x - min_x - 4, max_y - min_y - 4, border); + } +} + +// Function to draw box corners, Used by DrawBox +void BoxCorners(int minx, int miny, int maxx, int maxy, const rgba_t& color, bool transparent) { + const rgba_t& black = transparent ? colors::Transparent(colors::black) : colors::black; + const int size = box_corner_size; + + // Black corners + // Top Left + drawgl::FilledRect(minx, miny, size, 3, black); + drawgl::FilledRect(minx, miny + 3, 3, size - 3, black); + // Top Right + drawgl::FilledRect(maxx - size + 1, miny, size, 3, black); + drawgl::FilledRect(maxx - 3 + 1, miny + 3, 3, size - 3, black); + // Bottom Left + drawgl::FilledRect(minx, maxy - 3, size, 3, black); + drawgl::FilledRect(minx, maxy - size, 3, size - 3, black); + // Bottom Right + drawgl::FilledRect(maxx - size + 1, maxy - 3, size, 3, black); + drawgl::FilledRect(maxx - 2, maxy - size, 3, size - 3, black); + + // Colored corners + // Top Left + drawgl::Line(minx + 1, miny + 1, size - 2, 0, color); + drawgl::Line(minx + 1, miny + 1, 0, size - 2, color); + // Top Right + drawgl::Line(maxx - 1, miny + 1, -(size - 2), 0, color); + drawgl::Line(maxx - 1, miny + 1, 0, size - 2, color); + // Bottom Left + drawgl::Line(minx + 1, maxy - 2, size - 2, 0, color); + drawgl::Line(minx + 1, maxy - 2, 0, -(size - 2), color); + // Bottom Right + drawgl::Line(maxx - 1, maxy - 2, -(size - 2), 0, color); + drawgl::Line(maxx - 1, maxy - 2, 0, -(size - 2), color); +} + +// Used for caching collidable bounds +bool GetCollide(CachedEntity* ent) { + + // Null + Dormant check to prevent crashing + if (CE_BAD(ent)) return false; + // Grab esp data ESPData& ent_data = data[ent->m_IDX]; - - // Get color of entity - // TODO, check if we can move this after world to screen check - rgba_t fg = ent_data.color; - if (!fg || fg.a == 0.0f) fg = ent_data.color = colors::EntityF(ent); - // Check if entity is on screen, then save screen position if true - Vector screen, origin_screen; - if (!draw::EntityCenterToScreen(ent, screen) && !draw::WorldToScreen(ent->m_vecOrigin, origin_screen)) return; - - // Reset the collide cache - ent_data.has_collide = false; - - // Get if ent should be transparent - bool transparent = false; - if (vischeck && !ent->IsVisible()) transparent = true; - - // Bone esp - if (draw_bones && ent->m_Type == ENTITY_PLAYER) { - const model_t* model = RAW_ENT(ent)->GetModel(); - if (model) { - auto hdr = g_IModelInfo->GetStudiomodel(model); - bonelist_map[hdr].Draw(ent, fg); - } - } - - // Tracers - if (tracers && ent->m_Type == ENTITY_PLAYER) { - - // Grab the screen resolution and save to some vars - int width, height; - g_IEngine->GetScreenSize(width, height); - - // Center values on screen - width = width / 2; - // Only center height if we are using center mode - if ((int)tracers == 1) height = height / 2; - - // Get world to screen - Vector scn; - draw::WorldToScreen(ent->m_vecOrigin, scn); - - // Draw a line - drawgl::Line(scn.x, scn.y, width - scn.x, height - scn.y, fg); - } + // If entity has cached collides, return it. Otherwise generate new bounds + if (!ent_data.has_collide) { - // Emoji esp - if (emoji_esp) { - if (ent->m_Type == ENTITY_PLAYER) { - // Positions in the atlas for the textures - static textures::AtlasTexture joy_texture(64 * 4, textures::atlas_height - 64 * 4, 64, 64); - static textures::AtlasTexture thinking_texture(64 * 5, textures::atlas_height - 64 * 4, 64, 64); - - auto hb = ent->hitboxes.GetHitbox(0); - Vector hbm, hbx; - if (draw::WorldToScreen(hb->min, hbm) && draw::WorldToScreen(hb->max, hbx)) { - Vector head_scr; - if (draw::WorldToScreen(hb->center, head_scr)) { - float size = emoji_esp_scaling ? fabs(hbm.y - hbx.y) : float(emoji_esp_size); - if (emoji_esp_scaling && (size < float(emoji_min_size))) { - size = float(emoji_min_size); - } - textures::AtlasTexture* tx = nullptr; - if (int(emoji_esp) == 1) tx = &joy_texture; - if (int(emoji_esp) == 2) tx = &thinking_texture; - if (tx) - tx->Draw(head_scr.x - size / 2, head_scr.y - size / 2, size, size); - } - } + // Get collision center, max, and mins + const Vector& origin = RAW_ENT(ent)->GetCollideable()->GetCollisionOrigin(); + Vector mins = RAW_ENT(ent)->GetCollideable()->OBBMins() + origin; + Vector maxs = RAW_ENT(ent)->GetCollideable()->OBBMaxs() + origin; + + // Create a array for storing box points + Vector points_r[8]; // World vectors + Vector points[8]; // Screen vectors + + // If user setting for box expnad is true, spread the max and mins + if (esp_expand) { + const float& exp = (float)esp_expand; + maxs.x += exp; + maxs.y += exp; + maxs.z += exp; + mins.x -= exp; + mins.y -= exp; + mins.z -= exp; } - } - // Box esp - if (box_esp) { - switch (ent->m_Type) { - case ENTITY_PLAYER: - if (vischeck && !ent->IsVisible()) transparent = true; - if (!fg) fg = colors::EntityF(ent); - if (transparent) fg = colors::Transparent(fg); - DrawBox(ent, fg); - break; - case ENTITY_BUILDING: - if (CE_INT(ent, netvar.iTeamNum) == g_pLocalPlayer->team && !teammates) break; - if (!transparent && vischeck && !ent->IsVisible()) transparent = true; - if (!fg) fg = colors::EntityF(ent); - if (transparent) fg = colors::Transparent(fg); - DrawBox(ent, fg); - break; - } - } + // Create points for the box based on max and mins + float x = maxs.x - mins.x; + float y = maxs.y - mins.y; + float z = maxs.z - mins.z; + points_r[0] = mins; + points_r[1] = mins + Vector(x, 0, 0); + points_r[2] = mins + Vector(x, y, 0); + points_r[3] = mins + Vector(0, y, 0); + points_r[4] = mins + Vector(0, 0, z); + points_r[5] = mins + Vector(x, 0, z); + points_r[6] = mins + Vector(x, y, z); + points_r[7] = mins + Vector(0, y, z); - // Healthbar - if ((int)show_health >= 2) { + // Check if any point of the box isnt on the screen + bool success = true; + for (int i = 0; i < 8; i++) { + if (!draw::WorldToScreen(points_r[i], points[i])) success = false; + } + // If a point isnt on the screen, return here + if (!success) return false; + + // Get max and min of the box using the newly created screen vector + int max_x = -1; + int max_y = -1; + int min_x = 65536; + int min_y = 65536; + for (int i = 0; i < 8; i++) { + if (points[i].x > max_x) max_x = points[i].x; + if (points[i].y > max_y) max_y = points[i].y; + if (points[i].x < min_x) min_x = points[i].x; + if (points[i].y < min_y) min_y = points[i].y; + } - // We only want health bars on players and buildings - if (ent->m_Type == ENTITY_PLAYER || ent->m_Type == ENTITY_BUILDING) { - - // Get collidable from the cache - if (GetCollide(ent)) { - - // Pull the cached collide info - int max_x = ent_data.collide_max.x; - int max_y = ent_data.collide_max.y; - int min_x = ent_data.collide_min.x; - int min_y = ent_data.collide_min.y; + // Save the info to the esp data and notify cached that we cached info. + ent_data.collide_max = Vector(max_x, max_y, 0); + ent_data.collide_min = Vector(min_x, min_y, 0); + ent_data.has_collide = true; + + return true; + } else { + // We already have collidable so return true. + return true; + } + // Impossible error, return false + return false; +} - // Get health values - int health = 0; - int healthmax = 0; - switch (ent->m_Type) { - case ENTITY_PLAYER: - health = CE_INT(ent, netvar.iHealth); - healthmax = ent->m_iMaxHealth; - break; - case ENTITY_BUILDING: - health = CE_INT(ent, netvar.iBuildingHealth); - healthmax = CE_INT(ent, netvar.iBuildingMaxHealth); - break; - } - - // Get Colors - rgba_t hp = colors::Transparent(colors::Health(health, healthmax), fg.a); - rgba_t border = ((ent->m_iClassID == RCC_PLAYER) && IsPlayerInvisible(ent)) ? colors::FromRGBA8(160, 160, 160, fg.a * 255.0f) : colors::Transparent(colors::black, fg.a); - // Get bar height - int hbh = (max_y - min_y - 2) * min((float)health / (float)healthmax, 1.0f); - - // Draw - drawgl::Rect(min_x - 7, min_y, 7, max_y - min_y, border); - drawgl::FilledRect(min_x - 6, max_y - hbh - 1, 5, hbh, hp); - } - } - } +// Use to add a esp string to an entity +void AddEntityString(CachedEntity* entity, const std::string& string, const rgba_t& color) { + ESPData& entity_data = data[entity->m_IDX]; + if (entity_data.string_count >= 15) return; + entity_data.strings[entity_data.string_count].data = string; + entity_data.strings[entity_data.string_count].color = color; + entity_data.string_count++; + entity_data.needs_paint = true; +} - // Check if entity has strings to draw - if (ent_data.string_count) { - PROF_SECTION(PT_esp_drawstrings); // WHY IS PROF SECTION NEEDED HERE... WHYYYY - - // Create our initial point at the center of the entity - Vector draw_point = screen; - bool origin_is_zero = true; - - // Only get collidable for players and buildings - if (ent->m_Type == ENTITY_PLAYER || ent->m_Type == ENTITY_BUILDING) { - - // Get collidable from the cache - if (GetCollide(ent)) { - - // Origin could change so we set to false - origin_is_zero = false; - - // Pull the cached collide info - int max_x = ent_data.collide_max.x; - int max_y = ent_data.collide_max.y; - int min_x = ent_data.collide_min.x; - int min_y = ent_data.collide_min.y; - - // Change the position of the draw point depending on the user settings - switch ((int)esp_text_position) { - case 0: { // TOP RIGHT - draw_point = Vector(max_x + 2, min_y, 0); - } break; - case 1: { // BOTTOM RIGHT - draw_point = Vector(max_x + 2, max_y - data.at(ent->m_IDX).string_count * ((int)fonts::ftgl_ESP->height), 0); - } break; - case 2: { // CENTER - origin_is_zero = true; // origin is still zero so we set to true - } break; - case 3: { // ABOVE - draw_point = Vector(min_x, min_y - data.at(ent->m_IDX).string_count * ((int)fonts::ftgl_ESP->height), 0); - } break; - case 4: { // BELOW - draw_point = Vector(min_x, max_y, 0); - } - } - } - } - - // if user setting allows vis check and ent isnt visable, make transparent - if (vischeck && !ent->IsVisible()) transparent = true; - - // Loop through strings - for (int j = 0; j < ent_data.string_count; j++) { - - // Pull string from the entity's cached string array - const ESPString& string = ent_data.strings[j]; - - // If string has a color assined to it, apply that otherwise use entities color - rgba_t color = string.color ? string.color : ent_data.color; - if (transparent) color = colors::Transparent(color); // Apply transparency if needed - - // If the origin is centered, we use one method. if not, the other - if (!origin_is_zero) { - FTGL_Draw(string.data, draw_point.x, draw_point.y, fonts::ftgl_ESP, color); - } else { - int size_x; - FTGL_StringLength(string.data, fonts::ftgl_ESP, &size_x); - FTGL_Draw(string.data, draw_point.x - size_x / 2, draw_point.y, fonts::ftgl_ESP, color); - } - - // Add to the y due to their being text in that spot - draw_point.y += (int)fonts::ftgl_ESP->height - 1; - } +// Function to reset entitys strings +void ResetEntityStrings() { + for (auto& i : data) { + i.string_count = 0; + i.color = colors::empty; + i.needs_paint = false; } - - // TODO Add Rotation matix - // TODO Currently crashes, needs null check somewhere - // Draw Hitboxes - /*if (draw_hitbox && ent->m_Type == ENTITY_PLAYER) { - - // Loop through hitboxes - for (int i = 0; i <= 17; i++) { // I should probs get how many hitboxes instead of using a fixed number... - - // Get a hitbox from the entity - hitbox_cache::CachedHitbox* hb = ent->hitboxes.GetHitbox(i); - - // Create more points from min + max - Vector box_points[8]; - Vector vec_tmp; - for (int ii = 0; ii <= 8; ii++) { // 8 points to the box - - // logic le paste from sdk - vec_tmp[0] = ( ii & 0x1 ) ? hb->max[0] : hb->min[0]; - vec_tmp[1] = ( ii & 0x2 ) ? hb->max[1] : hb->min[1]; - vec_tmp[2] = ( ii & 0x4 ) ? hb->max[2] : hb->min[2]; - - // save to points array - box_points[ii] = vec_tmp; - } - - // Draw box from points - // Draws a point to every other point. Ineffient, use now fix later... - Vector scn1, scn2; // to screen - for (int ii = 0; ii < 8; ii++) { - - // Get first point - if (!draw::WorldToScreen(box_points[ii], scn1)) continue; - - for (int iii = 0; iii < 8; iii++) { - - // Get second point - if (!draw::WorldToScreen(box_points[iii], scn2)) continue; - - // Draw between points - drawgl::Line(scn1.x, scn1.y, scn2.x - scn1.x, scn2.y - scn1.y, fg); - } - } - } - }*/ +} + +// Sets an entitys esp color +void SetEntityColor(CachedEntity* entity, const rgba_t& color) { + data[entity->m_IDX].color = color; } }}} diff --git a/src/hacks/ESP.h b/src/hacks/ESP.h index f00b63d0..73397f3e 100644 --- a/src/hacks/ESP.h +++ b/src/hacks/ESP.h @@ -22,45 +22,14 @@ class CachedEntity; namespace hacks { namespace shared { namespace esp { -extern CatVar local_esp; -extern CatVar buildings; -extern CatVar enabled; -extern CatVar entity_info; -extern CatVar show_bot_id; -extern CatVar teammates; -extern CatVar item_esp; -extern CatVar item_dropped_weapons; -extern CatVar item_ammo_packs; -extern CatVar item_health_packs; -extern CatVar item_powerups; -extern CatVar item_money; -extern CatVar item_money_red; -extern CatVar entity_id; -extern CatVar tank; -extern CatVar box_esp; -extern CatVar show_distance; -extern CatVar show_name; -extern CatVar show_class; -extern CatVar show_conditions; -extern CatVar vischeck; -extern CatVar legit; -extern CatVar show_health; -extern CatVar proj_rockets; -extern CatVar proj_arrows; -extern CatVar proj_pipes; -extern CatVar proj_stickies; -extern CatVar proj_enemy; -extern CatVar proj_esp; -extern CatVar entity_model; -extern CatVar item_weapon_spawners; -extern CatVar item_adrenaline; - +// Strings class ESPString { public: std::string data { "" }; rgba_t color { colors::empty }; }; +// Cached data class ESPData { public: int string_count { 0 }; @@ -72,18 +41,26 @@ public: Vector collide_min { 0, 0, 0 }; }; +// extern std::array data; -void ResetEntityStrings(); -void AddEntityString(CachedEntity* entity, const std::string& string, const rgba_t& color = colors::empty); -void SetEntityColor(CachedEntity* entity, const rgba_t& color); - + void CreateMove(); void Draw(); - -void __attribute__((fastcall)) DrawBox(CachedEntity* ent, const rgba_t& clr, bool healthbar, int health, int healthmax); + +// Entity Processing void __attribute__((fastcall)) ProcessEntity(CachedEntity* ent); void __attribute__((fastcall)) ProcessEntityPT(CachedEntity* ent); +// helper funcs +void __attribute__((fastcall)) DrawBox(CachedEntity* ent, const rgba_t& clr); +void BoxCorners(int minx, int miny, int maxx, int maxy, const rgba_t& color, bool transparent); +bool GetCollide(CachedEntity* ent); + +// Strings +void AddEntityString(CachedEntity* entity, const std::string& string, const rgba_t& color = colors::empty); +void SetEntityColor(CachedEntity* entity, const rgba_t& color); +void ResetEntityStrings(); + }}} #endif /* HESP_H_ */ From 352133f99fbac2a76e16d35c145fcc6403a4767c Mon Sep 17 00:00:00 2001 From: julianacat Date: Thu, 17 Aug 2017 20:05:55 -0500 Subject: [PATCH 4/5] Fix css interfaces --- simple-ipc | 2 +- src/interfaces.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/simple-ipc b/simple-ipc index 94b3e53b..e532876f 160000 --- a/simple-ipc +++ b/simple-ipc @@ -1 +1 @@ -Subproject commit 94b3e53b00ac5be465ebe44ea5fe1b1fbc18aa8f +Subproject commit e532876ffd707a48389d54ff904dcc40a84f2839 diff --git a/src/interfaces.cpp b/src/interfaces.cpp index e1cbd62b..8c0272fc 100644 --- a/src/interfaces.cpp +++ b/src/interfaces.cpp @@ -150,7 +150,10 @@ void CreateInterfaces() { g_ppScreenSpaceRegistrationHead = *(CScreenSpaceEffectRegistration***)(gSignatures.GetClientSignature("E8 ? ? ? ? 8B 10 C7 44 24 04 ? ? ? ? 89 04 24 FF 52 28 85 C0 75 4B 8B 35 ? ? ? ? 85 F6 74 31 90 8B 5E 04 85 DB 74 22 8B 03 89 1C 24") + 27); } logging::Info("Finding HUD"); - { + IF_GAME (IsCSS()) { + logging::Info("FATAL: Signatures not defined for CSS - HUD"); + g_CHUD = nullptr; + } else { uintptr_t hud_sig = gSignatures.GetClientSignature("FF 50 08 D9 9D 24 FE FF FF 89 3C 24 E8 ? ? ? ? C7 44 24 04 ? ? ? ? C7 04 24 ? ? ? ? D9 9D 20 FE FF FF E8 ? ? ? ? 85 C0 74 3B 66 0F 6E C3 C7 44 24 10 00 00 00 00 F3 0F 5C 85 20 FE FF FF") + 28; g_CHUD = *reinterpret_cast(hud_sig); logging::Info("HUD 0x%08x 0x%08x", hud_sig, g_CHUD); From 37176eb3191d6251628cfb59876c8eb325ceda3b Mon Sep 17 00:00:00 2001 From: julianacat Date: Thu, 17 Aug 2017 23:45:03 -0500 Subject: [PATCH 5/5] Sightlines --- data/menu.json | 1 + src/hacks/ESP.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/data/menu.json b/data/menu.json index 2eae323a..ed4dc1d9 100644 --- a/data/menu.json +++ b/data/menu.json @@ -178,6 +178,7 @@ "esp_weapon_spawners", "esp_followbot_id", "esp_local", + "esp_sightlines", "esp_entity", "esp_model_name", "esp_entity_id", diff --git a/src/hacks/ESP.cpp b/src/hacks/ESP.cpp index 4a27c2bb..b0edb5f7 100644 --- a/src/hacks/ESP.cpp +++ b/src/hacks/ESP.cpp @@ -31,6 +31,8 @@ CatVar emoji_min_size(CV_INT, "esp_emoji_min_size", "20", "Emoji ESP min size", CatEnum show_health_enum({ "None", "Text", "Healthbar", "Both" }); CatVar show_health(show_health_enum, "esp_health", "3", "Health ESP", "Show enemy health"); CatVar draw_bones(CV_SWITCH, "esp_bones", "0", "Draw Bones"); +CatEnum sightlines_enum({ "None", "Sniper Only", "All" }); // I ripped of lbox's choices cuz its nice +CatVar sightlines(sightlines_enum, "esp_sightlines", "0", "Show sightlines", "Displays a line of where players are looking"); CatEnum esp_text_position_enum({"TOP RIGHT", "BOTTOM RIGHT", "CENTER", "ABOVE", "BELOW" }); CatVar esp_text_position(esp_text_position_enum, "esp_text_position", "0", "Text position", "Defines text position"); CatVar esp_expand(CV_INT, "esp_expand", "0", "Expand Esp", "Spreads out Box, health bar, and text from center"); // Note, check if this should be int, it is being used by casting as float @@ -301,6 +303,37 @@ void _FASTCALL ProcessEntityPT(CachedEntity* ent) { drawgl::Line(scn.x, scn.y, width - scn.x, height - scn.y, fg); } + // Sightline esp + if (sightlines && ent->m_Type == ENTITY_PLAYER) { + + // Logic for using the enum to sort out snipers + if ((int)sightlines == 2 || ((int)sightlines == 1 && CE_INT(ent, netvar.iClass) == tf_sniper)) { + + // Get players angle and head position + Vector& eye_angles = NET_VECTOR(RAW_ENT(ent), netvar.m_angEyeAngles); + Vector eye_position; + GetHitbox(ent, 0, eye_position); + + // Main ray tracing area + float sy = sinf(DEG2RAD(eye_angles.y)); // yaw + float cy = cosf(DEG2RAD(eye_angles.y)); + float sp = sinf(DEG2RAD(eye_angles.x)); // pitch + float cp = cosf(DEG2RAD(eye_angles.x)); + Vector forward = Vector(cp * cy, cp * sy, -sp); + // We dont want the sightlines endpoint to go behind us because the world to screen check will fail, but keep it at most 4096 + forward = forward * min(ent->m_flDistance - 1, 4096) + eye_position; + Ray_t ray; + ray.Init(eye_position, forward); + trace_t trace; + g_ITrace->TraceRay(ray, MASK_SHOT_HULL, &trace::filter_no_player, &trace); + + Vector scn1, scn2; + if (draw::WorldToScreen(eye_position, scn1) && draw::WorldToScreen(trace.endpos, scn2)) { + drawgl::Line(scn1.x, scn1.y, scn2.x - scn1.x, scn2.y - scn1.y, fg); + } + } + } + // Emoji esp if (emoji_esp) { if (ent->m_Type == ENTITY_PLAYER) {