Вопрос Help with autowall

Начинающий
Статус
Оффлайн
Регистрация
3 Ноя 2021
Сообщения
9
Реакции[?]
2
Поинты[?]
0
Hello! Can anyone tell me why fraction = 1.f always? I think ClipTraceToPlayers is broken but I can't understand why...

C++:
#include "Autowall.h"
#include "..\..\Utils\Utils.h"
#include "..\..\SDK\IVEngineClient.h"
#include "..\..\SDK\PlayerInfo.h"
#include "..\..\SDK\ISurfaceData.h"
#include "..\..\SDK\Hitboxes.h"
#include "..\..\SDK\bspflags.h"
#include "..\..\SDK\ICvar.h"
#include "..\..\Utils\Math.h"
#include "..\..\SDK\ClientClass.h"
#include <algorithm>

// esoterik ftw

bool Autowall::breakable_entity(C_BaseEntity* pEnt)
{
    if (!pEnt || !pEnt->EntIndex())
        return false;

    static auto is_breakable = Utils::FindSignature("client.dll", "55 8B EC 51 56 8B F1 85 F6 74 68");

    auto take_damage = *(uintptr_t*)((uintptr_t)is_breakable + 0x26);
    auto backup = *(uint8_t*)((uintptr_t)pEnt + take_damage);

    auto client_class = pEnt->GetClientClass();
    auto network_name = client_class->pNetworkName;

    if (!strcmp(network_name, "CBreakableSurface"))
        *(uint8_t*)((uintptr_t)pEnt + take_damage) = 2;
    else if (!strcmp(network_name, "CBaseDoor") || !strcmp(network_name, "CDynamicProp"))
        *(uint8_t*)((uintptr_t)pEnt + take_damage) = 0;

    using Fn = bool(__thiscall*)(C_BaseEntity*);
    autoresult = ((Fn)is_breakable)(pEnt);

    *(uint8_t*)((uintptr_t)pEnt + take_damage) = backup;
    return result;
}


float Autowall::GetDamage(const Vector& vecPoint, FireBulletData* pDataOut)
{
    const Vector vecPosition = g::pLocal->GetEyePosition();

    // setup data
    FireBulletData data = { };
    data.vecPosition = vecPosition;
    data.vecDirection = (vecPoint - vecPosition).Normalized();

    C_BaseCombatWeapon* pWeapon = g::pLocal->GetActiveWeapon();

    if (pWeapon == nullptr || !SimulateFireBullet(pWeapon, data))
        return -1.0f;

    if (pDataOut != nullptr)
        *pDataOut = data;

    return data.flCurrentDamage;
}

bool IsArmored(int hitgroup, C_BaseEntity* player)
{
    if (player->ArmorValue() > 0)
    {
        switch (hitgroup)
        {
        case HITGROUP_GENERIC:
        case HITGROUP_CHEST:
        case HITGROUP_STOMACH:
        case HITGROUP_LEFTARM:
        case HITGROUP_RIGHTARM:
        case HITGROUP_NECK:
            return true;
            break;
        case HITGROUP_HEAD:
            if (player->HasHelmet())
                return true;
            [[fallthrough]];
        case HITGROUP_LEFTLEG:
        case HITGROUP_RIGHTLEG:
            if (player->GetHeavyArmor())
                return true;
            break;
        default:
            break;
        }
    }

    return false;
}

