WELCOME TO INFOCHEATS.NET

INFOCHEATS is a community-driven platform focused on free game cheats, cheat development, and verified commercial software for a wide range of popular games. We provide a large collection of free cheats shared by the community. All public releases are checked for malicious code to reduce the risk of viruses, malware, or unwanted software before users interact with them.

Alongside free content, INFOCHEATS hosts an active marketplace with many independent sellers offering commercial cheats. Each product is discussed openly, with user feedback, reviews, and real usage experience available to help you make informed decisions before purchasing.

Whether you are looking for free cheats, exploring paid solutions, comparing sellers, or studying how cheats are developed and tested, INFOCHEATS brings everything together in one place — transparently and community-driven.

Undetected [Source] GunBound — Aimbot v25.0 GUI with Auto-Shoot & Physics Engine (Python)

byte_corvus

Newbie
Newbie

byte_corvus

Newbie
Newbie
Status
Offline
Joined
Mar 3, 2026
Messages
104
Reaction score
7
Had to dump this manually again to keep it clean for the community. I have been messing around with this GunBound aimbot project and finally got a stable build that isn't crashing every five minutes. It is a Python-based external using PyQt5 for the UI and Tesseract for OCR-based screen reading.

Tech Overview:
This is an external approach (Ring 3/RPM) that relies on screen capturing to detect game elements like wind, angle, and power values. It processes the coordinates, calculates the trajectory, and automates inputs via Windows API.

  1. Architecture: Python + PyQt5 interface with a threaded worker for low-latency processing.
  2. Performance: Integrated daemon flag for proper cleanup, state saving on close, and event-based sleep to avoid high CPU usage.
  3. Features: Manual targeting mode, auto-shoot with randomized delay for humanization, and a smoothed detection logic (70/30 weight).
  4. Dependencies: Requires Tesseract-OCR properly mapped in your PATH.

Compile & Setup:
You will need to ensure all the v25_*_ULTRA_FINAL modules are in your local directory. If you are planning to package this for distribution, I recommend using Nuitka over PyInstaller to handle the obfuscation better, as standard scripts get flagged by simple heuristics.

Code:
# Basic dependency check
pip install PyQt5 pyautogui pytesseract

Python:
"""
GunBound Aimbot v25.0 - GUI FINAL
 
 
FIXES IN THIS VERSION:
 
✅ 1. Worker with daemon flag (terminates correctly)
✅ 2. Protection against multiple activations
✅ 3. Sleep with event (more efficient)
✅ 4. State saving on closure
 
COMPLETE FEATURES:
 
✅ COMPLETE worker thread with all fixes
✅ Debounce on all hotkeys (200ms)
✅ Integrated ManualTargetingMode
✅ Integrated overlay WITH ALL fixes
✅ Complete validations
✅ Complete thread-safety
✅ Value fallback
✅ Human variation
✅ Setup wizard
✅ Professional interface
✅ Dark mode
✅ Tray icon
"""
 
import sys
import threading
import time
import random
import pyautogui
from pathlib import Path
from typing import Optional, Dict
from datetime import datetime
import os
import json
 
# PyQt5
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QPushButton, QLabel, QSlider, QComboBox, QCheckBox, QSpinBox,
    QTextEdit, QTabWidget, QTableWidget, QTableWidgetItem, QProgressBar,
    QSystemTrayIcon, QMenu, QDialog, QFileDialog, QMessageBox,
    QSplitter, QGroupBox, QGridLayout, QFrame, QShortcut
)
from PyQt5.QtCore import Qt, QTimer, pyqtSignal, QThread, QSize, QPoint
from PyQt5.QtGui import QIcon, QColor, QFont, QPixmap, QImage, QKeySequence
 
# ✅ Imports atualizados para versões ULTRA FINAL
try:
    from v25_config_ULTRA_FINAL import Config, detect_game_window, auto_calibrate, load_config, save_config
    from v25_capture_ULTRA_FINAL import (
        capture_screen,
        recognize_wind_from_image,
        recognize_angle_from_image,
        recognize_power_from_image,
        detect_enemy_position,
        detect_player_position,
        validate_ocr_result
    )
    from v25_overlay_ULTRA_ULTRA_FINAL import OverlayManager
    from v25_physics_wrapper import PhysicsEngine, calculate_trajectory
    from v25_automation_WIN_API_ULTRA_FINAL import WindowsAPIAutomation
    from v25_utils import setup_logger
except ImportError as e:
    print(f"⚠️ ERRO DE IMPORT: {e}")
    print("Certifique-se que todos os arquivos v25_*_ULTRA_FINAL.py estão presentes!")
    sys.exit(1)
 
