Skip to content

Commit

Permalink
version 0.4.9
Browse files Browse the repository at this point in the history
  • Loading branch information
SunOner committed Mar 5, 2024
1 parent c529503 commit 90a363b
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 62 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ The behavior of the aim bot can be configured via the [`config.ini`](https://git
- hotkey_exit `str`: Exit.
- hotkey_pause `str`: Pause AIM.
- hotkey_reload_config `str`: Reload config.
- hotkey_turn_off_mask `str`: Turn off exclude mask.

### Mouse:
- mouse_dpi `int`: Mouse DPI.
Expand Down Expand Up @@ -110,6 +111,7 @@ The behavior of the aim bot can be configured via the [`config.ini`](https://git
- show_overlay_detector `bool`: Show the detector overlay.
- show_overlay_boxes `bool`: Show goals inside the overlay.
- show_overlay_line `bool`: Show line from crosshair to target.
- show_overlay_mask `bool`: Show exclude mask.

### Debug window:
- show_window `bool`: Shows the OpenCV2 window for visual feedback.
Expand All @@ -123,6 +125,10 @@ The behavior of the aim bot can be configured via the [`config.ini`](https://git
- debug_window_scale_percent `int`: Adjusts the size of the debug window.
- debug_window_name `str`: Specifies the title of the debug window.

### Exclude mask:
- mask_enabled `bool`: Enable exclude mask.
- mask_points `str`: Saved points exclude mask. If you are playing from a third person, the character can be masked with a mask that will exclude him from targeting targets. Turn on the debugging window and select 4 points, the mask will be automatically saved in the config.

## AI Models
- *.pt: Default AI model.
- *.onnx: The model is optimized to run on processors.
Expand Down
6 changes: 6 additions & 0 deletions config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ hotkey_targeting = RightMouseButton
hotkey_exit = F2
hotkey_pause = F3
hotkey_reload_config = F4
hotkey_turn_off_mask = RightMouseButton

[Mouse]
mouse_dpi = 1000
Expand Down Expand Up @@ -53,6 +54,7 @@ AI_mouse_net = False
show_overlay_detector = False
show_overlay_boxes = True
show_overlay_line = True
show_overlay_mask = True

[Debug window]
show_window = False
Expand All @@ -65,3 +67,7 @@ show_target_line = True
debug_window_always_on_top = True
debug_window_scale_percent = 100
debug_window_name = Calculator

[Exclude Mask]
mask_enabled = False
mask_points = (0, 0),(220, 106),(220, 420),(0, 420)
91 changes: 59 additions & 32 deletions logic/config_watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,53 +17,56 @@ def Read(self, verbose=False):
self.bettercam_capture_fps = int(self.config_Bettercam_Capture['bettercam_capture_fps'])
self.bettercam_monitor_id = int(self.config_Bettercam_Capture['bettercam_monitor_id'])
self.bettercam_gpu_id = int(self.config_Bettercam_Capture['bettercam_gpu_id'])

self.config_Obs_capture = self.config['Capture Methods']
self.Obs_capture = self.config_Obs_capture.getboolean('Obs_capture')
self.Obs_camera_id = str(self.config_Obs_capture['Obs_camera_id'])
self.Obs_capture_fps = int(self.config_Obs_capture['Obs_capture_fps'])
# Aim
self.config_Aim_settings = self.config['Aim']
self.body_y_offset = float(self.config_Aim_settings['body_y_offset'])
self.hideout_targets = self.config_Aim_settings.getboolean('hideout_targets')
self.disable_headshot = self.config_Aim_settings.getboolean('disable_headshot')
self.config_Aim = self.config['Aim']
self.body_y_offset = float(self.config_Aim['body_y_offset'])
self.hideout_targets = self.config_Aim.getboolean('hideout_targets')
self.disable_headshot = self.config_Aim.getboolean('disable_headshot')
# Hotkeys
self.config_Hotkeys_settings = self.config['Hotkeys']
self.hotkey_targeting = str(self.config_Hotkeys_settings['hotkey_targeting'])
self.hotkey_targeting_list = self.hotkey_targeting.split(',')
self.hotkey_exit = str(self.config_Hotkeys_settings['hotkey_exit'])
self.hotkey_pause = str(self.config_Hotkeys_settings['hotkey_pause'])
self.hotkey_reload_config = str(self.config_Hotkeys_settings['hotkey_reload_config'])
self.hotkey_turn_off_mask = str(self.config_Hotkeys_settings['hotkey_turn_off_mask'])
# Mouse
self.config_Mouse_settings = self.config['Mouse']
self.mouse_dpi = int(self.config_Mouse_settings['mouse_dpi'])
self.mouse_sensitivity = float(self.config_Mouse_settings['mouse_sensitivity'])
self.mouse_fov_width = int(self.config_Mouse_settings['mouse_fov_width'])
self.mouse_fov_height = int(self.config_Mouse_settings['mouse_fov_height'])
self.mouse_lock_target = self.config_Mouse_settings.getboolean('mouse_lock_target')
self.mouse_auto_shoot = self.config_Mouse_settings.getboolean('mouse_auto_shoot')
self.mouse_auto_aim = self.config_Mouse_settings.getboolean('mouse_auto_aim')
self.mouse_ghub = self.config_Mouse_settings.getboolean('mouse_ghub')
self.mouse_triggerbot = self.config_Mouse_settings.getboolean('mouse_triggerbot')
self.mouse_force_click = self.config_Mouse_settings.getboolean('mouse_force_click')
self.config_Mouse = self.config['Mouse']
self.mouse_dpi = int(self.config_Mouse['mouse_dpi'])
self.mouse_sensitivity = float(self.config_Mouse['mouse_sensitivity'])
self.mouse_fov_width = int(self.config_Mouse['mouse_fov_width'])
self.mouse_fov_height = int(self.config_Mouse['mouse_fov_height'])
self.mouse_lock_target = self.config_Mouse.getboolean('mouse_lock_target')
self.mouse_auto_shoot = self.config_Mouse.getboolean('mouse_auto_shoot')
self.mouse_auto_aim = self.config_Mouse.getboolean('mouse_auto_aim')
self.mouse_ghub = self.config_Mouse.getboolean('mouse_ghub')
self.mouse_triggerbot = self.config_Mouse.getboolean('mouse_triggerbot')
self.mouse_force_click = self.config_Mouse.getboolean('mouse_force_click')
# Arduino
self.config_Arduino_settings = self.config['Arduino']
self.arduino_move = self.config_Arduino_settings.getboolean('arduino_move')
self.arduino_shoot = self.config_Arduino_settings.getboolean('arduino_shoot')
self.arduino_port = str(self.config_Arduino_settings['arduino_port'])
self.arduino_baudrate = int(self.config_Arduino_settings['arduino_baudrate'])
self.config_Arduino = self.config['Arduino']
self.arduino_move = self.config_Arduino.getboolean('arduino_move')
self.arduino_shoot = self.config_Arduino.getboolean('arduino_shoot')
self.arduino_port = str(self.config_Arduino['arduino_port'])
self.arduino_baudrate = int(self.config_Arduino['arduino_baudrate'])
# AI
self.config_AI_options = self.config['AI']
self.AI_model_name = str(self.config_AI_options['AI_model_name'])
self.AI_image_size = int(self.config_AI_options['AI_image_size'])
self.AI_conf = float(self.config_AI_options['AI_conf'])
self.AI_device = str(self.config_AI_options['AI_device'])
self.AI_enable_AMD = self.config_AI_options.getboolean('AI_enable_AMD')
self.AI_mouse_net = self.config_AI_options.getboolean('AI_mouse_net')
self.config_AI = self.config['AI']
self.AI_model_name = str(self.config_AI['AI_model_name'])
self.AI_image_size = int(self.config_AI['AI_image_size'])
self.AI_conf = float(self.config_AI['AI_conf'])
self.AI_device = str(self.config_AI['AI_device'])
self.AI_enable_AMD = self.config_AI.getboolean('AI_enable_AMD')
self.AI_mouse_net = self.config_AI.getboolean('AI_mouse_net')
# Overlay
self.config_Overlay_detector = self.config['Overlay']
self.show_overlay_detector = self.config_Overlay_detector.getboolean('show_overlay_detector')
self.show_overlay_boxes = self.config_Overlay_detector.getboolean('show_overlay_boxes')
self.show_overlay_line = self.config_Overlay_detector.getboolean('show_overlay_line')
self.config_Overlay = self.config['Overlay']
self.show_overlay_detector = self.config_Overlay.getboolean('show_overlay_detector')
self.show_overlay_boxes = self.config_Overlay.getboolean('show_overlay_boxes')
self.show_overlay_line = self.config_Overlay.getboolean('show_overlay_line')
self.show_overlay_mask = self.config_Overlay.getboolean('show_overlay_mask')
# Debug window
self.config_Debug_window = self.config['Debug window']
self.show_window = self.config_Debug_window.getboolean('show_window')
Expand All @@ -76,6 +79,30 @@ def Read(self, verbose=False):
self.debug_window_always_on_top = self.config_Debug_window.getboolean('debug_window_always_on_top')
self.debug_window_scale_percent = int(self.config_Debug_window['debug_window_scale_percent'])
self.debug_window_name = str(self.config_Debug_window['debug_window_name'])

# Exclude Detection Mask
self.config_Exclude_Mask = self.config['Exclude Mask']
self.mask_enabled = self.config_Exclude_Mask.getboolean('mask_enabled')
self.mask_points = str(self.config_Exclude_Mask['mask_points']).split(',')

if verbose:
print('Config reloaded')

def save_mask_points(self, mask_points):
self.config.set('Exclude Mask', 'mask_points', ','.join(map(str, mask_points)))
with open('./config.ini', 'w') as configfile:
self.config.write(configfile)

def read_mask_points(self):
mask_points_str = self.config.get('Exclude Mask', 'mask_points', fallback='')
mask_points = []
try:
points = mask_points_str.replace(' ', '').split('),(')
points[0] = points[0].lstrip('(')
points[-1] = points[-1].rstrip(')')
for point_str in points:
point = tuple(map(int, point_str.split(',')))
mask_points.append(point)
return mask_points
except Exception as e:
print(f'Invalid mask points format in config. Should be (x1, y1),(x2, y2),...\n{e}')
return []
8 changes: 3 additions & 5 deletions logic/mouse.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import math
import queue
import threading
import time
import torch
import win32con, win32api
from ctypes import *
Expand Down Expand Up @@ -90,9 +88,9 @@ def mouse_close(self):
class Mouse_net(nn.Module):
def __init__(self, arch):
super(Mouse_net, self).__init__()
self.fc1 = nn.Linear(in_features=10, out_features=64, device=f'{arch}')
self.fc2 = nn.Linear(in_features=64, out_features=64, device=f'{arch}')
self.fc3 = nn.Linear(in_features=64, out_features=2, device=f'{arch}')
self.fc1 = nn.Linear(in_features=10, out_features=64, device=arch)
self.fc2 = nn.Linear(in_features=64, out_features=64, device=arch)
self.fc3 = nn.Linear(in_features=64, out_features=2, device=arch)

def forward(self, x):
x = torch.relu(self.fc1(x))
Expand Down
96 changes: 73 additions & 23 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from logic.mouse import MouseThread

from ultralytics import YOLO
import numpy as np
import math
import torch
import cv2
Expand All @@ -13,6 +14,10 @@
import win32api, win32con, win32gui
if cfg.show_overlay_detector:
import tkinter as tk

mask_points = []
annotated_frame = None
global_mask = None

class Target:
def __init__(self, x, y, w, h, cls):
Expand Down Expand Up @@ -76,42 +81,63 @@ def print_startup_messages():
f'[{cfg.hotkey_targeting}] - Aiming at the target\n',
f'[{cfg.hotkey_exit}] - EXIT\n',
f'[{cfg.hotkey_pause}] - PAUSE AIM\n',
f'[{cfg.hotkey_reload_config}] - Reload config\n')
f'[{cfg.hotkey_reload_config}] - Reload config\n',
f'[{cfg.hotkey_turn_off_mask}] - Disable exclude mask\n')

def process_hotkeys(cfg_reload_prev_state):
global app_pause
global clss
global mask_active
app_pause = win32api.GetKeyState(Buttons.KEY_CODES[cfg.hotkey_pause])
app_reload_cfg = win32api.GetKeyState(Buttons.KEY_CODES[cfg.hotkey_reload_config])
mask_active = win32api.GetAsyncKeyState(Buttons.KEY_CODES[cfg.hotkey_turn_off_mask])
mask_points = cfg.read_mask_points()
if app_reload_cfg != cfg_reload_prev_state:
if app_reload_cfg in (1, 0):
cfg.Read(verbose=True)
frames.reload_capture()
mouse_worker.Update_settings()
clss = active_classes()

if cfg.show_window == False:
cv2.destroyAllWindows()

cfg_reload_prev_state = app_reload_cfg
return cfg_reload_prev_state
return cfg_reload_prev_state, mask_points

def update_overlay_window(overlay):
if cfg.show_overlay_detector:
overlay.overlay_detector.update()
overlay.canvas.delete("all")


def create_mask_from_points(image_shape, points):
mask = np.zeros([image_shape[1], image_shape[0]], dtype=np.uint8)
pts = np.array([points], dtype=np.int32)
cv2.fillPoly(mask, pts, 255)
return mask

def debug_window_click_handler(event, x, y, flags, param):
global mask_points
global global_mask
if event == cv2.EVENT_LBUTTONDOWN:
mask_points.append((x, y))
if len(mask_points) == 4:
global_mask = create_mask_from_points(param, mask_points)
cfg.save_mask_points(mask_points)
print('mask created:', mask_points)
mask_points = []

def spawn_debug_window():
if cfg.show_window:
cv2.namedWindow(cfg.debug_window_name)
cv2.setMouseCallback(cfg.debug_window_name, debug_window_click_handler, [cfg.detection_window_width, cfg.detection_window_height])
if cfg.debug_window_always_on_top:
debug_window_hwnd = win32gui.FindWindow(None, cfg.debug_window_name)
win32gui.SetWindowPos(debug_window_hwnd, win32con.HWND_TOPMOST, 100, 100, 200, 200, 0)

def sort_targets(frame, cfg, arch) -> List[Target]:
boxes_array = frame.boxes.xywh.to(f'{arch}')
distances_sq = torch.sum((boxes_array[:, :2] - torch.tensor([frames.screen_x_center, frames.screen_y_center], device=f'{arch}')) ** 2, dim=1)
classes_tensor = frame.boxes.cls.to(f'{arch}')
def sort_targets(frame, cfg, arch, mask) -> List[Target]:
boxes_array = frame.boxes.xywh.to(arch)
distances_sq = torch.sum((boxes_array[:, :2] - torch.tensor([frames.screen_x_center, frames.screen_y_center], device=arch)) ** 2, dim=1)
classes_tensor = frame.boxes.cls.to(arch)

if not cfg.disable_headshot:
score = distances_sq + 10000 * (classes_tensor != 7).float()
Expand All @@ -125,15 +151,23 @@ def sort_targets(frame, cfg, arch) -> List[Target]:
sort_heads = torch.argsort(heads_distances_sq)
heads = heads[sort_heads]
else:
sort_heads = torch.tensor([], dtype=torch.int64, device=f'{arch}')
sort_heads = torch.tensor([], dtype=torch.int64, device=arch)

other_distances_sq = distances_sq[other]
sort_indices_other = torch.argsort(other_distances_sq)

sort_indices = torch.cat((heads, other[sort_indices_other])).cpu().numpy()

return [Target(*boxes_array[i, :4].cpu().numpy(), classes_tensor[i].item()) for i in sort_indices]


if mask is not None and cfg.mask_enabled and mask_active != -32768:
targets = []
for i in sort_indices:
target = Target(*boxes_array[i, :4].cpu().numpy(), classes_tensor[i].item())
if mask[int(target.y), int(target.x)] == 0:
targets.append(target)
return targets
else:
return [Target(*boxes_array[i, :4].cpu().numpy(), classes_tensor[i].item()) for i in sort_indices]

def active_classes() -> List[int]:
clss = [0, 1]

Expand All @@ -146,26 +180,34 @@ def active_classes() -> List[int]:
return clss

def init():
arch = f'cuda:{cfg.AI_device}'
global annotated_frame
prev_frame_time, new_frame_time = 0, 0 if cfg.show_window and cfg.show_fps else None
cfg_reload_prev_state = 0
shooting_queue = []
spawn_debug_window()

if cfg.AI_enable_AMD:
arch = f'hip:{cfg.AI_device}'
else:
arch = f'cuda:{cfg.AI_device}'
if 'cpu' in cfg.AI_device:
arch = 'cpu'

prev_frame_time, new_frame_time = 0, 0 if cfg.show_window and cfg.show_fps else None
try:
model = YOLO(f'models/{cfg.AI_model_name}', task='detect')
print_startup_messages()
except Exception as e:
print(e)
print('Loading model error:\n', e)
quit(0)

spawn_debug_window()
cfg_reload_prev_state = 0
shooting_queue = []

global global_mask
if cfg.mask_enabled:
mask_points = cfg.read_mask_points()
if mask_points:
global_mask = create_mask_from_points([cfg.detection_window_width, cfg.detection_window_height], mask_points)

while True:
cfg_reload_prev_state = process_hotkeys(cfg_reload_prev_state)
cfg_reload_prev_state, mask_points = process_hotkeys(cfg_reload_prev_state)
image = frames.get_new_frame()
result = perform_detection(model, image, clss)
update_overlay_window(overlay) if cfg.show_overlay_detector else None
Expand All @@ -177,16 +219,22 @@ def init():
if cfg.show_window and cfg.show_speed == True:
annotated_frame = speed(annotated_frame, frame.speed['preprocess'], frame.speed['inference'], frame.speed['postprocess'])

if cfg.show_overlay_mask and cfg.show_overlay_detector and cfg.mask_enabled:
for i in range(len(mask_points)):
current_point = mask_points[i]
next_point = mask_points[(i + 1) % len(mask_points)]
overlay.canvas.create_line(current_point[0], current_point[1], next_point[0], next_point[1], width=2, fill='red')

if len(frame.boxes):
if app_pause == 0:
shooting_queue = sort_targets(frame, cfg, arch)
shooting_queue = sort_targets(frame, cfg, arch, global_mask)

if shooting_queue:
target = shooting_queue[0]
shooting_queue.clear()

mouse_worker.queue.put((target.x, target.y, target.w, target.h))

if cfg.show_window or cfg.show_overlay_detector:
screen_x_center = cfg.detection_window_width / 2
screen_y_center = cfg.detection_window_height / 2
Expand All @@ -209,7 +257,6 @@ def init():

if cfg.show_overlay_line:
overlay.canvas.create_line(screen_x_center, screen_y_center, target.x, target.y + cfg.body_y_offset / target.h, width=2, fill='red')

else: pass

if cfg.show_window and cfg.show_boxes:
Expand All @@ -225,6 +272,9 @@ def init():
cv2.putText(annotated_frame, f'FPS: {str(int(fps))}', (10, 80) if cfg.show_speed else (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 1, cv2.LINE_AA)

if cfg.show_window:
if cfg.mask_enabled:
mask_color = cv2.cvtColor(global_mask, cv2.COLOR_GRAY2BGR)
annotated_frame[global_mask > 0] = cv2.addWeighted(annotated_frame[global_mask > 0], 0.5, mask_color[global_mask > 0], 0.5, 0)
try:
if cfg.debug_window_scale_percent != 100:
height = int(cfg.detection_window_height * cfg.debug_window_scale_percent / 100)
Expand Down
Loading

0 comments on commit 90a363b

Please sign in to comment.