void Autowall::ScaleDamage(const int iHitGroup, C_BaseEntity* pEntity, const float flWeaponArmorRatio, const float flWeaponHeadShotMultiplier, float& flDamage)
{
    // @ida traceattack: server.dll @ 55 8B EC 83 E4 F8 81 EC C0 00 00 00 56 8B 75 08 57 8B F9 C6 44 24 13 01

    const bool bHeavyArmor = pEntity->GetHeavyArmor();

    static ConVar* mp_damage_scale_ct_head = g_pCvar->FindVar("mp_damage_scale_ct_head");
    static ConVar* mp_damage_scale_t_head = g_pCvar->FindVar("mp_damage_scale_t_head");

    static ConVar* mp_damage_scale_ct_body = g_pCvar->FindVar("mp_damage_scale_ct_body");
    static ConVar* mp_damage_scale_t_body = g_pCvar->FindVar("mp_damage_scale_t_body");

    float flHeadDamageScale = pEntity->GetTeam() == 3 ? mp_damage_scale_ct_head->GetFloat() : pEntity->GetTeam() == 2 ? mp_damage_scale_t_head->GetFloat() : 1.0f;
    const float flBodyDamageScale = pEntity->GetTeam() == 3 ? mp_damage_scale_ct_body->GetFloat() : pEntity->GetTeam() == 2 ? mp_damage_scale_t_body->GetFloat() : 1.0f;

    if (bHeavyArmor)
        flHeadDamageScale *= 0.5f;

    switch(iHitGroup)
    {
    case HITGROUP_HEAD:
        flDamage *= flWeaponHeadShotMultiplier * flHeadDamageScale;
        break;
    case HITGROUP_CHEST:
    case HITGROUP_LEFTARM:
    case HITGROUP_RIGHTARM:
    case HITGROUP_NECK:
        flDamage *= flBodyDamageScale;
        break;
    case HITGROUP_STOMACH:
        flDamage *= 1.25f * flBodyDamageScale;
        break;
    case HITGROUP_LEFTLEG:
    case HITGROUP_RIGHTLEG:
        flDamage *= 0.75f * flBodyDamageScale;
        break;
    default:
        break;
    }

    if (IsArmored(iHitGroup, pEntity))
    {
        // @ida ontakedamage: server.dll @ 80 BF ? ? ? ? ? F3 0F 10 5C 24 ? F3 0F 10 35

        const int iArmor = pEntity->ArmorValue();
        float flHeavyArmorBonus = 1.0f, flArmorBonus = 0.5f, flArmorRatio = flWeaponArmorRatio * 0.5f;

        if (bHeavyArmor)
        {
            flHeavyArmorBonus = 0.25f;
            flArmorBonus = 0.33f;
            flArmorRatio *= 0.20f;
        }

        float flDamageToHealth = flDamage * flArmorRatio;
        if (const float flDamageToArmor = (flDamage - flDamageToHealth) * (flHeavyArmorBonus * flArmorBonus); flDamageToArmor > static_cast<float>(iArmor))
            flDamageToHealth = flDamage - static_cast<float>(iArmor) / flArmorBonus;

        flDamage = flDamageToHealth;
    }
}

// @credits: https://github.com/perilouswithadollarsign/cstrike15_src/blob/master/game/shared/util_shared.cpp#L757
void Autowall::ClipTraceToPlayers(const Vector& vecAbsStart, const Vector& vecAbsEnd, const unsigned int fMask, ITraceFilter* pFilter, C_Trace* pTrace)
{
    // @ida util_cliptracetoplayers: client.dll @ E8 ? ? ? ? 0F 28 84 24 68 02 00 00

    float frac = pTrace->flFraction;
    C_Trace trace = { };
    C_Ray ray(vecAbsStart, vecAbsEnd);

    for (int i = 1; i < g_pGlobalVars->maxClients; i++)
    {
        C_BaseEntity* pEntity = g_pEntityList->GetClientEntity(i);

        if (pEntity == nullptr || !pEntity->IsAlive() || pEntity->IsDormant())
            continue;

        if (pFilter != nullptr && !pFilter->ShouldHitEntity(pEntity, fMask))
            continue;

        // get bounding box
        const Vector vecMin = pEntity->GetCollideable()->OBBMins();
        const Vector vecMax = pEntity->GetCollideable()->OBBMaxs();

        // calculate world space center
        const Vector vecCenter = (vecMax + vecMin) * 0.5f;
        const Vector vecPosition = vecCenter + pEntity->GetOrigin();

        const Vector vecTo = vecPosition - vecAbsStart;
        Vector vecDirection = vecAbsEnd - vecAbsStart;
        const float flLength = vecDirection.NormalizeInPlace2();

        const float flRangeAlong = vecDirection.Dot(vecTo);
        float flRange = 0.0f;

        // calculate distance to ray
        if (flRangeAlong < 0.0f)
            // off start point
            flRange = -vecTo.Length();
        else if (flRangeAlong > vecDirection.Length())
            // off end point
            flRange = -(vecPosition - vecAbsEnd).Length();
        else
            // within ray bounds
            flRange = (vecPosition - (vecDirection * flRangeAlong + vecAbsStart)).Length();

        if (flRange <= 60.f) {

            g_pTrace->ClipRayToEntity(ray, fMask | contents_hitbox, pEntity, &trace);

            //Utils::Log("Sending fraction = " + std::to_string(trace->flFraction));

            if (trace.flFraction < frac) {
                *p trace = trace; // we shortened the ray - save off the trace
                frac = trace.flFraction;
            }
        }
    }         
}

