MyScienceBlog

Selfmade-Website


Wie funktioniert ein Aimbot

Luke
15.05.2023

Disclaimer: Der gezeigte Aimbot dient nur der Erklärung und Bildungszwecken. Ich rate ausdrücklich davon ab, ihn in einem Spiel gegen andere Spieler einzusetzen. Bei Verwendung muss man mit einem Ausschluss aus dem Spiel rechnen (permanenter Ban).

In diesem Artikel zeige ich euch, wie ein Aimbot in einem Panzerspiel funktionieren könnte. Der Artikel dient der Veranschaulichung, um ein Verständnis für die Mechanik von Aimbots zu bekommen.

Die Formel und Idee für den Aimbot gab mir folgender Artikel in der Steam-Community: Perfect accuracy with CALCULATIONS

(Der folgende Code ist in Python geschrieben und alles kann nacheinander in ein Script kopiert werden)

Für den Bot brauchen wir die folgenden Bibliotheken:
from PIL import ImageGrab import cv2 import numpy as np import win32gui import time import math
PIL und win32gui brauchen wir, um das Spielfeld zu bekommen. Dies geschieht durch einen einfachen Screenshot. Numpy und Math brauchen wir zur Berechnung. Time ist für einen kleinen Delay zuständig, da sonst Screenshot Probleme auftreten können.

Als erstes müssen wir das Spielfeld unserem Bot zeigen. Hierfür schreiben wir die Funktion get_window():
def get_window(): hwnd = win32gui.FindWindow(None, GAMENAME) #select Game win32gui.SetForegroundWindow(hwnd) #push it to foreground time.sleep(0.1) #wait for it to be in foreground rect = (0,50,1920,950) #image has to be in the upper left corner: 1920x1080 image = np.array(ImageGrab.grab(rect)) #gescreenshot return image
Wenn man eine andere Spielauflösung als 1920x1080 benötigt, muss man bei der Formel die Pixelanzahl umrechnen. Weitere Angaben dazu im Steam-Artikel.

Nun müssen wir die gegnerischen Panzer und unseren Panzer mit der Funktion detector(image,color) ausfindig machen:
def detector(image,color): img = image hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) if color == "red": # color range in hsv for red lower = np.array([160, 100, 100]) upper = np.array([180, 255, 255]) elif color == "green": # color range in hsv for green lower = np.array([50, 150, 150]) upper = np.array([70, 255, 255]) mask = cv2.inRange(hsv, lower, upper) #cv2.imshow("mask", mask) #cv2.waitKey(0) points = cv2.findNonZero(mask) #get points of the color res_points = points.reshape(len(points), -1) #reshape sorted_p = res_points[res_points[:, 0].argsort()] #sort by first column value #detect groups of red pixels to find enemies (works for single target too) enemies = [] #array for the groups while True: sorted_p_l = len(sorted_p) #get started length of points for i in range(sorted_p_l): if i < sorted_p_l-1: #for out of range error #proof if point as a meaningfull distance to next one current_point = sorted_p[i] next_point = sorted_p[i+1] difference = next_point[0] - current_point[0] if difference > 50: #proof if the difference is bigger than min distance enemies.append([sorted_p[:i+1]]) #append this range sorted_p = sorted_p[i+1:] #cut appended range of break if sorted_p_l == len(sorted_p): #proof if method found (deleted) something enemies.append([sorted_p]) #append last group cause you cant find a distance cause there is only one left break enemies_pos = [] for enemy in enemies: if len(enemy[0]) < 250: #if they have less than 300 points it isnt an enemy like the red arrow over your tank pass else: #get min and max xs and ys min = np.min(enemy[0], axis=0).flatten() max = np.max(enemy[0], axis=0).flatten() # filter to get middle pixel of tank median_max = int(np.median([min[0], max[0]])) # convert to int to cut .5 of x = median_max y = min[1]+20 #+20 so i get the middle and not the top enemies_pos.append((x,y)) #append return enemies_pos
Dieser langer Codeblock macht Folgendes:
1. Wir suchen uns alle Pixel der ausgewählten Farbe (Grün oder Rot).
2. Nun gruppieren wir die Pixel zu Clustern und machen daran die Panzer ausfindig. Hierbei muss eine gewisse Anzahl an Pixeln erreicht sein.
3. Jetzt flatten wir den Array und suchen uns das Minimum und Maximum. So können wir die Position des Clusters bestimmen und bekommen X- und Y-Werte jedes Gegners zurück.

Nachdem wir dann per Input in der Main-Methode, die wir am Ende begutachten, den Gegner ausgewählt haben, berechnen wir mithilfe der Formeln aus dem Steam-Artikel die Kraft mit der Methode calc_power(x,y,angle). Hierbei sind X und Y relativ:
def calc_power(x,y,angle): g = (-379.106) q = 0.0518718 angle = math.radians(angle) velocity = math.sqrt(((-1*g)*(x**2))/(2*(math.cos(angle)**2)*(math.tan(angle)*x-y))) power = (-2/(g*q)) * velocity return power

Nun vereinen wir die einzelnen Methoden in der Main-Methode run_live():
def run_live(): img = get_window() img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) #cv2 reads in BGR and we want RGB me = detector(img, "green")[0] enemies = detector(img, "red") #draw and save image drawed = cv2.circle(img, me, radius=5, color=(255, 0, 255), thickness=2) for enemy in enemies: drawed = cv2.circle(drawed, enemy, radius=5, color=(0, 255, 255), thickness=2) cv2.imwrite("drawed.png", drawed) print("Enemies detected: ",len(enemies)) enemy = int(input("Enemy: "))-1 #so we start counting by 1 and not zero #get distance of enemy x = me[0] - enemies[enemy][0] y = me[1] - enemies[enemy][1] if x < 0: x = x * -1 #insert angle angle = int(input("angle: ")) print("Power: ",calc_power(x,y,angle))

Hier müssen wir wie erwähnt den Gegner per Zahl auswählen (es wird von links nach rechts gezählt) und den Winkel angeben in dem wir schießen möchten, da z.B. Berge im Weg sein könnten und das Script das nicht erkennt. Auch wird ein Bild namens drawed.png erstellt, auf dem man die Erkennung der Gegner und sich selbst nachvollziehen kann (Gegner: Gelber Kreis, Spieler: Lila Kreis):


Zum Schluss muss man nur noch die Funktion aufrufen:
run_live()

Mögliche Probleme:
In vielen Spielen gibt es noch andere Dinge, die die gleiche bzw. ähnliche Farbe wie die gegnerischen Panzer haben. Da der Bot nur eindimensional scannt, können dadurch Fehler entstehen. Auch wenn Panzer übereinander sind, entstehen Fehler.

Eine weitere Besonderheit ist, dass wenn zwei Panzer sehr nah nebeneinander stehen, werden sie als ein Panzer erkannt. Dies ist nicht weiter schlimm, da wenn man diesen auswählt, in die Mitte der beiden Panzer trifft und optimalen Schaden anrichtet.


Selfmade-Website