# ═══════════════════════════════════════════════════════════════
# ✅ DETECÇÃO DINÂMICA DE TESSERACT (corrigido!)
# ═══════════════════════════════════════════════════════════════
 
def find_tesseract() -> bool:
    """Detecta Tesseract dinamicamente"""
    import pytesseract
    
    possible_paths = [
        r'C:\Program Files\Tesseract-OCR\tesseract.exe',
        r'C:\Arquivos de Programas\Tesseract-OCR\tesseract.exe',
        r'C:\Program Files (x86)\Tesseract-OCR\tesseract.exe',
        r'C:\Users\{}\AppData\Local\Tesseract-OCR\tesseract.exe'.format(
            os.getenv('USERNAME', 'User')
        ),
        '/usr/bin/tesseract',
        '/usr/local/bin/tesseract',
    ]
    
    for path in possible_paths:
        if os.path.exists(path):
            pytesseract.pytesseract.tesseract_cmd = path
            print(f"✅ Tesseract encontrado: {path}")
            return True
    
    try:
        import subprocess
        result = subprocess.run(['tesseract', '--version'], capture_output=True, timeout=2)
        if result.returncode == 0:
            print("✅ Tesseract encontrado no PATH")
            return True
    except:
        pass
    
    return False
 
# ═══════════════════════════════════════════════════════════════
# MANUAL TARGETING MODE
# ═══════════════════════════════════════════════════════════════
 
class ManualTargetingMode:
    """Modo de mira manual (F2)"""
    
    def __init__(self):
        self.manual_target = None
        self.locked = False
    
    def set_target(self, x: int, y: int):
        self.manual_target = (x, y)
        self.locked = True
        print(f"🎯 Alvo manual travado: ({x}, {y})")
    
    def clear_target(self):
        self.manual_target = None
        self.locked = False
        print("🔓 Alvo manual desbloqueado")
    
    def get_target(self):
        return self.manual_target if self.locked else None
 
# ═══════════════════════════════════════════════════════════════
# ✅ WORKER THREAD COM TODAS AS CORREÇÕES
# ═══════════════════════════════════════════════════════════════
 