bool Autowall::TraceToExit(C_Trace& enterTrace, C_Trace& exitTrace, const Vector& vecPosition, const Vector& vecDirection)
{
    // @ida tracetoexit: client.dll @ 55 8B EC 83 EC 4C F3
    // server.dll @ 55 8B EC 83 EC 4C F3 0F 10 75

    float flDistance = 0.0f;
    int iStartContents = 0;

    while (flDistance <= 90.0f)
    {
        // add extra distance to our ray
        flDistance += 4.0f;

        // multiply the direction vector to the distance so we go outwards, add our position to it
        Vector vecStart = vecPosition + vecDirection * flDistance;

        if (!iStartContents)
            iStartContents = g_pTrace->GetPointContents(vecStart, mask_shot_hull | contents_hitbox, nullptr);

        const int iCurrentContents = g_pTrace->GetPointContents(vecStart, mask_shot_hull | contents_hitbox, nullptr);

        if (!(iCurrentContents & mask_shot_hull) || (iCurrentContents & contents_hitbox && iCurrentContents != iStartContents))
        {
            // setup our end position by deducting the direction by the extra added distance
            const Vector vecEnd = vecStart - (vecDirection * 4.0f);

            // trace ray to world
            C_Ray rayWorld(vecStart, vecEnd);
            g_pTrace->TraceRay(rayWorld, mask_shot_hull | contents_hitbox, nullptr, &exitTrace);

            if (static ConVar* sv_clip_penetration_traces_to_players = g_pCvar->FindVar("sv_clip_penetration_traces_to_players"); sv_clip_penetration_traces_to_players != nullptr && sv_clip_penetration_traces_to_players->GetBool())
            {
                C_TraceFilter filter(g::pLocal);
                ClipTraceToPlayers(vecEnd, vecStart, mask_shot_hull | contents_hitbox, &filter, &exitTrace);
            }

            // check if a hitbox is in-front of our enemy and if they are behind of a solid wall
            if (exitTrace.startSolid && exitTrace.surface.flags & surf_hitbox)
            {
                // trace ray to entity
                C_Ray ray(vecStart, vecPosition);
                C_TraceFilter filter(exitTrace.m_pEnt);

                g_pTrace->TraceRay(ray, mask_shot_hull, &filter, &exitTrace);

                if (exitTrace.DidHit() && !exitTrace.startSolid)
                {
                    vecStart = exitTrace.end;
                    return true;
                }

                continue;
            }

            if (exitTrace.DidHit() && !exitTrace.startSolid)
            {
                if (Autowall::breakable_entity(enterTrace.m_pEnt) && Autowall::breakable_entity(exitTrace.m_pEnt))
                    return true;

                if (enterTrace.surface.flags & surf_nodraw || (!(exitTrace.surface.flags & surf_nodraw) && exitTrace.plane.normal.Dot(vecDirection) <= 1.0f))
                {
                    const float flMultiplier = exitTrace.flFraction * 4.0f;
                    vecStart -= vecDirection * flMultiplier;
                    return true;
                }

                continue;
            }

            if (!exitTrace.DidHit() || exitTrace.startSolid)
            {
                if (enterTrace.m_pEnt != nullptr && enterTrace.m_pEnt->EntIndex() != 0 && Autowall::breakable_entity(enterTrace.m_pEnt))
                {
                    // did hit breakable non world entity
                    exitTrace = enterTrace;
                    exitTrace.end = vecStart + vecDirection;
                    return true;
                }

                continue;
            }
        }
    }

    return false;
}

void TraceLine(Vector& vecAbsStart, Vector& vecAbsEnd, unsigned int mask, C_BaseEntity* ignore, C_Trace* ptr)
{
    C_TraceFilter filter(ignore);
    g_pTrace->TraceRay(C_Ray(vecAbsStart, vecAbsEnd), mask, &filter, ptr);
}

