Question Universal CalcAngle Trigonometry Math

Hexui Undetected CSGO Cheats Sinkicheat PUBG Cheat

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,372
78,998
2,414
Game Name
CSGO and assaultcube for this example
Anticheat
N/A
Tutorial Link
N/A
How long you been coding/hacking?
5 Years
Coding Language
C++
In my experience I have used 5-6 different CalcAngle functions, every time you start a new game it's annoying to figure it out.

I'm working on creating a "universal" CalcAngle mechanism, or a CalcAngle generator. It would generate the correct CalcAngle function and the correct Normalize function for your game.

Basically you input the address of your view angles, it will bruteforce the min and max values and then generate the correct CalcAngle based on the min and max values.

To start this process I am working with CSGO and AssaultCube.

This is the current data and the correct CalcAngle functions for each game:

CSGO
pitch = x [0] = -89.0 to 89.0 up is -89.0, down is +89.0 total of 180
yaw = y [1] = -179.99 to 179.9 increases as your rotate left, total of 360
C++:
vec3 CalcAngle(vec3 src, vec3 dst)
{
    vec3 angles;

    vec3 delta = dst - src;
    float hyp = delta.Length();

    angles.v[PITCH] =    -RadToDeg(asinf(delta.v[ROLL] / hyp));
    angles.v[YAW]    =     RadToDeg(atan2f(delta.v[YAW], delta.v[PITCH]));

    angles.v[ROLL] = 0.0f;
    return angles;
}
AssaultCube
pitch = y [1] = -90 to +90 down is -90, total of 180
yaw = x [0] = 0 to 360 increases as you rotate right, total of 360

C++:
vec CalcAngle(vec src, vec dst)
{
    vec angles;

    vec delta = Subtract(src, dst);
    float hyp = delta.Length();

    //AC
    angles.v[PITCH] =  RadToDeg(asinf(delta.v[ROLL] / hyp));
    angles.v[YAW]    = -RadToDeg(atan2f(delta.v[YAW], delta.v[PITCH])) + 180.0f;

    angles.v[ROLL]    =  0.0f;
    return angles;
}
Obvious difference:
pitch and yaw and swapped positions in the vec3

What's interesting is the range for pitch in both games includes negative and positive numbers, but one game requires you to change the sign of the resulting pitch value which I thought was really wierd. Any ideas here?

Similarly the Yaw, you have to change the sign of one but not the other, they both have a total range of 360 degress, but one includes a range of negative and positive numbers and the other includes only positive numbers.

So I have to figure out how to figure out when to negate the result based on the ranges (the min & max values for each angle)

Lastly, when you get the difference between your current angle and the aimbot angle to do a comparison, for the purpose of finding the closest enemy to your crosshair you need to normalize the results. I have already come up with a function which works on both games:

C++:
vec3 NormalizeDiff(vec3 src, vec3 dst, float xmin, float xmax, float ymin, float ymax)
{
    vec3 diff = dst - src;

    if (diff.x > xmax)
        diff.x -= 360;

    if (diff.x < xmin)
        diff.x += 360;

    if (diff.y > ymax)
        diff.y -= 360;

    if (diff.y < ymin)
        diff.y += 360;

    return diff;
}
I am curious if you guys have any tips or advice
 

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,372
78,998
2,414
Additionally if you would like to contribute, if you have made an aimbot for another game and can supply your calc angle function and this information:
pitch = y [1] = -90 to +90 down is -90, total of 180
yaw = x [0] = 0 to 360 increases as you rotate right, total of 360

I can use this data to come up with a universal solution
 

Traxin

Escobar Tier VIP
Dank Tier Donator
Aug 3, 2015
1,041
25,378
154
Instead of generating and racking your brains on brute-forcing this or that, you make something that's 1. configurable and 2. simply picks prefabbed components to "build" the correct aimbot algo. Min-max values can be placed on a slider and you can have several options to toggle whether results should be in deg/radians or if something needs to be negated or whatever. Requires some, virtually none really, effort from the end user but "generating" seems like a lot of work that can be done but fiddling with a slider and a few check boxes.

I was actually thinking of building just this back in the day but never got around to it.
 

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,372
78,998
2,414
This code works on CSGO and Assault Cube
You just need to change the first 7 lines to match your game

C++:
#define PITCH 0 //x
#define YAW 1  //y
#define ROLL 2 //z
const float PITCH_MAX_DOWN    =    90;
const float PITCH_MAX_UP    =  -90;
const float YAW_MAX_LEFT    =    180;
const float YAW_MAX_RIGHT    =  -180;

class vec3
{
public:

    union
    {
        struct { float x, y, z; };
        float v[3];
    };