class AimbotWorker(QThread):
    """✅ Worker COM TODAS AS CORREÇÕES APLICADAS!"""
    
    # Signals
    performance_updated = pyqtSignal(dict)
    detection_updated = pyqtSignal(dict)
    shot_info_updated = pyqtSignal(dict)
    log_message = pyqtSignal(str)
    
    def __init__(self, config: Config, game_window: dict, overlay_manager):
        super().__init__()
        
        # ✅ QThread não precisa de setDaemon - usa quit() e wait()
        
        self.config = config
        self.game_window = game_window
        self.overlay_manager = overlay_manager
        
        # Estado
        self.running = True
        self.enabled = False
        
        # ✅ CORREÇÃO 3: EVENTO PARA CONTROLE EFICIENTE!
        self.resume_event = threading.Event()
        
        # Physics
        self.physics = PhysicsEngine()
        
        # Automation
        self.automation = WindowsAPIAutomation()
        
        # Manual mode
        self.manual_mode = ManualTargetingMode()
        
        # Auto-shoot
        self.auto_shoot_enabled = False
        self.last_shot_time = 0
        
        # Fallback values
        self.last_valid_wind = (0, "none")
        self.last_valid_angle = 45
        self.last_valid_power = 50
        
        # Smoothing
        self.player_positions = []
        self.enemy_positions = []
        
        # Performance
        self.frame_count = 0
        self.loop_times = []
    
    def enable(self):
        """Habilita worker"""
        self.enabled = True
        self.resume_event.set()  # ✅ Acorda thread
        self.log_message.emit("✅ Aimbot ATIVADO")
    
    def disable(self):
        """Desabilita worker"""
        self.enabled = False
        self.resume_event.clear()
        self.log_message.emit("⏸️ Aimbot PAUSADO")
    
    def toggle_auto_shoot(self):
        """Toggle auto-shoot"""
        self.auto_shoot_enabled = not self.auto_shoot_enabled
        status = "ON" if self.auto_shoot_enabled else "OFF"
        self.log_message.emit(f"🎯 Auto-shoot: {status}")
    
    def stop(self):
        """Para worker"""
        self.running = False
        self.resume_event.set()  # ✅ Desbloqueia se estiver esperando
        self.wait()
    
    def run(self):
        """✅ Loop principal COM EVENTO (mais eficiente)"""
        self.log_message.emit("🚀 Worker iniciado")
        
        while self.running:
            loop_start = time.time()
            
            # ✅ CORREÇÃO 3: ESPERA COM EVENTO (não sleep fixo!)
            if not self.enabled:
                self.resume_event.wait(timeout=0.1)  # ✅ Mais eficiente!
                continue
            
            try:
                # Capturar tela
                hwnd = self.game_window['hwnd']
                screenshot = capture_screen(hwnd)
                
                if screenshot is None:
                    self.log_message.emit("⚠️ Falha ao capturar tela")
                    time.sleep(0.1)
                    continue
                
                # ✅ OCR com FALLBACK
                wind_result = recognize_wind_from_image(screenshot, self.config.WIND_ROI)
                if validate_ocr_result(wind_result, 'wind'):
                    self.last_valid_wind = wind_result
                wind_speed, wind_dir = self.last_valid_wind
                
                angle_result = recognize_angle_from_image(screenshot, self.config.PLAYER_ANGLE_ROI)
                if validate_ocr_result(angle_result, 'angle'):
                    self.last_valid_angle = angle_result
                current_angle = self.last_valid_angle
                
                power_result = recognize_power_from_image(screenshot, self.config.POWER_ROI)
                if validate_ocr_result(power_result, 'power'):
                    self.last_valid_power = power_result
                current_power = self.last_valid_power
                
                # ✅ Detecção com SMOOTHING (70/30)
                player_pos = detect_player_position(screenshot, self.config.GAME_AREA_ROI)
                if player_pos:
                    self.player_positions.append(player_pos)
                    if len(self.player_positions) > 5:
                        self.player_positions.pop(0)
                
                enemy_pos = detect_enemy_position(
                    screenshot,
                    self.config.GAME_AREA_ROI,
                    frame_count=self.frame_count  # ✅ Sem global!
                )
                if enemy_pos:
                    self.enemy_positions.append(enemy_pos)
                    if len(self.enemy_positions) > 5:
                        self.enemy_positions.pop(0)
                
                # Smoothed positions
                smoothed_player = self._get_smoothed_position(self.player_positions)
                smoothed_enemy = self._get_smoothed_position(self.enemy_positions)
                
                # ✅ Manual target mode
                target_pos = self.manual_mode.get_target() or smoothed_enemy
                
                # Calcular shot
                if smoothed_player and target_pos:
                    shot_angle, shot_power, trajectory = calculate_trajectory(
                        smoothed_player,
                        target_pos,
                        wind_speed,
                        wind_dir,
                        self.physics
                    )
                    
                    # ✅ Verificar se encontrou solução
                    if shot_angle is None or shot_power is None:
                        # Não encontrou solução - pular este frame
                        time.sleep(0.05)
                        continue
                    
                    # ✅ Validar ranges
                    shot_angle = max(0, min(90, shot_angle))
                    shot_power = max(0, min(100, shot_power))
                    
                    # ✅ Update overlay (com verificação None!)
                    if self.overlay_manager is not None:
                        self.overlay_manager.update_trajectory(trajectory)
                        self.overlay_manager.update_player(*smoothed_player)
                        self.overlay_manager.update_target(*target_pos)
                        self.overlay_manager.update_wind(wind_speed, wind_dir)
                        self.overlay_manager.update_shot_info(shot_angle, shot_power)
                        self.overlay_manager.update_player_power(current_power)
                        
                        # Status
                        if self.manual_mode.locked:
                            status = "Aimbot: ON (ALVO TRAVADO)"
                        else:
                            status = "Aimbot: ON"
                        self.overlay_manager.set_status(status)
                    
                    # Emit signals
                    self.shot_info_updated.emit({
                        'angle': shot_angle,
                        'power': shot_power,
                        'wind_speed': wind_speed,
                        'wind_direction': wind_dir
                    })
                    
                    self.detection_updated.emit({
                        'player': smoothed_player,
                        'enemy': target_pos,
                        'manual_locked': self.manual_mode.locked
                    })
                    
                    # ✅ Auto-shoot com VARIAÇÃO HUMANA
                    if self.auto_shoot_enabled:
                        now = time.time()
                        cooldown = random.uniform(2.5, 3.5)  # ✅ Variação!
                        
                        if now - self.last_shot_time >= cooldown:
                            success = self.automation.perform_shot(
                                hwnd,
                                current_angle,
                                shot_angle,
                                shot_power
                            )
                            
                            if success:
                                self.last_shot_time = now
                                self.log_message.emit(f"🎯 TIRO! Ângulo: {shot_angle}°, Força: {shot_power}%")
                
                # Performance
                loop_time = time.time() - loop_start
                self.loop_times.append(loop_time)
                if len(self.loop_times) > 30:
                    self.loop_times.pop(0)
                
                avg_loop_time = sum(self.loop_times) / len(self.loop_times)
                fps = 1.0 / avg_loop_time if avg_loop_time > 0 else 0
                
                self.performance_updated.emit({
                    'fps': fps,
                    'loop_time': loop_time * 1000  # ms
                })
                
                self.frame_count += 1
                
                # ✅ Sleep mínimo
                time.sleep(0.05)
                
            except Exception as e:
                self.log_message.emit(f"❌ Erro no loop: {e}")
                import traceback
                traceback.print_exc()
                time.sleep(0.1)
        
        self.log_message.emit("🛑 Worker parado")
    
    def _get_smoothed_position(self, positions):
        """Smoothing 70/30"""
        if not positions:
            return None
        
        if len(positions) == 1:
            return positions[0]
        
        # 70% último, 30% anterior
        last = positions[-1]
        prev = positions[-2]
        
        smoothed_x = int(last[0] * 0.7 + prev[0] * 0.3)
        smoothed_y = int(last[1] * 0.7 + prev[1] * 0.3)
        
        return (smoothed_x, smoothed_y)
 