bool Autowall::HandleBulletPenetration(const WeaponInfo_t* pWeaponData, surfacedata_t* pEnterSurfaceData, FireBulletData& data)
{
    // @ida handlebulletpenetration: client.dll @ E8 ? ? ? ? 83 C4 40 84 C0

    static ConVar* ff_damage_reduction_bullets = g_pCvar->FindVar("ff_damage_reduction_bullets");
    static ConVar* ff_damage_bullet_penetration = g_pCvar->FindVar("ff_damage_bullet_penetration");

    const float flReductionDamage = ff_damage_reduction_bullets->GetFloat();
    const float flPenetrateDamage = ff_damage_bullet_penetration->GetFloat();

    const std::uint16_t hEnterMaterial = pEnterSurfaceData->game.material;

    if (data.iPenetrateCount == 0 && hEnterMaterial != CHAR_TEX_GRATE && hEnterMaterial != CHAR_TEX_GLASS && !(data.enterTrace.surface.flags & surf_nodraw))
        return false;

    if (pWeaponData->penetration <= 0.0f || data.iPenetrateCount <= 0)
        return false;

    C_Trace exitTrace = { };
    if (!TraceToExit(data.enterTrace, exitTrace, data.enterTrace.end, data.vecDirection) && !(g_pTrace->GetPointContents(data.enterTrace.end, mask_shot_hull, nullptr) & mask_shot_hull))
        return false;

    const surfacedata_t* pExitSurfaceData = g_pSurfaceData->GetSurfaceData(exitTrace.surface.surfaceProps);
    const std::uint16_t hExitMaterial = pExitSurfaceData->game.material;

    const float flEnterPenetrationModifier = pEnterSurfaceData->game.flPenetrationModifier;
    const float flExitPenetrationModifier = pExitSurfaceData->game.flPenetrationModifier;

    float flDamageLostModifier = 0.16f;
    float flPenetrationModifier = 0.0f;

    if (hEnterMaterial == CHAR_TEX_GRATE || hEnterMaterial == CHAR_TEX_GLASS)
    {
        flDamageLostModifier = 0.05f;
        flPenetrationModifier = 3.0f;
    }
    else if (((data.enterTrace.contents >> 3) & contents_solid) || ((data.enterTrace.surface.flags >> 7) & surf_light))
    {
        flDamageLostModifier = 0.16f;
        flPenetrationModifier = 1.0f;
    }
    else if (hEnterMaterial == CHAR_TEX_FLESH && flReductionDamage == 0.0f && data.enterTrace.m_pEnt != nullptr && data.enterTrace.m_pEnt->IsPlayer() && (g::pLocal->GetTeam() == data.enterTrace. m_pEnt->GetTeam()))
    {
        if (flPenetrateDamage == 0.0f)
            return false;

        // shoot through teammates
        flDamageLostModifier = flPenetrateDamage;
        flPenetrationModifier = flPenetrateDamage;
    }
    else
    {
        flDamageLostModifier = 0.16f;
        flPenetrationModifier = (flEnterPenetrationModifier + flExitPenetrationModifier) * 0.5f;
    }

    if (hEnterMaterial == hExitMaterial)
    {
        if (hExitMaterial == CHAR_TEX_CARDBOARD || hExitMaterial == CHAR_TEX_WOOD)
            flPenetrationModifier = 3.0f;
        else if (hExitMaterial == CHAR_TEX_PLASTIC)
            flPenetrationModifier = 2.0f;
    }

    const float flTraceDistance = (exitTrace.end - data.enterTrace.end).LengthSqr();

    // penetration modifier
    const float flModifier = (flPenetrationModifier > 0.0f ? 1.0f / flPenetrationModifier : 0.0f);

    // this calculates how much damage we've lost depending on thickness of the wall, our penetration, damage, and the modifiers set earlier
    const float flLostDamage = (data.flCurrentDamage * flDamageLostModifier + (pWeaponData->penetration > 0.0f ? 3.75f / pWeaponData->penetration : 0.0f) * (flModifier * 3.0f)) + ((flModifier * flTraceDistance) / 24.0f) ;

    // did we loose too much damage?
    if (flLostDamage > data.flCurrentDamage)
        return false;

    // we can't use any of the damage that we've lost
    if (flLostDamage > 0.0f)
        data.flCurrentDamage -= flLostDamage;

    // do we still have enough damage to deal?
    if (data.flCurrentDamage < 1.0f)
        return false;

    data.vecPosition = exitTrace.end;
    --data.iPenetrateCount;
    return true;
}

