Aim assist Script with Arduino and Python for Gaming

arduino aim assist

Introduction

In the realm of gaming, precision and accuracy can make all the difference. One way to enhance your gaming experience is through the use of scripts that automate certain actions, such as aim assist mechanisms. In this guide, we’ll delve into a Python script that leverages Arduino and Win32 API to create an aim assist system for a specific weapon in a game.

Want to Skip to the video: click here to see it!

Github Source: https://github.com/slyautomation/aim-assist-with-python

Prerequisites

Before diving into the code, ensure you have the following:

  • Python installed on your system
  • Necessary Python libraries: serial, win32api, time, keyboard, and pyyaml
  • An Arduino leonardo board connected to your system
  • Arduino Mouse library installed (available at https://github.com/ArduinoHannover/arduino-mouse)

Understanding the Code

Let’s break down the key components of the provided Python script:

1. Importing Libraries

import serial
import win32api
import time
import keyboard
import yaml
from arduino_mouse import arduino

This section imports essential libraries for serial communication, mouse control, time manipulation, keyboard input, and YAML file parsing.

2. Setting Default Configuration

enabled = False
toggle_button = 'num lock'

The script initializes variables, such as enabled to determine if anti-recoil is active, and toggle_button as the key to toggle the system on or off.

3. Serial Communication with Arduino

arduino = serial.Serial(port='COM8', baudrate=115200, timeout=.1)

Establishes a serial connection with the Arduino board, assuming it is connected to COM8.

To configure your arduino leonardo refer to this article which uses the same concepts: Setting up and Running Arduino

4. Function for Writing and Reading

def write_read(x):
    arduino.write(bytes(x, 'utf-8'))

Defines a function for writing data to the Arduino and reading the response. This will send the left click event to arduino to mimic a hardware mouse click.

5. Mouse Button State Check

def is_mouse_down():
    lmb_state = win32api.GetKeyState(0x01)
    return lmb_state < 0

Checks whether the left mouse button is pressed.

Let’s delve deeper into the aim_assist function to understand the aim assist logic and its various components.

6. Aim Assist Function

def aim_assist(game, weapon):
    global enabled, toggle_button, horizontal_range, min_vertical, max_vertical, min_firerate, max_firerate, end_exit
    with open(f"{game}_settings.yaml", "r") as yamlfile:
        data = yaml.load(yamlfile, Loader=yaml.FullLoader)
        print("Read successful")
        yamlfile.close()
    w_name = weapon
    weapon = data[game][weapon]
    horizontal_range = weapon['horizontal_range']
    min_vertical = weapon['min_vertical']
    max_vertical = weapon['max_vertical']
    min_firerate = weapon['min_firerate']
    max_firerate = weapon['max_firerate']

    print("Anti-recoil started!!")
    if enabled:
        print("Status: ENABLED")
    else:
        print("Status: DISABLED")

    last_state = False
    while True:
        with open('aim_assist.txt', 'r') as f:
            status = f.readline()
            f.close()

        if status == 'TRUE':
            enabled = False
            exit()

        key_down = keyboard.is_pressed(toggle_button)
        if key_down != last_state:
            last_state = key_down
            if last_state:
                enabled = not enabled
                if enabled:
                    print("Anti-recoil ENABLED")
                    with open('aim_assist.txt', 'w') as f:
                        f.write('ENABLED')
                        f.close()
                else:
                    print("Anti-recoil DISABLED")
                    with open('aim_assist.txt', 'w') as f:
                        f.write('DISABLED')
                        f.close()
        if not is_mouse_down():
            start_time = True
        if is_mouse_down() and enabled:
            if start_time:
                start = time.time()
                start_time = False
                if w_name == 'havoc':
                    time.sleep(0.5)

            offset_const = 1000
            bonus_offset = eval(weapon['bonus_offset'])
            horizontal_offset = eval(weapon['horizontal_offset'])
            vertical_offset = eval(weapon['vertical_offset'])
            write_read(str(int(horizontal_offset)) + ";" + str(int(vertical_offset)))

            time_offset = eval(weapon['time_offset'])
            time.sleep(time_offset)

Explanation:

  • Loading Weapon Settings:
  • The function begins by loading weapon settings from a YAML file based on the specified game and weapon. The yaml.load function is used to parse the YAML data.
  • Initial Setup:
  • Variables like horizontal_range, min_vertical, max_vertical, min_firerate, and max_firerate are assigned values from the loaded weapon settings.
  • Toggle and Status Handling:
  • The function continuously monitors the toggle key defined by toggle_button. If the toggle state changes, it updates the enabled variable accordingly and prints the status.
  • Exit Condition:
  • The function checks a file named ‘aim_assist.txt’ for an exit command. If the content is ‘TRUE’, it disables the aim assist and exits the program.
  • Mouse Button State Check:
  • It checks whether the left mouse button is pressed using the is_mouse_down function.
  • Anti-Recoil Logic:
  • If the left mouse button is pressed and the anti-recoil is enabled, the script enters the aim assist logic.
  • It measures the time between consecutive mouse clicks and applies offsets (horizontal_offset and vertical_offset) to simulate anti-recoil behavior.
  • Delay and Bonus Offset:
  • A small delay (time.sleep(time_offset)) is introduced between consecutive mouse movements based on the weapon settings.
  • For certain weapons (e.g., ‘havoc’), an additional delay of 0.5 seconds is introduced.

This function essentially acts as the core of the aim assist script, handling user input, toggling the system, and applying aim assist logic based on weapon settings. Customizing the YAML file allows users to fine-tune the script for different games and weapons.

Building the GUI for the Sly Aim Assist

Introduction

We’ll now explore the Python script that leverages a graphical user interface (GUI) to control the ant recoil mechanism. This tool, named “Sly Aim Assist,” integrates with the YAML configuration file and utilizes threading for smooth execution.

Aim Assist Prerequisites

Before diving into the code, ensure you have the following:

  • Tkinter library for GUI development
  • YAML library for working with configuration files

Understanding the Code

Let’s break down the essential components of the provided Python script:

1. Importing Libraries

import os
import threading
import tkinter
from tkinter import *
from aim_assist import *
import yaml

This section imports necessary libraries for threading, GUI development using Tkinter, ant recoil functionalities from an external module (aim_assist.py), and YAML file processing.

2. Initializing Variables and Aim Assist GUI

data = 'NOT STARTED'
running_func = False

with open('aim_assist.txt', 'w') as f:
    data = f.write('NOT STARTED')
    f.close()

root = Tk()
root.title('Sly Aim Assist')

Here, the script initializes variables, such as data for status, and running_func to track the execution status. The Tkinter GUI window is created with the title “Sly Aim Assist.”

3. Reading and Displaying Status

with open('aim_assist.txt', 'r') as f:
    data = f.readline()
    f.close()

print(f'aim_assist: {data}')
lbl_status = tkinter.Label(root, text=f'STATUS: {data}', background='#40362C', fg='yellow', font=Font_tuple, width=20, borderwidth=2, relief="groove")

The status is read from the ‘aim_assist.txt’ file and displayed on the GUI. The Label widget is used for this purpose.

4. Threading and Aim Assist Execution

def read_status():
    while True:
        with open('aim_assist.txt', 'r') as f:
            status = f.readline()
            f.close()
        lbl_status.config(text=f'STATUS: {status}')

        if status == 'TRUE':
            break

        if status != 'TRUE':
            with open(f"weapon_settings.yaml", "r") as yamlfile:
                data = yaml.load(yamlfile, Loader=yaml.FullLoader)
                yamlfile.close()
            weapon_list = []
            for d in data[lb_game.get(lb_game.curselection())]:
                weapon_list.append(d)
            var_weapon.set(weapon_list)
    exit()

def clicked():
    global end_exit, running_func
    end_exit = False
    if running_func:
        with open('aim_assist.txt', 'w') as f:
            f.write('TRUE')
            f.close()
        time.sleep(1)
        with open('aim_assist.txt', 'w') as f:
            f.write('NOT STARTED')
            f.close()
        threading.Thread(target=read_status).start()

    with open('aim_assist.txt', 'w') as f:
        f.write('STARTED')
        f.close()
    with open('aim_assist.txt', 'r') as f:
        data = f.readline()
        f.close()
    weapon = lb_weapon.get(lb_weapon.curselection())
    game = lb_game.get(lb_game.curselection())
    lbl_status.config(text=f'STATUS: {data}')
    print('starting aim-assist script...')
    running_func = True
    aim_assist(game, weapon)

def stop():
    global end_exit
    end_exit = True
    with open('aim_assist.txt',  'w') as f:
        f.write('TRUE')
        f.close()
    time.sleep(1)
    print("stopping aim-assist script...")
    root.quit()
    exit()

Explanation:

read_status Function:

  • This function is responsible for continuously monitoring the ‘aim_assist.txt’ file for status updates.
  • It updates the lbl_status label on the GUI with the current status, providing real-time feedback to the user.
  • If the status becomes ‘TRUE’, indicating a request to stop the anti recoil, the function breaks out of the loop and exits.

Weapon_settings.yaml structure

## Configuration
└── Name of Game Title
    └── Weapon Name 1
    └── Weapon Name 2
    └── Weapon Name 3
    └── Weapon Name ...
untitled zombie game:
  glock:
  acc_honey_badger:
  p90:
  • Make sure to use indents for the yaml file to pick up the tree structure properly.
  • Use the full colon at the end.
  • No need for quotations and spaces are allowed (e.g assault rifle).

Creating the weapon settings:

name the file ‘Name of Game Title’_settings

untitled zombie game:
  glock:
    # Set the horizontal limit: 5 means a maximum of 5 pixels to the left or to the right every shot
    horizontal_range: 2
    # Set the minimum and maximum amount of pixels to move the mouse every shot
    min_vertical: 5
    max_vertical: 6
    # Set the minimum and maximum amount of time in seconds to wait until moving the mouse again
    min_firerate: 0.01
    max_firerate: 0.02
    bonus_offset: '0'
    horizontal_offset: '(-horizontal_range * offset_const) / offset_const'
    vertical_offset: 'random.randrange(min_vertical * offset_const, max_vertical * offset_const, 1) / offset_const'
    time_offset: 'random.randrange(min_firerate * offset_const, max_firerate * offset_const, 1) / offset_const'
  acc_honey_badger:
    horizontal_range: 0
    min_vertical: 5
    max_vertical: 6
    min_firerate: 0.02
    max_firerate: 0.03
    bonus_offset: '0'
    horizontal_offset: '0'
    vertical_offset: 'random.randrange(min_vertical * offset_const, max_vertical * offset_const, 1) / offset_const'
    time_offset: 'random.randrange(min_firerate * offset_const, max_firerate * offset_const, 1) / offset_const'
  p90:
    horizontal_range: 1.85
    min_vertical: 3
    max_vertical: 4
    min_firerate: 0.03
    max_firerate: 0.04
    bonus_offset: '0'
    horizontal_offset: '(-horizontal_range * offset_const) / offset_const'
    vertical_offset: 'random.randrange(min_vertical * offset_const, max_vertical * offset_const, 1) / offset_const'
    time_offset: 'random.randrange(min_firerate * offset_const, max_firerate * offset_const, 1) / offset_const'

clicked Function:

  • This function is triggered when the user clicks the “Start” button in the GUI.
  • it uses the weapon settings to get the game and weapon and then gets the values from the game settings to adjust the inputs for the mouse adjustments.
  • It sets the end_exit flag to False to prevent premature exit.
  • If running_func is already True (indicating aim assist is running), it stops the current execution by updating the ‘aim_assist.txt’ file and waits for a brief period.
  • It then starts a new thread to execute the read_status function concurrently, providing real-time status updates.
  • The ‘aim_assist.txt’ file is updated to indicate the start of the aim assist process.
  • The selected game and weapon are retrieved from the GUI, and the aim_assist function is called with these parameters.

stop Function:

  • This function is triggered when the user clicks the “Stop” button in the GUI.
  • It sets the end_exit flag to True to signal the aim assist script to stop.
  • The ‘aim_assist.txt’ file is updated to indicate the request to stop the aim assist.
  • A brief sleep is introduced to allow time for the ant recoil script to gracefully exit.
  • The GUI is then closed, and the program exits.

These functions utilize threading to ensure that GUI interactions remain responsive while concurrently executing the aim assist script in the background. Threading is crucial for preventing the GUI from freezing during time-consuming operations like reading status updates and executing the anti recoil logic. The threading approach enhances the overall user experience and responsiveness of the Sly Aim Assist tool.

5. Aim Assist GUI Components

WIDTH, HEIGHT = 250, 350
Font_tuple = ('Unispace', 8)
root.geometry('{}x{}'.format(WIDTH, HEIGHT))

canvas = tkinter.Canvas(root, width=WIDTH, height=HEIGHT, highlightthickness=0, background='#40362C')
canvas.pack()

lbl_selection = tkinter.Label(root, text="Select Game", background='#40362C', fg='yellow', font=Font_tuple)
lbl_selection_window = canvas.create_window(5, 40, anchor=tkinter.NW, window=lbl_selection)

lbl_status = tkinter.Label(root, text=f'STATUS: {data}', background='#40362C', fg='yellow', font=Font_tuple, width=20, borderwidth=2, relief="groove")
lbl_status_window = canvas.create_window(100, 10, anchor=tkinter.NW, window=lbl_status)

lbl_status.setvar(str(data))

var_list_sel = tkinter.StringVar()
var_game = tkinter.StringVar()
with open(f"weapon_settings.yaml", "r") as yamlfile:
    data = yaml.load(yamlfile, Loader=yaml.FullLoader)
    yamlfile.close()
games_list = []
for d in data:
    games_list.append(d)
var_game.set(games_list)

lb_game = tkinter.Listbox(root, listvariable=var_game, width=30, height=5, background='#40362C', fg='yellow', font=Font_tuple, borderwidth=2, relief="groove", exportselection=False)
lb_game.select_set(0)

lbl_weapon = tkinter.Label(root, text="Select Weapon", background='#40362C', fg='yellow', font=Font_tuple)
lbl_weapon_window = canvas.create_window(5, 160, anchor=tkinter.NW, window=lbl_weapon)

var_list_weapon = tkinter.StringVar()
var_weapon = tkinter.StringVar()
var_weapon.set(('glock','acc_honey_badger','p90'))
lb_weapon = tkinter.Listbox(root, listvariable=var_weapon, width=30, height=5, background='#40362C', fg='yellow', font=Font_tuple, borderwidth=2, relief="groove", exportselection=False)
lb_weapon.select_set(0)

button_s = tkinter.Button(root, text="Stop", command=lambda: threading.Thread(target=stop).start(), background='#40362C', fg='yellow', font=Font_tuple)
button_s_window = canvas.create_window(25, 10, anchor=tkinter.NW, window=button_s)

button_e = tkinter.Button(root, text="Start", command=lambda: threading.Thread(target=clicked).start(), background='#40362C', fg='yellow', font=Font_tuple)
button_e_window = canvas.create_window(25, 315, anchor=tkinter.NW, window=button_e)

game_window = canvas.create_window(10, 65, anchor=tkinter.NW, window=lb_game)
weapon_window = canvas.create_window(10, 185, anchor=tkinter.NW, window=lb_weapon)

Explanation:

  • Setting Up the Canvas:
    • The script initializes the width and height of the GUI window, sets a font tuple, and configures the canvas accordingly.
  • Creating Labels:
    • lbl_selection and lbl_weapon are labels providing instructions to the user for game and weapon selection, respectively.
    • lbl_status is a label displaying the current status of the aim assist, dynamically updated during runtime.
  • Displaying Status:
    • A label (lbl_status) is used to display the current status fetched from the ‘aim_assist.txt’ file.
  • Listboxes for Game and Weapon Selection:
    • lb_game is a listbox displaying the available games for selection.
    • lb_weapon is a listbox displaying the available weapons for the selected game.
  • Buttons for Starting and Stopping:
    • button_e is a button labeled “Start,” triggering the clicked function when clicked. It starts the aim assist process.
      • button_s is a button labeled “Stop,” triggering the stop function when clicked. It stops the aim assist process.
  • Positioning GUI Elements:
    • The canvas.create_window method is used to position the labels, listboxes, and buttons on the canvas.
  • Threading for Button Commands:
    • Threading is applied to the button commands (clicked and stop) to ensure they run concurrently without freezing the GUI.
  • Default Game and Weapon Settings:
    • Default game and weapon settings are loaded to populate the initial values in the listboxes.

Added Functionality Change the Arduino Port by the User

arduino = ''
def connect_to_ard():
    global arduino
    com_port = lbl_connect.get()
    print(com_port)
    arduino = serial.Serial(port=com_port, baudrate=115200, timeout=.1)
  • Connect to Arduino: Added functionality to connect to a PORT by the user instead of a static PORT.
  • Tkinter Elements are added for the COM PORT entry and the button to execute the connect_to_ard function.
lbl_connect = tkinter.Entry(root, width=10, background='#a18a74', fg='yellow', font=Font_tuple)
lbl_connect_window = canvas.create_window(10, 285, anchor=tkinter.NW, window=lbl_connect)

lbl_connect.insert(0, "COM9")

button_a = tkinter.Button(root, text="Connect to Arduino", command=lambda: threading.Thread(target=connect_to_ard).start(), background='#40362C', fg='yellow', font=Font_tuple)
button_a_window = canvas.create_window(100, 281, anchor=tkinter.NW, window=button_a)

This section of the script is responsible for creating an interactive GUI interface, allowing users to select games, weapons, and control the aim assist process. As shown in the image it can be used as a fortnite aim assist but also used as apex aim assist. Labels provide clear instructions, listboxes offer options for selection, and buttons trigger relevant actions. Threading ensures a smooth user experience by preventing the GUI from becoming unresponsive during time-consuming operations.

6. Main Aim Assist GUI Loop

root.after(500, lambda: threading.Thread(target=read_status).start())
root.mainloop()

The after method schedules the read_status function to run every 500 milliseconds, providing real-time status updates on the GUI.

Here’s a video of what it can do, Lauch the script and using the GUI select the game then the weapon and experience some aim assist! This is also compatiable as apex, csgo and fortnite aim assist!

Aim Assist Demonstration Video

Conclusion

This script provides a foundation for an anti recoil system in gaming using Python and Arduino. To customize the script for your game and weapon, modify the YAML configuration file and experiment with the provided parameters. In addition to creating a GUI-based Sly Aim Assist tool. The script allows users to select games and weapons, start and stop the aim assist functionality, and dynamically updates the status on the GUI. This gives the user apex, csgo and fortnite aim assist when the coder has made their adjustments. Experiment with different game and weapon settings to optimize the tool for your gaming preferences.

Where to buy Arduino Leonardo

You can purchase an Arduino Leonardo from various online and offline retailers. Here are some popular options:

Buy the Arduino Leonardo on the Slyautomation Shop! Only $10 USD! 😍 The Arduino Micro Pro also will work as well!

Official Arduino Store: Visit the official Arduino online store for authentic Arduino Leonardo boards. Check their website for availability.

Online Retailers:

Local Electronics Stores: Explore local electronics stores or hobbyist shops specializing in microcontrollers, electronics, or DIY kits. They may carry Arduino boards, including the Leonardo.

One thought on “Aim assist Script with Arduino and Python for Gaming

Leave a Reply

Your email address will not be published. Required fields are marked *