# ═══════════════════════════════════════════════════════════════
# FIRST RUN DIALOG
# ═══════════════════════════════════════════════════════════════
 
class FirstRunDialog(QDialog):
    """Dialog de primeira execução"""
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("GunBound Aimbot - Primeira Execução")
        self.setModal(True)
        self.setMinimumSize(600, 400)
        
        self.game_window = None
        self.config = None
        
        self.setup_ui()
    
    def setup_ui(self):
        layout = QVBoxLayout()
        
        # Header
        header = QLabel("🎮 BEM-VINDO AO GUNBOUND AIMBOT v25.0 ULTRA FINAL")
        header.setStyleSheet("font-size: 16px; font-weight: bold; color: #4CAF50;")
        header.setAlignment(Qt.AlignCenter)
        layout.addWidget(header)
        
        # Info
        info = QLabel(
            "Este assistente irá configurar o aimbot automaticamente.\n\n"
            "1. Abra o GunBound\n"
            "2. Entre em uma partida\n"
            "3. Clique em 'Detectar Janela'"
        )
        info.setWordWrap(True)
        layout.addWidget(info)
        
        # Status
        self.status_label = QLabel("Status: Aguardando...")
        self.status_label.setStyleSheet("color: #FFA726;")
        layout.addWidget(self.status_label)
        
        # Buttons
        btn_layout = QHBoxLayout()
        
        self.btn_detect = QPushButton("🔍 Detectar Janela")
        self.btn_detect.clicked.connect(self.detect_window)
        btn_layout.addWidget(self.btn_detect)
        
        self.btn_ok = QPushButton("✅ Continuar")
        self.btn_ok.clicked.connect(self.accept)
        self.btn_ok.setEnabled(False)
        btn_layout.addWidget(self.btn_ok)
        
        layout.addLayout(btn_layout)
        
        self.setLayout(layout)
    
    def detect_window(self):
        self.status_label.setText("🔍 Procurando janela do GunBound...")
        QApplication.processEvents()
        
        time.sleep(0.5)
        
        game_window = detect_game_window()
        
        if game_window:
            self.game_window = game_window
            self.config = auto_calibrate(game_window)
            
            self.status_label.setText(
                f"✅ Janela detectada: {game_window['title']}\n"
                f"   Resolução: {game_window['rect'][2]}x{game_window['rect'][3]}"
            )
            self.status_label.setStyleSheet("color: #4CAF50;")
            self.btn_ok.setEnabled(True)
        else:
            self.status_label.setText(
                "❌ Janela não encontrada!\n"
                "   Certifique-se que o GunBound está aberto e em uma partida."
            )
            self.status_label.setStyleSheet("color: #F44336;")
 
# ═══════════════════════════════════════════════════════════════
# ✅ DASHBOARD PRINCIPAL COM TODAS AS CORREÇÕES
# ═══════════════════════════════════════════════════════════════
 