    vec3() { x = y = z = 0; }
    vec3(const float x, const float y, const float z) : x(x), y(y), z(z) {}
    vec3 operator + (const vec3& rhs) const { return vec3(x + rhs.x, y + rhs.y, z + rhs.z); }
    vec3 operator - (const vec3& rhs) const { return vec3(x - rhs.x, y - rhs.y, z - rhs.z); }
    vec3 operator * (const float& rhs) const { return vec3(x * rhs, y * rhs, z * rhs); }
    vec3 operator / (const float& rhs) const { return vec3(x / rhs, y / rhs, z / rhs); }
    vec3& operator += (const vec3& rhs) { return *this = *this + rhs; }
    vec3& operator -= (const vec3& rhs) { return *this = *this - rhs; }
    vec3& operator *= (const float& rhs) { return *this = *this * rhs; }
    vec3& operator /= (const float& rhs) { return *this = *this / rhs; }
    float dot() const { return x * x + y * y + z * z; }
    float Length() const { return sqrtf(dot()); }
    vec3 Normalize() const { return *this * (1 / Length()); }
    float Distance(const vec3& rhs) const { return (*this - rhs).Length(); }
};

float RadToDeg(float radian)
{
    return radian * (180 / pi);
}

float DegToRad(float degree)
{
    return degree * (pi / 180);
}

vec3 RadToDeg(vec3& radians)
{
    vec3 degrees;
    degrees.x = radians.x * (180 / pi);
    degrees.y = radians.y * (180 / pi);
    degrees.z = radians.z * (180 / pi);
    return degrees;
}

vec3 DegToRad(vec3& degrees)
{
    vec3 radians;
    radians.x = degrees.x * (pi / 180);
    radians.y = degrees.y * (pi / 180);
    radians.z = degrees.z * (pi / 180);
    return radians;
}

vec3 CalcAngle(vec3 src, vec3 dst)
{
    vec3 angles;

    vec3 delta = dst - src;
    float hyp = delta.Length();

    angles.v[PITCH] = RadToDeg(asinf(delta.v[ROLL] / hyp));
    angles.v[YAW]    = RadToDeg(atan2f(delta.v[YAW], delta.v[PITCH]));

    if (PITCH_MAX_UP < 0)
    {
        angles.v[PITCH] = -angles.v[PITCH];
    }

    if (YAW_MAX_RIGHT > 0)
    {
        angles.v[YAW] = -angles.v[YAW];
    }

    if (YAW_MAX_RIGHT > 0)
    {
        angles.v[YAW] = angles.v[YAW] + 180.0f;
    }

    angles.v[ROLL] = 0.0f;

    return angles;
}
Please try in your games and post your results

who can help test on other games? this is gonna be OG GH Bad Ass shit when we're done with it

if you have an aimbot for a game, just swap out the calcangle for this one, change the first 7 lines and report back
 
Last edited:
  • Like
Reactions: Just_another_kyle

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,372
78,998
2,414
anyone have a up to date aimbot for a game that isn't for source engine or cube engine that we can test this on?

I'm trying it for COD4 now
 

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,372
78,998
2,414
I was working on this for quite some time but I have put this on pause for now.

It works fine in 3 different games but not on COD4, so I'm still trying to figure that out
 
  • Like
Reactions: R41NY and Lukor

h4nsbr1x