bool Autowall::SimulateFireBullet(C_BaseCombatWeapon* pWeapon, FireBulletData& data)
{
    // @ida firebullet: client.dll @ 55 8B EC 83 E4 F0 81 EC ? ? ? ? F3 0F 7E

    WeaponInfo_t* pWeaponData = pWeapon->GetCSWpnData();

    if (pWeaponData == nullptr)
        return false;

    float flMaxRange = pWeaponData->range;

    // the total number of any surfaces bullet can penetrate in a single flight is capped at 4
    data.iPenetrateCount = 4;
    // set our current damage to what our gun's initial damage reports it will do
    data.flCurrentDamage = static_cast<float>(pWeaponData->damage);

    float flTraceLength = 0.0f;
    C_TraceFilter filter(g::pLocal);

    while ((data.iPenetrateCount > 0) && (data.flCurrentDamage >= 1.0f))
    {
        // max bullet range
        flMaxRange -= flTraceLength;

        // end position of bullet
        Vector vecEnd = data.vecPosition + data.vecDirection * flMaxRange;

        TraceLine(data.vecPosition, vecEnd, mask_shot_hull | contents_hitbox, g::pLocal, &data.enterTrace);

        // check for player hitboxes extending outside their collision bounds
        ClipTraceToPlayers(data.vecPosition, vecEnd + data.vecDirection * 40.0f, mask_shot_hull | contents_hitbox, &filter, &data.enterTrace);

        surfacedata_t* pEnterSurfaceData = g_pSurfaceData->GetSurfaceData(data.enterTrace.surface.surfaceProps);
        const float flEnterPenetrationModifier = pEnterSurfaceData->game.flPenetrationModifier;

        Utils::Log("fraction = " + std::to_string(data.enterTrace.flFraction));
        // we didn't hit anything, stop tracing shoot
        if (data.enterTrace.flFraction == 1.0f)
            break;

        // calculate the damage based on the distance the bullet traveled
        flTraceLength += data.enterTrace.flFraction * flMaxRange;
        data.flCurrentDamage *= std::powf(pWeaponData->range_modifier, flTraceLength / 500.f);

        // check is actually can shoot through
        if (flTraceLength > 3000.f || flEnterPenetrationModifier < 0.1f)
            break;                     
        Utils::Log("Got passed 2nd breakpoint");

        // check is can do damage
        if (data.enterTrace.hitGroup != HITGROUP_GENERIC && data.enterTrace.hitGroup != HITGROUP_GEAR && g::pLocal->IsEnemy(data.enterTrace.m_pEnt))
        {
            // we got target - scale damage
            ScaleDamage(data.enterTrace.hitGroup, data.enterTrace.m_pEnt, pWeaponData->armor_ratio, pWeaponData->flHeadShotMultiplier, data.flCurrentDamage);
            Utils::Log("Simulate returned true");
            return true;
        }

        // calling handlebulletpenetration here reduces our penetration ñounter, and if it returns true, we can't shoot through it
        if (!HandleBulletPenetration(pWeaponData, pEnterSurfaceData, data)) {
            Utils::Log("HandleBulletPen returned false");
            break;
        }
        Utils::Log("HandleBulletPen returned true ");
    }

    Utils::Log("Simulate returned false");
    return false;
}

bool VectortoVectorVisible(Vector src, Vector point)
{
    C_Trace Trace;
    TraceLine(src, point, mask_solid, g::pLocal, &Trace);

    if (Trace.flFraction == 1.0f)
    {
        return true;
    }

    return false;
}

bool Autowall::CanHitFloatingPoint(const Vector& point, const Vector& source) // source = eyepos
{

    if (!g::pLocal)
        return false;

    FireBulletData data = {};
    data.vecPosition = source;

    Vector angles = g_Math.CalcAngle(data.vecPosition, point);
    g_Math.AngleVectors(angles, &data.vecDirection);
    VectorNormalize(data.vecDirection);

    C_BaseCombatWeapon* pWeapon = (C_BaseCombatWeapon*)g::pLocal->GetActiveWeapon();

    if (!pWeapon)
        return false;

    data.iPenetrateCount = 1;
    data.iTraceLength = 0.0f;

    WeaponInfo_t* weaponData = pWeapon->GetCSWpnData();

    if (!weaponData)
        return false;

    data.flCurrentDamage = (float)weaponData->damage;

    data.iTraceLengthRemaining = weaponData->range - data.iTraceLength;

    Vector end = data.vecPosition + data.vecDirection * data.iTraceLengthRemaining;

    TraceLine(data.vecPosition, end, mask_shot | contents_hitbox, g::pLocal, &data.enterTrace);

    surfacedata_t* pEnterSurfaceData = g_pSurfaceData->GetSurfaceData(data.enterTrace.surface.surfaceProps);

    if (VectortoVectorVisible(data.vecPosition, point))
    {
        return true;
    }
    if (HandleBulletPenetration(weaponData, pEnterSurfaceData, data))
    {
        return true;
    }

    return false;
}
 
Сверху Снизу