class AimbotDashboard(QMainWindow):
    """✅ Dashboard COM TODAS AS CORREÇÕES!"""
    
    def __init__(self):
        super().__init__()
        
        # State
        self.config = None
        self.game_window = None
        self.overlay_manager = None
        self.worker = None
        
        # Debounce
        self.last_f1_time = 0
        self.last_f2_time = 0
        self.last_f3_time = 0
        
        # Setup
        self.setWindowTitle("GunBound Aimbot v25.0 ULTRA FINAL")
        self.setMinimumSize(1200, 800)
        
        # ✅ First run (ANTES de criar overlay!)
        if not self.first_run():
            sys.exit(0)
        
        # ✅ UI setup
        self.setup_ui()
        
        # ✅ CORREÇÃO: Overlay DEPOIS de QApplication!
        self.create_overlay()
        
        # ✅ Hotkeys (QShortcut!)
        self.setup_hotkeys()
        
        # ✅ Tray icon
        self.setup_tray()
        
        # Logger
        self.logger = setup_logger()
    
    def first_run(self) -> bool:
        """Wizard de primeira execução"""
        # Verificar Tesseract
        if not find_tesseract():
            QMessageBox.critical(
                self,
                "Tesseract não encontrado",
                "Tesseract-OCR não foi encontrado!\n\n"
                "Baixe e instale de:\n"
                "https://github.com/UB-Mannheim/tesseract/wiki"
            )
            return False
        
        # Carregar config
        self.config = load_config()
        
        if self.config is None or not self.config.is_calibrated():
            # Primeira execução - wizard
            dialog = FirstRunDialog(self)
            if dialog.exec_() == QDialog.Accepted:
                self.game_window = dialog.game_window
                self.config = dialog.config
                return True
            else:
                return False
        else:
            # Config já existe - detectar janela
            self.game_window = detect_game_window()
            if not self.game_window:
                QMessageBox.warning(
                    self,
                    "Janela não encontrada",
                    "Abra o GunBound e entre em uma partida antes de iniciar o aimbot."
                )
                return False
            
            # Recalibrar se necessário
            current_rect = self.game_window['rect']
            if current_rect != getattr(self, '_last_rect', None):
                self.config.calibrate_from_window(self.game_window)
                save_config(self.config)
                self._last_rect = current_rect
            
            return True
    
    def create_overlay(self):
        """✅ Cria overlay DEPOIS de QApplication"""
        try:
            self.overlay_manager = OverlayManager(self.game_window)
            self.overlay_manager.show()
            self.log("✅ Overlay criado e ativado")
        except Exception as e:
            self.log(f"⚠️ Erro ao criar overlay: {e}")
            self.overlay_manager = None
    
    def setup_ui(self):
        """Setup da interface"""
        central = QWidget()
        self.setCentralWidget(central)
        
        main_layout = QHBoxLayout()
        
        # ═══ PAINEL ESQUERDO ═══
        left_panel = QWidget()
        left_layout = QVBoxLayout()
        
        # Header
        header = QLabel("🎮 GUNBOUND AIMBOT v25.0")
        header.setStyleSheet(
            "font-size: 20px; font-weight: bold; "
            "color: #4CAF50; padding: 10px;"
        )
        header.setAlignment(Qt.AlignCenter)
        left_layout.addWidget(header)
        
        # Controls
        controls_group = QGroupBox("⚙️ Controles")
        controls_layout = QVBoxLayout()
        
        self.btn_toggle = QPushButton("🎯 LIGAR AIMBOT (F1)")
        self.btn_toggle.setCheckable(True)
        self.btn_toggle.setMinimumHeight(50)
        self.btn_toggle.setStyleSheet(self.get_button_style(False))
        self.btn_toggle.clicked.connect(self.toggle_aimbot)
        controls_layout.addWidget(self.btn_toggle)
        
        self.btn_set_target = QPushButton("📍 Definir Alvo Manual (F2)")
        self.btn_set_target.setMinimumHeight(40)
        self.btn_set_target.clicked.connect(self.set_manual_target)
        controls_layout.addWidget(self.btn_set_target)
        
        self.btn_calculate = QPushButton("🧮 Calcular Tiro (F3)")
        self.btn_calculate.setMinimumHeight(40)
        self.btn_calculate.clicked.connect(self.calculate_shot)
        controls_layout.addWidget(self.btn_calculate)
        
        self.chk_auto_shoot = QCheckBox("🎯 Auto-Shoot (F4)")
        self.chk_auto_shoot.stateChanged.connect(self.toggle_auto_shoot)
        controls_layout.addWidget(self.chk_auto_shoot)
        
        controls_group.setLayout(controls_layout)
        left_layout.addWidget(controls_group)
        
        # Status
        status_group = QGroupBox("📊 Status")
        status_layout = QVBoxLayout()
        
        self.lbl_status = QLabel("Status: Desligado")
        self.lbl_fps = QLabel("FPS: --")
        self.lbl_loop_time = QLabel("Loop: -- ms")
        
        status_layout.addWidget(self.lbl_status)
        status_layout.addWidget(self.lbl_fps)
        status_layout.addWidget(self.lbl_loop_time)
        
        status_group.setLayout(status_layout)
        left_layout.addWidget(status_group)
        
        # Detection
        detection_group = QGroupBox("🎯 Detecção")
        detection_layout = QVBoxLayout()
        
        self.lbl_player = QLabel("Jogador: --")
        self.lbl_enemy = QLabel("Inimigo: --")
        self.lbl_manual = QLabel("Manual: --")
        
        detection_layout.addWidget(self.lbl_player)
        detection_layout.addWidget(self.lbl_enemy)
        detection_layout.addWidget(self.lbl_manual)
        
        detection_group.setLayout(detection_layout)
        left_layout.addWidget(detection_group)
        
        # Shot Info
        shot_group = QGroupBox("🎯 Tiro")
        shot_layout = QVBoxLayout()
        
        self.lbl_angle = QLabel("Ângulo: --")
        self.lbl_power = QLabel("Força: --")
        self.lbl_wind = QLabel("Vento: --")
        
        shot_layout.addWidget(self.lbl_angle)
        shot_layout.addWidget(self.lbl_power)
        shot_layout.addWidget(self.lbl_wind)
        
        shot_group.setLayout(shot_layout)
        left_layout.addWidget(shot_group)
        
        left_layout.addStretch()
        left_panel.setLayout(left_layout)
        left_panel.setMaximumWidth(350)
        
        # ═══ PAINEL DIREITO (LOGS) ═══
        right_panel = QWidget()
        right_layout = QVBoxLayout()
        
        log_header = QLabel("📋 Logs")
        log_header.setStyleSheet("font-size: 14px; font-weight: bold;")
        right_layout.addWidget(log_header)
        
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        self.log_text.setStyleSheet(
            "background: #1E1E1E; color: #E0E0E0; "
            "font-family: Consolas; font-size: 11px;"
        )
        right_layout.addWidget(self.log_text)
        
        right_panel.setLayout(right_layout)
        
        # Adicionar ao main
        main_layout.addWidget(left_panel)
        main_layout.addWidget(right_panel)
        
        central.setLayout(main_layout)
        
        # Dark theme
        self.apply_dark_theme()
        
        self.log("✅ Interface inicializada")
    
    def setup_hotkeys(self):
        """✅ Setup com QShortcut (não keyboard library!)"""
        # F1 - Toggle
        QShortcut(QKeySequence("F1"), self).activated.connect(self.toggle_aimbot_hotkey)
        
        # F2 - Set target
        QShortcut(QKeySequence("F2"), self).activated.connect(self.set_manual_target_hotkey)
        
        # F3 - Calculate
        QShortcut(QKeySequence("F3"), self).activated.connect(self.calculate_shot_hotkey)
        
        # F4 - Auto-shoot
        QShortcut(QKeySequence("F4"), self).activated.connect(self.toggle_auto_shoot_hotkey)
        
        self.log("✅ Hotkeys configurados (F1-F4)")
    
    def setup_tray(self):
        """Setup tray icon"""
        try:
            self.tray_icon = QSystemTrayIcon(self)
            self.tray_icon.setToolTip("GunBound Aimbot v25.0")
            
            tray_menu = QMenu()
            show_action = tray_menu.addAction("Mostrar")
            show_action.triggered.connect(self.show)
            
            quit_action = tray_menu.addAction("Sair")
            quit_action.triggered.connect(self.close)
            
            self.tray_icon.setContextMenu(tray_menu)
            self.tray_icon.show()
        except:
            pass
    
    # ═══════════════════════════════════════════════════════════════
    # ✅ CORREÇÃO 2: PROTEÇÃO CONTRA MÚLTIPLAS ATIVAÇÕES
    # ═══════════════════════════════════════════════════════════════
    
    def toggle_aimbot(self):
        """Toggle aimbot COM PROTEÇÃO"""
        if self.btn_toggle.isChecked():
            # ✅ VERIFICAR se worker já existe
            if self.worker is not None:
                self.log("⚠️ Worker já está rodando!")
                self.btn_toggle.setChecked(False)
                return
            
            # Criar worker
            self.worker = AimbotWorker(
                self.config,
                self.game_window,
                self.overlay_manager
            )
            
            # Conectar signals
            self.worker.performance_updated.connect(self.update_performance)
            self.worker.detection_updated.connect(self.update_detection)
            self.worker.shot_info_updated.connect(self.update_shot_info)
            self.worker.log_message.connect(self.log)
            
            # Iniciar
            self.worker.start()
            self.worker.enable()
            
            # UI
            self.btn_toggle.setText("🛑 DESLIGAR AIMBOT (F1)")
            self.btn_toggle.setStyleSheet(self.get_button_style(True))
            self.lbl_status.setText("Status: ✅ LIGADO")
            
            self.log("✅ Aimbot LIGADO")
        else:
            # Parar
            if self.worker:
                self.worker.disable()
                self.worker.stop()
                self.worker = None
            
            # UI
            self.btn_toggle.setText("🎯 LIGAR AIMBOT (F1)")
            self.btn_toggle.setStyleSheet(self.get_button_style(False))
            self.lbl_status.setText("Status: ⏸️ DESLIGADO")
            
            # ✅ Limpar overlay (com verificação None!)
            if self.overlay_manager is not None:
                self.overlay_manager.clear()
                self.overlay_manager.set_status("Aimbot: OFF")
            
            self.log("⏸️ Aimbot DESLIGADO")
    
    def toggle_aimbot_hotkey(self):
        """✅ F1 com DEBOUNCE"""
        now = time.time()
        if now - self.last_f1_time < 0.2:
            return
        self.last_f1_time = now
        
        self.btn_toggle.setChecked(not self.btn_toggle.isChecked())
        self.toggle_aimbot()
    
    def set_manual_target(self):
        """Set manual target"""
        if not self.worker or not self.worker.enabled:
            self.log("⚠️ Aimbot deve estar ligado!")
            return
        
        # Get mouse position
        pos = pyautogui.position()
        
        # Convert to game window coordinates
        game_x = self.game_window['rect'][0]
        game_y = self.game_window['rect'][1]
        
        target_x = pos.x - game_x
        target_y = pos.y - game_y
        
        # Set target
        self.worker.manual_mode.set_target(target_x, target_y)
        
        self.log(f"📍 Alvo manual definido: ({target_x}, {target_y})")
    
    def set_manual_target_hotkey(self):
        """✅ F2 com DEBOUNCE"""
        now = time.time()
        if now - self.last_f2_time < 0.2:
            return
        self.last_f2_time = now
        
        self.set_manual_target()
    
    def calculate_shot(self):
        """Calculate shot"""
        self.log("🧮 Calculando tiro...")
    
    def calculate_shot_hotkey(self):
        """✅ F3 com DEBOUNCE"""
        now = time.time()
        if now - self.last_f3_time < 0.2:
            return
        self.last_f3_time = now
        
        self.calculate_shot()
    
    def toggle_auto_shoot(self):
        """Toggle auto-shoot"""
        if self.worker:
            self.worker.toggle_auto_shoot()
    
    def toggle_auto_shoot_hotkey(self):
        """F4 - toggle auto-shoot"""
        self.chk_auto_shoot.setChecked(not self.chk_auto_shoot.isChecked())
    
    # ═══════════════════════════════════════════════════════════════
    # UPDATES
    # ═══════════════════════════════════════════════════════════════
    
    def update_performance(self, data):
        """Update performance"""
        self.lbl_fps.setText(f"FPS: {data['fps']:.1f}")
        self.lbl_loop_time.setText(f"Loop: {data['loop_time']:.1f} ms")
    
    def update_detection(self, data):
        """Update detection"""
        player = data.get('player')
        enemy = data.get('enemy')
        manual = data.get('manual_locked', False)
        
        if player:
            self.lbl_player.setText(f"Jogador: ({player[0]}, {player[1]})")
        
        if enemy:
            self.lbl_enemy.setText(f"Inimigo: ({enemy[0]}, {enemy[1]})")
        
        if manual:
            self.lbl_manual.setText("Manual: 🔒 TRAVADO")
        else:
            self.lbl_manual.setText("Manual: 🔓 Livre")
    
    def update_shot_info(self, data):
        """Update shot info"""
        self.lbl_angle.setText(f"Ângulo: {data['angle']}°")
        self.lbl_power.setText(f"Força: {data['power']}%")
        self.lbl_wind.setText(
            f"Vento: {data['wind_speed']} {data['wind_direction']}"
        )
    
    def log(self, message: str):
        """Log message"""
        timestamp = datetime.now().strftime("%H:%M:%S")
        formatted = f"[{timestamp}] {message}"
        self.log_text.append(formatted)
        
        # Auto-scroll
        scrollbar = self.log_text.verticalScrollBar()
        scrollbar.setValue(scrollbar.maximum())
    
    # ═══════════════════════════════════════════════════════════════
    # STYLES
    # ═══════════════════════════════════════════════════════════════
    
    def get_button_style(self, active: bool) -> str:
        """Get button style"""
        if active:
            return """
                QPushButton {
                    background: #F44336;
                    color: white;
                    font-size: 14px;
                    font-weight: bold;
                    border-radius: 8px;
                    padding: 10px;
                }
                QPushButton:hover {
                    background: #D32F2F;
                }
            """
        else:
            return """
                QPushButton {
                    background: #4CAF50;
                    color: white;
                    font-size: 14px;
                    font-weight: bold;
                    border-radius: 8px;
                    padding: 10px;
                }
                QPushButton:hover {
                    background: #45A049;
                }
            """
    
    def apply_dark_theme(self):
        """Apply dark theme"""
        self.setStyleSheet("""
            QMainWindow {
                background: #2B2B2B;
            }
            QWidget {
                background: #2B2B2B;
                color: #E0E0E0;
                font-family: Segoe UI;
            }
            QGroupBox {
                border: 2px solid #404040;
                border-radius: 8px;
                margin-top: 10px;
                padding-top: 10px;
                font-weight: bold;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 10px;
                padding: 0 5px;
            }
            QPushButton {
                background: #404040;
                color: white;
                border-radius: 6px;
                padding: 8px;
                font-size: 12px;
            }
            QPushButton:hover {
                background: #505050;
            }
            QCheckBox {
                spacing: 8px;
            }
            QLabel {
                color: #E0E0E0;
            }
        """)
    
    # ═══════════════════════════════════════════════════════════════
    # ✅ CORREÇÃO 4: SALVAMENTO DE ESTADO AO FECHAR
    # ═══════════════════════════════════════════════════════════════
    
    def closeEvent(self, event):
        """✅ Close COM SALVAMENTO DE ESTADO!"""
        print("\n👋 Encerrando...")
        
        # ✅ CORREÇÃO 4: Salvar estado
        if self.worker and self.worker.enabled:
            try:
                state = {
                    'last_target': self.worker.manual_mode.manual_target,
                    'last_wind': self.worker.last_valid_wind,
                    'last_angle': self.worker.last_valid_angle,
                    'last_power': self.worker.last_valid_power,
                    'auto_shoot_enabled': self.worker.auto_shoot_enabled
                }
                
                # Salvar em arquivo
                state_path = Path.home() / '.gunbound_aimbot' / 'last_state.json'
                with open(state_path, 'w') as f:
                    json.dump(state, f, indent=2)
                
                print("✅ Estado salvo")
            except Exception as e:
                print(f"⚠️ Erro ao salvar estado: {e}")
        
        # Parar worker
        if self.worker:
            self.worker.disable()
            self.worker.stop()
            print("✅ Worker parado")
        
        # Esconder overlay
        if self.overlay_manager is not None:
            self.overlay_manager.hide()
            print("✅ Overlay escondido")
        
        # Aceitar close
        event.accept()
        print("✅ Encerrado!\n")
 