Dank Tier Donator
Full Member
Jul 24, 2020
32
2,583
1
That sounds pretty cool. AFAIK you can only really model view direction with pitch/yaw or a vector (and you'd be silly to not use a unit vector), and then there's a question of whether they use degrees vs radians.

I've always been of the opinion that it's important to do everything by hand a couple times until you know how it works, and after that there's no need to reinvent the wheel. There's a bunch of stuff in that domain that'd be interesting - automatic view angle finder (heck why not use OCR and use automatic health/ammo finder too). I think we could do some smarter pointerscan work too, if you find the line where a var is accessed why not take the stacktrace and step back through all the dereferences automatically? It's kind of related to writing a vm lifter, but should be substantially easier.

Anyway, sounds like a cool project, and ties in with some of the work I've got on at the moment anyway.
 

h4nsbr1x

Dank Tier Donator
Full Member
Jul 24, 2020
32
2,583
1
It's a bit cobbled together but works for Assault Cube

C++:
#include <stdio.h>
#include <math.h>
#include <cmath>
#include <windows.h>
#include <tlhelp32.h>
#include <vector>
#include <vector>
#include "MemoryAllocation.h"
#include "FloatScanResult.h"

DWORD GetProcessId(const char* appName) {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    DWORD processId = 0;

    if (hSnapshot != INVALID_HANDLE_VALUE) {
        PROCESSENTRY32 processEntry;
        processEntry.dwSize = sizeof(processEntry);

        if (Process32First(hSnapshot, &processEntry)) {
            do {
                if (!_stricmp(processEntry.szExeFile, appName)) {
                    processId = processEntry.th32ProcessID;
                    break;
                }
            } while (Process32Next(hSnapshot, &processEntry));
        }
    }

    CloseHandle(hSnapshot);
    return processId;
}

char appName[] = "ac_client.exe";

int main(int argc, char** argv) {
    printf("Loaded console\n");

    // find window
    printf("Looking for process %s\n", appName);
    DWORD processId = GetProcessId(appName);

    if (processId > 0) {
        printf("Process ID: %d\n", processId);
    }
    else {
        printf("Couldn't find process ID, exiting\n");
        return -1;
    }

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, processId);

    if (hProcess && hProcess != INVALID_HANDLE_VALUE) {
        printf("Successfully opened process\n");

        uintptr_t base=0;
        MEMORY_BASIC_INFORMATION mbi;
        std::vector<MemoryAllocation> memoryAllocations;

        printf("Scanning for memory regions...\n");

        while (true) {
            if (VirtualQueryEx(hProcess, (void*)base, &mbi, sizeof(mbi))) {
                base += mbi.RegionSize;
                if (mbi.State == MEM_COMMIT) {
                    memoryAllocations.push_back(MemoryAllocation((uintptr_t)mbi.BaseAddress, mbi.RegionSize));
                }
            }
            else {
                printf("Error requesting info on base address 0x%X\n", mbi.BaseAddress);
                break;
            }
        }

        printf("Switch to the game\n");

        Sleep(5000);

        // move mouse up
        int screenWidth = GetSystemMetrics(SM_CXFULLSCREEN);
        int screenHeight = GetSystemMetrics(SM_CYFULLSCREEN);
        INPUT input;
        for (int i = 0; i < 10; i++) {
            input.type = INPUT_MOUSE;
            input.mi.dwFlags = MOUSEEVENTF_MOVE;
            input.mi.dx = 0;
            input.mi.dy = -screenHeight;
            input.mi.time = GetTickCount();
            printf("Moving mouse to %d %d\n", input.mi.dx, input.mi.dy);
            SendInput(1, &input, sizeof(input));
            Sleep(30);
        }

        std::vector<FloatScanResult> results;

        for (std::vector<MemoryAllocation>::iterator memoryAllocation = memoryAllocations.begin(); memoryAllocation != memoryAllocations.end(); ++memoryAllocation) {
            printf("Allocation at %X size %X\n", memoryAllocation->base, memoryAllocation->size);

            // scan it

            for (uintptr_t pageBase = memoryAllocation->base; pageBase < memoryAllocation->base + memoryAllocation->size; pageBase += 0x1000) {
                unsigned char buffer[0x1000];

                ReadProcessMemory(hProcess, (void*) pageBase, buffer, sizeof(buffer), 0);

                // dword search
                float* floatBuffer = (float*)buffer;
                for (size_t i = 0; i < 0x1000 / sizeof(float); i++) {
                    if (88.0f < floatBuffer[i] && floatBuffer[i] < 91.0f) {
                        uintptr_t address = pageBase + (i * sizeof(float));
                        printf("Found float at %X: %0.2f\n", address, floatBuffer[i]);
                        results.push_back(FloatScanResult(address, floatBuffer[i], NULL));
                    }
                }
            }
        }

        // move mouse down
        for (int i = 0; i < 10; i++) {
            input.type = INPUT_MOUSE;
            input.mi.dwFlags = MOUSEEVENTF_MOVE;
            input.mi.dx = 0;
            input.mi.dy = screenHeight;
            input.mi.time = GetTickCount();
            printf("Moving mouse to %d %d\n", input.mi.dx, input.mi.dy);
            SendInput(1, &input, sizeof(input));
            Sleep(30);
        }

        std::vector<FloatScanResult> candidates;

        // recheck results
        for (std::vector<FloatScanResult>::iterator result = results.begin(); result != results.end(); ++result) {
            float newValue;

            ReadProcessMemory(hProcess, (void*)result->address, &newValue, sizeof(newValue), 0);

            printf("Value at %X was %0.2f, now is %0.2f\n", result->address, result->value, newValue);
            if (-91.0f < newValue && newValue < -88.0f) {
                printf("Possible view angle address: %X\n", result->address);
                candidates.push_back(FloatScanResult(result->address, newValue, result->value));
            }
        }
        for (std::vector<FloatScanResult>::iterator candidate = candidates.begin(); candidate != candidates.end(); ++candidate) {
            printf("Potential view angle address at %X, was %0.2f, now is %0.2f\n", candidate->address, candidate->previous, candidate->value);
        }
    }

    return 0;
}
What I'm thinking is the following:
  • Pitch is probably the easiest (should always be -90 to 90 or 90 to -90 or pi to -pi or -pi to pi, plus/minus clipping), so we can get candidates from that first
  • This is going to be stored in memory as (pitch,roll,yaw) or (yaw,roll,pitch) or similar, so we only need to check the 2 floats/doubles either side
  • We can do smaller mouse moves to confirm pitch and also to identify which value is yaw
More to come
 
  • Love
  • Like
Reactions: Rake and Kleon742
Attention! Before you post:

Read the How to Ask Questions Guide
99% of questions are answered in the Beginner's Guide, do it before asking a question.

No Hack Requests. Post in the correct section.  Search the forum first. Read the rules.

How to make a good post:

  • Fill out the form correctly
  • Tell us the game name & coding language
  • Post everything we need to know to help you
  • Ask specific questions, be descriptive
  • Post errors, line numbers & screenshots
  • Post code snippets using code tags
  • If it's a large project, zip it up and attach it

If you do not comply, your post may be deleted.  We want to help, please make a good post and we will do our best to help you.

Community Mods