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