# ═══════════════════════════════════════════════════════════════
# MAIN
# ═══════════════════════════════════════════════════════════════
 
def main():
    """Main entry point"""
    print("\n" + "="*70)
    print("🎮 GUNBOUND AIMBOT v25.0 - ULTRA ULTRA FINAL")
    print("="*70 + "\n")
    
    # ✅ QApplication PRIMEIRO!
    app = QApplication(sys.argv)
    
    # Dashboard
    dashboard = AimbotDashboard()
    dashboard.show()
    
    print("✅ Dashboard aberto!")
    print("\n💡 HOTKEYS:")
    print("   F1 - Ligar/Desligar aimbot")
    print("   F2 - Definir alvo manual (posição do mouse)")
    print("   F3 - Calcular tiro")
    print("   F4 - Toggle auto-shoot")
    print()
    
    # Run
    sys.exit(app.exec_())
 
if __name__ == '__main__':
    main()

Repository:
You cant view this link please login.


Dev Note:
The logic currently uses a 200ms debounce on hotkeys to prevent input spam. The trajectory calculations are handled via a physics wrapper. I have included a setup wizard to handle the initial window detection, so it should be relatively plug-and-play if you are running at standard resolutions.

I’m currently looking into refining the OCR fallback logic since it can be inconsistent during high-intensity matches. If any of you coders here have ideas on how to optimize the `detect_enemy_position` loop to reduce the frame-time or have a better way to hook the game memory without triggering detection, drop your fixes below.

Has anyone tested this on the current server version? Let me know if you run into any weird behavior with the auto-shoot timing.
 
Top