diff --git a/.gitignore b/.gitignore index 4c785298..7119bfd0 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,4 @@ sunone_aimbot_cpp/modules/SimpleIni.h /sunone_aimbot_cpp/modules/serial sunone_aimbot_cpp/config.ini /sunone_aimbot_cpp/sunone_aimbot_cpp.zip +/sunone_aimbot_cpp/RN_AI \ No newline at end of file diff --git a/LICENSE b/LICENSE index 2aa7dd01..6325fe95 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 SunOne +Copyright (c) 2025 ReksarGames Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 3dc4555b..62194f25 100644 --- a/README.md +++ b/README.md @@ -1,383 +1,229 @@ -## 🛠️ Main Changes in This Version - -1. **HID Methods Implementation** - Added two methods to improve system accuracy and speed. -2. **Makcu Method** - Improvements to game movement handling and control. -3. **Kalman Filter** - Increased accuracy of target movement prediction. -4. **Aiming Smoothness** - Reduced jitter, improving user experience. -5. **Performance** - Optimized processes for higher performance on supported devices. -6. **Code Cleanup** - Applied SOLID principles to improve code structure and maintainability. +# 🎯 RN_AI_cpp — AI Aim Assistant ---- - -## 🟣 New Configurations and Features - -### 🎨 Colorbot — Color Detection Parameters +
-* **color_erode_iter:** number of erosion iterations — reduces image noise by removing small artifacts. -* **color_dilate_iter:** number of dilation iterations — enlarges objects after erosion, restoring target shape. -* **color_min_area:** minimum object area for detection — ignores very small regions (noise). -* **color_target:** target color for tracking (e.g., Yellow). -* **tinyArea:** minimum "point" to filter small elements — helps remove noise not related to the target. -* **isOnlyTop:** consider only top objects/layers (true/false) — useful for selecting the most visible target. -* **scanError:** allowed error in color scanning — reduces false positives. +![Status](https://img.shields.io/badge/Status-Active-brightgreen?style=for-the-badge) +![License](https://img.shields.io/badge/License-MIT-blue?style=for-the-badge) +![Platform](https://img.shields.io/badge/Platform-Windows%2010%2F11-blue?style=for-the-badge) +![CUDA](https://img.shields.io/badge/CUDA-12.8-76B900?style=for-the-badge) +![TensorRT](https://img.shields.io/badge/TensorRT-10.8-76B900?style=for-the-badge) -💡 **Description:** -Colorbot improves target detection by color, filtering noise and keeping accuracy on top objects. Perfect for highlighting specific targets on screen. - ---- +[🚀 Quick Start](#-quick-start) • [📚 Documentation](#-technical-details) * [📚Русская версия README](README_RU.md) -### 🎯 Kalman Filter — Target Movement Prediction -💡 **Description:** -The Kalman filter smooths target movement and predicts its future position. This reduces jitter during aiming and improves shooting accuracy. +![RN_AI Demo](docs/demo.gif) -**Parameter Purpose:** - -* **kalman_process_noise:** accounts for random changes in target movement (process noise). -* **kalman_measurement_noise:** accounts for measurement inaccuracies (sensor or camera noise). -* **kalman_speed_multiplier_x / kalman_speed_multiplier_y:** scales prediction speed horizontally and vertically. -* **resetThreshold:** threshold above which the filter resets and starts tracking the target anew. +
--- -### 🖥️ HID — Device Connection +## ✨ Features -* **hid_vid:** `0x1956` -* **hid_pid:** `0x3001` -* **PING_CODE:** `0xF9` - -💡 **Description:** -HID configuration allows direct connection to specific boards for controlling the system. Use these parameters for connecting an Arduino Leonardo. +| | | +|---|---| +| **🎯 AI Detection** | Target detection using neural networks with high accuracy | +| **🎨 Color Detection** | Target identification through color-based filtering | +| **📈 Real-time Stats** | FPS counter and latency information | +| **🖱️ Aim Simulator** | Visualization of target movement prediction | +| **🎛️ ClassTable** | Real-time dynamic class management | +| **🔄 Kalman Filter** | Smooth movement without aim jitter | +| **⚡ Multiple Backends** | DirectML, CUDA+TensorRT, Color Detection | --- -### ⚠️ Important Changes +## 🚀 Quick Start -* Removed methods that are already detected automatically: **Arduino**, **WIN32**, **HID**. -* These methods remained in the code but are no longer needed, as they are detected automatically. -* If necessary, you can re-enable them depending on your firmware and hardware. +### 1️⃣ Choose Your Build +
+🟢 DirectML (Universal) -[![C++](https://img.shields.io/badge/C%2B%2B-17-blue)](https://github.com/SunOner/sunone_aimbot_cpp) -[![License MIT](https://badgen.net/github/license/SunOner/sunone_aimbot_cpp)](https://github.com/SunOner/sunone_aimbot_cpp/blob/main/LICENSE) -

- - - -

- +**For:** Any GPU (NVIDIA, AMD, Intel, integrated graphics) -### 🟢 DirectML (DML) Build — Universal (All GPUs) +``` +✅ Windows 10/11 (x64) +✅ No CUDA required +✅ Recommended for older GPUs +``` -* **Works on:** +**Recommended for:** +- GTX 10xx/9xx/7xx series +- AMD Radeon GPU +- Intel Iris/Xe GPU +- Laptops and office PCs - * Any modern GPU (NVIDIA, AMD, Intel, including integrated graphics) - * Windows 10/11 (x64) - * No need for CUDA or special drivers! -* **Recommended for:** +
- * GTX 10xx/9xx/7xx series (old NVIDIA) - * Any AMD Radeon or Intel Iris/Xe GPU - * Laptops and office PCs with integrated graphics -* **Download DML build:** - [DirectML Release](https://disk.yandex.ru/d/9mf8VwfN0cK96w) +
+🟡 CUDA + TensorRT (Maximum Performance) -### 🟡 CUDA + TensorRT Build — High Performance (NVIDIA Only) +**For:** Latest generation NVIDIA GPUs -* **Works on:** +``` +✅ RTX 2000/3000/4000 and newer +✅ GTX 1660 +✅ CUDA 12.8 + TensorRT 10.8 (included) +❌ Does not support GTX 10xx/Pascal and older +``` - * NVIDIA GPUs **GTX 1660, RTX 2000/3000/4000 or newer** - * **Requires:** CUDA 12.8, TensorRT 10.8 (included in build) - * Windows 10/11 (x64) -* **Not supported:** GTX 10xx/Pascal and older (TensorRT 10 limitation) -* **Includes both CUDA+TensorRT and DML support (switchable in settings)** -* **Download CUDA build:** - [CUDA + TensorRT Release](https://disk.yandex.ru/d/VjyDyWLbv7AUHQ) +**Features:** +- Switch between CUDA+TensorRT and DML in settings +- Maximum FPS and accuracy +- Professional-grade performance -**Both versions are ready-to-use: just download, unpack, run `ai.exe` and follow instructions in the overlay.** +
--- -## 🚀 How to Run (For Precompiled Builds) +## ⚙️ Configuration & Parameters -1. **Download and unpack your chosen version (see links above).** -2. For CUDA build, install [CUDA 12.8](https://developer.nvidia.com/cuda-12-8-0-download-archive) if not already installed. -3. For DML build, no extra software is needed. -4. **Run `ai.exe`.** - On first launch, the model will be exported (may take up to 5 minutes). -5. Place your `.onnx` model in the `models` folder and select it in the overlay (HOME key). -6. All settings are available in the overlay. - Use the HOME key to open/close overlay. +### 📦 ClassTable — Class Management -### 🎮 Controls - -* **Right Mouse Button:** Aim at the detected target -* **F2:** Exit -* **F3:** Pause aiming -* **F4:** Reload config -* **Home:** Open/close overlay and settings +Dynamic management of target classes with: +- ✅ Add/switch classes in real-time +- ✅ Auto-detection of new classes +- ✅ Configure Y1/Y2 position for each class --- -# 🛠️ Build From Source (Advanced Users) - -If you want to compile the project yourself or modify code, follow these instructions. - -## 1. Requirements - -* **Visual Studio 2022 Community** ([Download](https://visualstudio.microsoft.com/vs/community/)) -* **Windows 10 or 11 (x64)** -* **Windows SDK 10.0.26100.0** or newer -* **CMake** ([Download](https://cmake.org/)) -* **OpenCV 4.10.0** -* **\[For CUDA version]** +### 🎨 Colorbot — Color Detection - * [CUDA Toolkit 12.8](https://developer.nvidia.com/cuda-12-8-0-download-archive) - * [cuDNN 9.7.1](https://developer.nvidia.com/cudnn-downloads) - * [TensorRT 10.8.0.43](https://developer.nvidia.com/tensorrt/download/10x) -* **\[For DML version]** +Advanced color filtering system: - * You can use [pre-built OpenCV DLLs](https://github.com/opencv/opencv/releases/tag/4.10.0) (just copy `opencv_world4100.dll` to your exe folder) -* Other dependencies: +| Parameter | Range | Description | +|-----------|-------|-------------| +| `color_erode_iter` | 0-5 | Number of erosion iterations (reduces noise) | +| `color_dilate_iter` | 0-5 | Number of dilation iterations (restores size) | +| `color_min_area` | 1-1000 | Minimum object area | +| `color_target` | Yellow/Red/etc | Target color for tracking | +| `tinyArea` | 1-100 | Small element filtering threshold | +| `isOnlyTop` | true/false | Consider only top objects | +| `scanError` | 0-100 | Allowed search error (0=precise) | - * [simpleIni](https://github.com/brofield/simpleini/blob/master/SimpleIni.h) - * [serial](https://github.com/wjwwood/serial) - * [GLFW](https://www.glfw.org/download.html) - * [ImGui](https://github.com/ocornut/imgui) +**💡 Use:** Accurate color-based target selection while ignoring noise --- -## 2. Choose Build Target in Visual Studio +### 🎯 Kalman Filter — Movement Prediction -* **DML (DirectML):** - Select `Release | x64 | DML` (works on any modern GPU) -* **CUDA (TensorRT):** - Select `Release | x64 | CUDA` (requires supported NVIDIA GPU, see above) +Smoothing filter for target position prediction: ---- - -## 3. Placement of Third-Party Modules and Libraries - -Before building the project, **download and place all third-party dependencies** in the following directories inside your project structure: +| Parameter | Description | +|-----------|-------------| +| `kalman_process_noise` | Accounts for random movement changes | +| `kalman_measurement_noise` | Accounts for sensor/camera errors | +| `kalman_speed_multiplier_x/y` | Speed multiplier per axis | +| `resetThreshold` | Filter reinitialization threshold | -**Required folders inside your repository:** +**💡 Result:** Smooth aiming without jitter -``` -sunone_aimbot_cpp/ -└── sunone_aimbot_cpp/ - └── modules/ -``` - -**Place each dependency as follows:** +--- -| Library | Path | -| --------- | ----------------------------------------------------------------- | -| SimpleIni | `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/SimpleIni.h` | -| serial | `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/serial/` | -| TensorRT | `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/TensorRT-10.8.0.43/` | -| GLFW | `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/glfw-3.4.bin.WIN64/` | -| OpenCV | `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/opencv/` | -| cuDNN | `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/cudnn/` | +## 🖥️ Interface & Controls -* **SimpleIni:** - Download [`SimpleIni.h`](https://github.com/brofield/simpleini/blob/master/SimpleIni.h) - Place in `modules/`. +### 🎨 ImGui Menu -* **serial:** - Download the [`serial`](https://github.com/wjwwood/serial) library (whole folder). - To build, open +**Menu interface features:** - ``` - sunone_aimbot_cpp/sunone_aimbot_cpp/modules/serial/visual_studio/visual_studio.sln - ``` +- 🧭 Vertical navbar with custom icons +- 🖼️ Custom background via `ui_bg.png` +- 🎨 Theming in `ui_theme.ini` +- ⚙️ `Components` tab for runtime configuration - * Set **C/C++ > Code Generation > Runtime Library** to **Multi-threaded (/MT)** - * Build in **Release x64** - * Use the built DLL/LIB with your project. +#### 📸 Interface Screenshots -* **TensorRT:** - Download [TensorRT 10.8.0.43](https://developer.nvidia.com/tensorrt/download/10x) - Place the folder as shown above. +| Screen Capture | Target Status | +|---|---| +| ![Capture](docs\menu\сapture.jpg) | ![Status](docs\menu\status.jpg) | -* **GLFW:** - Download [GLFW Windows binaries](https://www.glfw.org/download.html) - Place the folder as shown above. +#### 🎛️ Overlay Controls -* **OpenCV:** - Use your custom build or official DLLs (see CUDA/DML notes below). - Place DLLs either next to your exe or in `modules/opencv/`. +- **Overlay Opacity** — Transparency (slider or ±) +- **UI Scale** — Interface scale (± or manual input) +- **Window Width/Height** — Window size (manual input) +- **Resize Handles** — Resize window from edges -* **cuDNN:** - Place cuDNN files here (for CUDA build): - `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/cudnn/` +### 🎮 Game Overlay — On-Screen Visualization -**Example structure after setup:** +Information displayed directly on desktop over games and apps: -``` -sunone_aimbot_cpp/ -└── sunone_aimbot_cpp/ - └── modules/ - ├── SimpleIni.h - ├── serial/ - ├── TensorRT-10.8.0.43/ - ├── glfw-3.4.bin.WIN64/ - ├── opencv/ - └── cudnn/ -``` +- 📊 **Stats** — FPS counter and latency info +- 🎯 **Aim Simulator** — Aiming prediction visualization +- 🔲 **Detection Boxes** — Detected target boxes +- 🎨 **Class Colors** — Auto-coloring (class 0 = green) +- 📝 **Text Size** — Adjustable in Components → Advanced --- -## 4. How to Build OpenCV 4.10.0 with CUDA Support (For CUDA Version Only) - -> This section is **only required** if you want to use the CUDA (TensorRT) version and need OpenCV with CUDA support. -> For DML build, skip this step — you can use the pre-built OpenCV DLL. - -**Step-by-step instructions:** - -1. **Download Sources** - - * [OpenCV 4.10.0](https://github.com/opencv/opencv/releases/tag/4.10.0) - * [OpenCV Contrib 4.10.0](https://github.com/opencv/opencv_contrib/releases/tag/4.10.0) - * [CMake](https://cmake.org/download/) - * [CUDA Toolkit 12.8](https://developer.nvidia.com/cuda-12-8-0-download-archive) - * [cuDNN 9.7.1](https://developer.nvidia.com/cudnn-downloads) - -2. **Prepare Directories** - - * Create: - `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/opencv/` - `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/opencv/build` - * Extract `opencv-4.10.0` into - `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/opencv/opencv-4.10.0` - * Extract `opencv_contrib-4.10.0` into - `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/opencv/opencv_contrib-4.10.0` - * Extract cuDNN to - `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/cudnn` - -3. **Configure with CMake** - - * Open CMake GUI - * Source code: - `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/opencv/opencv-4.10.0` - * Build directory: - `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/opencv/build` - * Click **Configure** - (Choose "Visual Studio 17 2022", x64) - -4. **Enable CUDA Options** - - * After first configure, set the following: - - * `WITH_CUDA` = ON - * `WITH_CUBLAS` = ON - * `ENABLE_FAST_MATH` = ON - * `CUDA_FAST_MATH` = ON - * `WITH_CUDNN` = ON - * `CUDNN_LIBRARY` = - `full_path_to/sunone_aimbot_cpp/sunone_aimbot_cpp/modules/cudnn/lib/x64/cudnn.lib` - * `CUDNN_INCLUDE_DIR` = - `full_path_to/sunone_aimbot_cpp/sunone_aimbot_cpp/modules/cudnn/include` - * `CUDA_ARCH_BIN` = - See [CUDA Wikipedia](https://en.wikipedia.org/wiki/CUDA) for your GPU. - Example for RTX 3080-Ti: `8.6` - * `OPENCV_DNN_CUDA` = ON - * `OPENCV_EXTRA_MODULES_PATH` = - `full_path_to/sunone_aimbot_cpp/sunone_aimbot_cpp/modules/opencv/opencv_contrib-4.10.0/modules` - * `BUILD_opencv_world` = ON - * Uncheck: - - * `WITH_NVCUVENC` - * `WITH_NVCUVID` - * Click **Configure** again - (make sure nothing is reset) - * Click **Generate** - -5. **Build in Visual Studio** - - * Open `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/opencv/build/OpenCV.sln` - or click "Open Project" in CMake - * Set build config: **x64 | Release** - * Build `ALL_BUILD` target (can take up to 2 hours) - * Then build `INSTALL` target - -6. **Copy Resulting DLLs** - - * DLLs: - `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/opencv/build/install/x64/vc16/bin/` - * LIBs: - `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/opencv/build/install/x64/vc16/lib/` - * Includes: - `sunone_aimbot_cpp/sunone_aimbot_cpp/modules/opencv/build/install/include/opencv2` - * Copy needed DLLs (`opencv_world4100.dll`, etc.) next to your project’s executable. +## 🔧 Technical Details ---- +### 📁 File Structure -## 5. Notes on OpenCV for CUDA/DML +| File | Purpose | +|------|---------| +| **config.ini** | Main project configuration | +| **ui_theme.ini** | UI colors, sizes, and parameters | +| **ui_bg.png** | Menu background image (replaceable) | +| **imgui.ini** | Window state (local, not committed) | -* **For CUDA build (TensorRT backend):** +### 📦 Core Modules - * You **must** build OpenCV with CUDA support (see the guide above). - * Place all built DLLs (e.g., `opencv_world4100.dll`) next to your executable or in the `modules` folder. -* **For DML build (DirectML backend):** +📹 **capture/** — Screen capture methods +- DirectX Duplication API — `duplication_api_capture` +- Windows Runtime capture — `winrt_capture` +- [📖 OBS Capture](docs/obs/obs_en.md) — `obs_capture` - * You can use the official pre-built OpenCV DLLs if you **only** plan to use DirectML. - * If you want to use both CUDA and DML modes in the same executable, you should always use your custom OpenCV build with CUDA enabled (it will work for both modes). -* **Note:** - If you run the CUDA backend with non-CUDA OpenCV DLLs, the program will not work and may crash due to missing symbols. +🧠 **detector/** — Target detection system +- DirectML detector — `dml_detector` +- TensorRT detector (NVIDIA) — `trt_detector` +- Color-based detection — `color_detector` ---- +🎨 **overlay/** — Visual interface +- ImGui implementation — `imgui_impl_*` +- 2D/3D rendering — `rendering` -## 6. Build and Run +### ⚡ Input Methods -1. Open the solution in Visual Studio 2022. -2. Choose your configuration (`Release | x64 | DML` or `Release | x64 | CUDA`). -3. Build the solution. -4. Run `ai.exe` from the output folder. +- **WIN32 API** — Built-in Windows APIs + ⚠️ **Warning:** Don't use in games (instant detection) ---- +- **Makcu/Kmbox/KmboxNet** — Specialized input devices + ✅ Recommended for games (low latency) -## 🔄 Exporting AI Models +--- -* Convert PyTorch `.pt` models to ONNX: +## 📚 Links & Resources - ```bash - pip install ultralytics -U - yolo export model=sunxds_0.5.6.pt format=onnx dynamic=true simplify=true - ``` -* To convert `.onnx` to `.engine` for TensorRT, use the overlay export tab (open overlay with HOME). +### 📖 Documentation -## 📋 Configuration +- 🔗 [TensorRT Docs](https://docs.nvidia.com/deeplearning/tensorrt/) +- 🔗 [OpenCV Docs](https://docs.opencv.org/4.x/d1/dfb/intro.html) +- 🔗 [CUDA 12.8](https://developer.nvidia.com/cuda-12-8-0-download-archive) +- 🔗 [Config](docs\config_en.md) -* See all configuration options and documentation here: - [config\_cpp.md](https://github.com/SunOner/sunone_aimbot_docs/blob/main/config/config_cpp.md) +### 🛠️ Libraries Used ---- +| Library | Purpose | +|---------|---------| +| [ImGui](https://github.com/ocornut/imgui) | User Interface | +| [OpenCV](https://opencv.org/) | Computer Vision | +| [TensorRT](https://developer.nvidia.com/tensorrt) | Neural network inference (NVIDIA) | +| [DirectML](https://github.com/microsoft/DirectML) | GPU computing (universal) | +| [CppWinRT](https://github.com/microsoft/cppwinrt) | Windows Runtime APIs | +| [GLFW](https://www.glfw.org/) | Window management | +| [nlohmann/JSON](https://github.com/nlohmann/json) | JSON processing | -## 📚 References & Useful Links +### 💡 Methods & Inspiration -* [TensorRT Documentation](https://docs.nvidia.com/deeplearning/tensorrt/) -* [OpenCV Documentation](https://docs.opencv.org/4.x/d1/dfb/intro.html) -* [ImGui](https://github.com/ocornut/imgui) -* [CppWinRT](https://github.com/microsoft/cppwinrt) -* [GLFW](https://www.glfw.org/) -* [WindMouse](https://ben.land/post/2021/04/25/windmouse-human-mouse-movement/) -* [KMBOX](https://www.kmbox.top/) -* [Python AI Version](https://github.com/SunOner/sunone_aimbot) +- 🔗 [WindMouse Algorithm](https://ben.land/post/2021/04/25/windmouse-human-mouse-movement/) — Natural mouse movement +- 🔗 [KMBOX](https://www.kmbox.top/) — Input device integration +- 🐍 [RN_AI (Python version)](https://github.com/ReksarGames/RN_AI) +- 🔀 [Original SunOne Aimbot](https://github.com/SunOner/sunone_aimbot_cpp) — RN_AI_cpp is a complete fork and rebuild --- -## 📄 Licenses - -### OpenCV +
-* **License:** [Apache License 2.0](https://opencv.org/license.html) +**Made with ❤️ for the gaming community** -### ImGui - -* **License:** [MIT License](https://github.com/ocornut/imgui/blob/master/LICENSE) +
diff --git a/README_ru.md b/README_ru.md new file mode 100644 index 00000000..2b10391e --- /dev/null +++ b/README_ru.md @@ -0,0 +1,226 @@ +# 🎯 RN_AI_cpp — AI Aim Assistant + +
+ +![Status](https://img.shields.io/badge/Status-Active-brightgreen?style=for-the-badge) +![License](https://img.shields.io/badge/License-MIT-blue?style=for-the-badge) +![Platform](https://img.shields.io/badge/Platform-Windows%2010%2F11-blue?style=for-the-badge) +![CUDA](https://img.shields.io/badge/CUDA-12.8-76B900?style=for-the-badge) +![TensorRT](https://img.shields.io/badge/TensorRT-10.8-76B900?style=for-the-badge) + +[🚀 Быстрый старт](#-быстрый-старт) • [📚 Документация](#-технические-детали) * [English README](README.md) + +![RN_AI Demo](docs/demo.gif) + +
+ + +## ✨ Возможности + +| | | +|---|---| +| **🎯 AI Detection** | Детектирование целей через нейросети с высокой точностью | +| **🎨 Color Detection** | Определение цели по цвету через фильтрацию | +| **📈 Real-time Stats** | FPS счетчик и информация о задержке | +| **🖱️ Aim Simulator** | Визуализация предсказания движения цели | +| **🎛️ ClassTable** | Динамическое управление классами в реальном времени | +| **🔄 Kalman Filter** | Сглаживание движения без дрожания прицела | +| **⚡ Multiple Backends** | DirectML, CUDA+TensorRT, Color Detection | + +--- + +## 🚀 Быстрый старт + +### 1️⃣ Выберите сборку + +
+🟢 DirectML (Универсальная) + +**Для:** Любые GPU (NVIDIA, AMD, Intel, встроенная видеокарта) + +``` +✅ Windows 10/11 (x64) +✅ Без необходимости CUDA +✅ Авто-рекомендуется для старых GPU +``` + +**Рекомендуется для:** +- GTX 10xx/9xx/7xx серии +- AMD Radeon GPU +- Intel Iris/Xe GPU +- Ноутбуки и офисные ПК + +
+ +
+🟡 CUDA + TensorRT (Максимальная производительность) + +**Для:** NVIDIA GPU последних поколений + +``` +✅ RTX 2000/3000/4000 и новее +✅ GTX 1660 +✅ CUDA 12.8 + TensorRT 10.8 (встроено) +❌ Не поддерживает GTX 10xx/Pascal и старше +``` + +**Возможности:** +- Переключение между CUDA+TensorRT и DML в настройках +- Максимальный FPS и точность +- Professional-grade производительность + +
+ +--- + +## ⚙️ Настройки и параметры + +### 📦 ClassTable — Управление классами + +Динамическое управление классами целей с возможностью: +- ✅ Переключать/добавлять классы в реальном времени +- ✅ Автодобавление найденных классов +- ✅ Настройка позиции Y1/Y2 для каждого класса + +--- + +### 🎨 Colorbot — Определение цвета + +Расширенная система цветовой фильтрации: + +| Параметр | Значение | Описание | +|----------|---------|---------| +| `color_erode_iter` | 0-5 | Кол-во итераций эрозии (уменьшает шум) | +| `color_dilate_iter` | 0-5 | Кол-во итераций дилатации (восстанавливает размер) | +| `color_min_area` | 1-1000 | Минимальная площадь объекта | +| `color_target` | Yellow/Red/etc | Целевой цвет для отслеживания | +| `tinyArea` | 1-100 | Порог фильтрации мелких элементов | +| `isOnlyTop` | true/false | Учитывать только верхние объекты | +| `scanError` | 0-100 | Допустимая ошибка при поиске (0=точно) | + +**💡 Применение:** Точное выделение целей по цвету с игнорированием шума + +--- + +### 🎯 Kalman Filter — Предсказание движения + +Сглаживающий фильтр для предсказания позиции цели: + +| Параметр | Описание | +|----------|---------| +| `kalman_process_noise` | Учет случайных изменений движения | +| `kalman_measurement_noise` | Учет ошибок датчика/камеры | +| `kalman_speed_multiplier_x/y` | Множитель скорости по осям | +| `resetThreshold` | Порог переинициализации фильтра | + +**💡 Результат:** Гладкое наведение без дрожания + +--- + +## 🖥️ Интерфейс и управление + +### ImGui Menu + +**Интерфейс меню включает:** + +- 🧭 Вертикальная навбар с иконками +- 🖼️ Кастомный фон через `ui_bg.png` +- 🎨 Темизация в `ui_theme.ini` +- ⚙️ Таб `Components` для runtime-настройки + +#### 📸 Скриншоты интерфейса + +| Захват экрана | Статус целей | +|---|---| +| ![Capture](docs\menu\сapture.jpg) | ![Status](docs\menu\status.jpg) | + +#### 🎛️ Контролы оверлея + +- **Overlay Opacity** — Прозрачность (слайдер или ±) +- **UI Scale** — Масштаб интерфейса (± или ручной ввод) +- **Window Width/Height** — Размер окна (ручной ввод) +- **Resize Handles** — Изменение окна за края + +### 🎮 Game Overlay — Визуализация на экране + +Информация выводится прямо на рабочий стол поверх игры: + +- 📊 **Stats** — FPS счетчик и информация о задержке +- 🎯 **Aim Simulator** — Визуализация предсказания наводки +- 🔲 **Detection Boxes** — Боксы обнаруженных целей +- 🎨 **Class Colors** — Автоматическая раскраска (класс 0 = зеленый) +- 📝 **Text Size** — Настройка размера в Components → Advanced + +--- + +## 🔧 Технические детали + +### 📁 Структура файлов + +| Файл | Назначение | +|------|-----------| +| **config.ini** | Основная конфигурация проекта | +| **ui_theme.ini** | Цвета, размеры и параметры UI | +| **ui_bg.png** | Фоновое изображение меню (можно заменить) | +| **imgui.ini** | Состояние окон (локальный, не коммитится) | + +### 📦 Основные модули + +📹 **capture/** — Методы захвата экрана +- DirectX Duplication API — `duplication_api_capture` +- Windows Runtime capture — `winrt_capture` +- [📖 OBS Capture](docs/obs/obs_ru.md) — `obs_capture` + +🧠 **detector/** — Система детекции целей +- DirectML detector — `dml_detector` +- TensorRT detector (NVIDIA) — `trt_detector` +- Color-based detection — `color_detector` + +🎨 **overlay/** — Визуальный интерфейс +- ImGui implementation — `imgui_impl_*` +- 2D/3D rendering — `rendering` + +### ⚡ Методы управления + +- **WIN32 API** — Встроенные API Windows + ⚠️ **Внимание:** Не используйте в играх (моментальный детект) + +- **Makcu/Kmbox/KmboxNet** — Специализированные устройства ввода + ✅ Рекомендуется для игр (низкая задержка) + +--- + +## 📚 Ссылки и ресурсы + +### 📖 Документация + +- 🔗 [TensorRT Docs](https://docs.nvidia.com/deeplearning/tensorrt/) +- 🔗 [OpenCV Docs](https://docs.opencv.org/4.x/d1/dfb/intro.html) +- 🔗 [CUDA 12.8](https://developer.nvidia.com/cuda-12-8-0-download-archive) +- 🔗 [Config](docs\config_ru.md) + +### 🛠️ Использованные библиотеки + +| Библиотека | Назначение | +|-----------|-----------| +| [ImGui](https://github.com/ocornut/imgui) | Пользовательский интерфейс | +| [OpenCV](https://opencv.org/) | Компьютерное зрение | +| [TensorRT](https://developer.nvidia.com/tensorrt) | Инференс нейросетей (NVIDIA) | +| [DirectML](https://github.com/microsoft/DirectML) | GPU computing (универсально) | +| [CppWinRT](https://github.com/microsoft/cppwinrt) | Windows Runtime APIs | +| [GLFW](https://www.glfw.org/) | Управление окнами | +| [nlohmann/JSON](https://github.com/nlohmann/json) | JSON обработка | + +### 💡 Методы и вдохновение + +- 🔗 [WindMouse Algorithm](https://ben.land/post/2021/04/25/windmouse-human-mouse-movement/) — Натуральное движение мыши +- 🔗 [KMBOX](https://www.kmbox.top/) — Интеграция устройств ввода +- 🐍 [RN_AI (Python версия)](https://github.com/ReksarGames/RN_AI) +- 🔀 [Original SunOne Aimbot](https://github.com/SunOner/sunone_aimbot_cpp) — RN_AI_cpp полностью переделана на его основе + +--- +
+ +**Made with ❤️ for the gaming community** + +
diff --git a/sunone_aimbot_cpp.sln b/RN_AI_cpp.sln similarity index 84% rename from sunone_aimbot_cpp.sln rename to RN_AI_cpp.sln index dda446ec..b90fd1eb 100644 --- a/sunone_aimbot_cpp.sln +++ b/RN_AI_cpp.sln @@ -1,9 +1,9 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.13.35825.156 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sunone_aimbot_cpp", "sunone_aimbot_cpp\sunone_aimbot_cpp.vcxproj", "{A27FFC6C-5EC3-43D3-BE46-9925B722B3C8}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RN_AI_cpp", "RN_AI_cpp\RN_AI_cpp.vcxproj", "{A27FFC6C-5EC3-43D3-BE46-9925B722B3C8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -23,3 +23,5 @@ Global SolutionGuid = {4EA9F6E2-D68A-4A8E-B8A2-C04AEB67F9B1} EndGlobalSection EndGlobal + + diff --git a/RN_AI_cpp/.vscode/settings.json b/RN_AI_cpp/.vscode/settings.json new file mode 100644 index 00000000..ea486f65 --- /dev/null +++ b/RN_AI_cpp/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "translation.targetLanguage": "ru", + "translation.api": "google" +} \ No newline at end of file diff --git a/sunone_aimbot_cpp/Package.appxmanifest b/RN_AI_cpp/Package.appxmanifest similarity index 100% rename from sunone_aimbot_cpp/Package.appxmanifest rename to RN_AI_cpp/Package.appxmanifest diff --git a/RN_AI_cpp/README.md b/RN_AI_cpp/README.md new file mode 100644 index 00000000..85ef8cdb --- /dev/null +++ b/RN_AI_cpp/README.md @@ -0,0 +1,53 @@ +# RN_AI_cpp + +Черновой README с фиксацией текущих кастомных изменений проекта. +Позже можно структурировать и оформить финальную документацию. + +## Текущий статус изменений + +### UI/Меню (ImGui Overlay) +- Левый вертикальный навбар с кастомными иконками и изменяемой шириной. +- Поддержка фоновой картинки меню через `ui_bg.png`. +- Темизация через `ui_theme.ini` (цвета, размеры, часть runtime-параметров). +- Добавлен таб `Components` для runtime-настройки UI (дизайн-токены и advanced-параметры). +- В `Overlay`: + - `Overlay Opacity`: `-` / слайдер / `+` (без ручного поля ввода). + - `UI Scale`: `-` / `+` / ручной ввод (без слайдера). + - `Window Width` и `Window Height` для ручного изменения размера окна. +- Убраны лишние проблемные скроллы, которые конфликтовали с основным layout. + +### Resize окна +- Реализованы resize-хэндлы: + - правый край, + - нижний край, + - правый нижний угол. +- Размер окна также можно менять через контролы в `Overlay`. + +### Game Overlay +- Добавлены элементы визуализации поверх игры: + - FPS counter, + - latency, + - детект-боксы. +- Цвета боксов по классам: + - класс `0` всегда зеленый, + - остальным классам цвет назначается автоматически. +- Добавлены настройки размеров текста FPS/latency (через `Components -> Advanced`). + +### Target/Mouse связанные правки +- Расширены визуальные параметры для target-correction в game overlay. +- Актуализированы UI-контролы для target/smart блоков (исправления layout и элементов управления). + +### Makcu/Kmbox интеграция +- Подключена работа с `modules/makcu/include/makcu.h`. +- Исправлены конфликты интеграции и сборки, из-за которых Makcu не подключался корректно. +- Сохранена рабочая логика для текущего пайплайна управления мышью. + +## Важные файлы +- `ui_theme.ini` — текущая тема/настройки визуала меню. +- `ui_bg.png` — фон меню. +- `config.ini` — runtime-конфиг проекта. + +## Технические заметки +- `imgui.ini` обычно локальный файл состояния окон и, как правило, не должен храниться в репозитории. +- `runtime_console.log` — локальный лог-файл, также обычно не коммитится. + diff --git a/sunone_aimbot_cpp/sunone_aimbot_cpp.vcxproj b/RN_AI_cpp/RN_AI_cpp.vcxproj similarity index 87% rename from sunone_aimbot_cpp/sunone_aimbot_cpp.vcxproj rename to RN_AI_cpp/RN_AI_cpp.vcxproj index 8f992f82..a7785e16 100644 --- a/sunone_aimbot_cpp/sunone_aimbot_cpp.vcxproj +++ b/RN_AI_cpp/RN_AI_cpp.vcxproj @@ -39,20 +39,31 @@ + + + + + + + + + + + - + true @@ -90,12 +101,22 @@ + + + + + + + + + + - + true @@ -120,7 +141,7 @@ 16.0 Win32Proj {a27ffc6c-5ec3-43d3-be46-9925b722b3c8} - sunoneaimbotcpp + rn_ai_cpp 10.0.26100.0 @@ -153,12 +174,14 @@ false + $(Platform)\$(Configuration)\$(MSBuildProjectName)\ $(MSBuildProjectDirectory)\modules\serial\include;$(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\imgui;$(MSBuildProjectDirectory)\keyboard;$(MSBuildProjectDirectory)\config;$(MSBuildProjectDirectory)\tensorrt;$(MSBuildProjectDirectory)\detector;$(MSBuildProjectDirectory)\mouse;$(MSBuildProjectDirectory)\overlay;$(MSBuildProjectDirectory)\capture;$(MSBuildProjectDirectory)\modules\opencv\build\install\include;$(WindowsSDK_IncludePath);$(WindowsSDK_IncludePath)\cppwinrt;$(MSBuildProjectDirectory)\modules\TensorRT-10.8.0.43\include;include;$(ProgramW6432)\NVIDIA GPU Computing Toolkit\CUDA\v12.8\include;$(ProgramW6432)\NVIDIA\CUDNN\v9.7\include\12.8;$(IncludePath) $(MSBuildProjectDirectory)\modules\serial\visual_studio\x64\Release;$(MSBuildProjectDirectory)\modules\glfw-3.4.bin.WIN64\lib-vc2019;$(MSBuildProjectDirectory)\modules\opencv\build\install\x64\vc16\lib;$(MSBuildProjectDirectory)\modules\\TensorRT-10.8.0.43\lib;$(ProgramW6432)\NVIDIA GPU Computing Toolkit\CUDA\v12.8\lib\x64;$(ProgramW6432)\NVIDIA\CUDNN\v9.7\lib\12.8;$(LibraryPath) ai false + $(Platform)\$(Configuration)\$(MSBuildProjectName)\ $(MSBuildProjectDirectory)\modules\serial\include;$(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\imgui;$(MSBuildProjectDirectory)\keyboard;$(MSBuildProjectDirectory)\config;$(MSBuildProjectDirectory)\detector;$(MSBuildProjectDirectory)\mouse;$(MSBuildProjectDirectory)\overlay;$(MSBuildProjectDirectory)\capture;$(MSBuildProjectDirectory)\modules\opencv\build\install\include;$(WindowsSDK_IncludePath);$(WindowsSDK_IncludePath)\cppwinrt;include;$(IncludePath) $(MSBuildProjectDirectory)\modules\serial\visual_studio\x64\Release;$(MSBuildProjectDirectory)\modules\glfw-3.4.bin.WIN64\lib-vc2019;$(MSBuildProjectDirectory)\modules\opencv\build\install\x64\vc16\lib;$(LibraryPath) ai @@ -171,7 +194,7 @@ true NDEBUG;_CONSOLE;USE_CUDA;%(PreprocessorDefinitions) true - $(MSBuildProjectDirectory)\modules\glfw-3.4.bin.WIN64\include;$(MSBuildProjectDirectory)\modules\stb;$(MSBuildProjectDirectory)\modules\imgui-1.91.2\backends;$(MSBuildProjectDirectory)\modules\imgui-1.91.2;E:\sunone_aimbot_cpp\sunone_aimbot_cpp\modules\vcpkg-master\installed\x64-windows\include;<VCPKG_ROOT>\installed\x64-windows\include;%(AdditionalIncludeDirectories) + $(MSBuildProjectDirectory)\modules\glfw-3.4.bin.WIN64\include;$(MSBuildProjectDirectory)\modules\stb;$(MSBuildProjectDirectory)\modules\imgui-1.91.2\backends;$(MSBuildProjectDirectory)\modules\imgui-1.91.2;$(MSBuildProjectDirectory)\modules\makcu\include;$(MSBuildProjectDirectory)\modules\vcpkg-master\installed\x64-windows\include;<VCPKG_ROOT>\installed\x64-windows\include;%(AdditionalIncludeDirectories) MultiThreadedDLL NotUsing pch.h @@ -183,7 +206,7 @@ true true opencv_world4100.lib;nvinfer_10.lib;nvonnxparser_10.lib;WindowsApp.lib;d3d11.lib;dxgi.lib;d2d1.lib;cuda.lib;cudart.lib;glfw3_mt.lib;glfw3dll.lib;serial.lib;%(AdditionalDependencies) - E:\sunone_aimbot_cpp\sunone_aimbot_cpp\modules\opencv\build\install\include\opencv2;E:\sunone_aimbot_cpp\sunone_aimbot_cpp\modules\opencv\build\install\x64\vc17\lib;E:\sunone_aimbot_cpp\sunone_aimbot_cpp\modules\opencv\build\install\x64\vc17\bin;E:\sunone_aimbot_cpp\sunone_aimbot_cpp\modules\vcpkg-master\installed\x64-windows\lib;E:\sunone_aimbot_cpp\sunone_aimbot_cpp\modules;%(AdditionalLibraryDirectories) + $(MSBuildProjectDirectory)\modules\opencv\build\install\include\opencv2;$(MSBuildProjectDirectory)\modules\opencv\build\install\x64\vc17\lib;$(MSBuildProjectDirectory)\modules\opencv\build\install\x64\vc17\bin;$(MSBuildProjectDirectory)\modules\vcpkg-master\installed\x64-windows\lib;$(MSBuildProjectDirectory)\modules;%(AdditionalLibraryDirectories) false @@ -200,7 +223,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(MSBuildProjectDirectory)\modules\glfw-3.4.bin.WIN64\include;$(MSBuildProjectDirectory)\modules\stb;$(MSBuildProjectDirectory)\modules\imgui-1.91.2\backends;$(MSBuildProjectDirectory)\modules\imgui-1.91.2;%(AdditionalIncludeDirectories) + $(MSBuildProjectDirectory)\modules\glfw-3.4.bin.WIN64\include;$(MSBuildProjectDirectory)\modules\stb;$(MSBuildProjectDirectory)\modules\imgui-1.91.2\backends;$(MSBuildProjectDirectory)\modules\imgui-1.91.2;$(MSBuildProjectDirectory)\modules\makcu\include;%(AdditionalIncludeDirectories) MultiThreadedDLL NotUsing @@ -213,7 +236,7 @@ true true opencv_world4100.lib;WindowsApp.lib;d3d11.lib;dxgi.lib;d2d1.lib;glfw3_mt.lib;glfw3dll.lib;serial.lib;%(AdditionalDependencies) - E:\sunone_aimbot_cpp\sunone_aimbot_cpp\modules;%(AdditionalLibraryDirectories) + $(MSBuildProjectDirectory)\modules;%(AdditionalLibraryDirectories) false @@ -241,3 +264,7 @@ + + + + diff --git a/sunone_aimbot_cpp/sunone_aimbot_cpp.vcxproj.filters b/RN_AI_cpp/RN_AI_cpp.vcxproj.filters similarity index 78% rename from sunone_aimbot_cpp/sunone_aimbot_cpp.vcxproj.filters rename to RN_AI_cpp/RN_AI_cpp.vcxproj.filters index d15295fa..f4c40106 100644 --- a/sunone_aimbot_cpp/sunone_aimbot_cpp.vcxproj.filters +++ b/RN_AI_cpp/RN_AI_cpp.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -21,22 +21,33 @@ - + + + + + + + + + + + + @@ -72,8 +83,15 @@ - + + + + + + + + @@ -84,6 +102,9 @@ + + + diff --git a/sunone_aimbot_cpp/sunone_aimbot_cpp.vcxproj.user b/RN_AI_cpp/RN_AI_cpp.vcxproj.user similarity index 100% rename from sunone_aimbot_cpp/sunone_aimbot_cpp.vcxproj.user rename to RN_AI_cpp/RN_AI_cpp.vcxproj.user diff --git a/sunone_aimbot_cpp/capture/capture.cpp b/RN_AI_cpp/capture/capture.cpp similarity index 85% rename from sunone_aimbot_cpp/capture/capture.cpp rename to RN_AI_cpp/capture/capture.cpp index 82ce76ee..6935865f 100644 --- a/sunone_aimbot_cpp/capture/capture.cpp +++ b/RN_AI_cpp/capture/capture.cpp @@ -1,4 +1,4 @@ -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #define NOMINMAX #include #include @@ -10,12 +10,13 @@ #include #include #include +#include #include "capture.h" #ifdef USE_CUDA #include "trt_detector.h" #endif -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "keycodes.h" #include "keyboard_listener.h" #include "other_tools.h" @@ -65,9 +66,9 @@ void captureThread(int CAPTURE_WIDTH, int CAPTURE_HEIGHT) std::cout << "[Capture] OpenCV version: " << CV_VERSION << std::endl; IScreenCapture* capturer = nullptr; - if (config.capture_method == "duplication_api") + if (config.capture_method == "duplication_api" || config.capture_method == "obs") { - capturer = new DuplicationAPIScreenCapture(CAPTURE_WIDTH, CAPTURE_HEIGHT); + capturer = new DuplicationAPIScreenCapture(CAPTURE_WIDTH, CAPTURE_HEIGHT, config.monitor_idx); if (config.verbose) std::cout << "[Capture] Using Duplication API" << std::endl; } @@ -91,7 +92,7 @@ void captureThread(int CAPTURE_WIDTH, int CAPTURE_HEIGHT) { config.capture_method = "duplication_api"; config.saveConfig(); - capturer = new DuplicationAPIScreenCapture(CAPTURE_WIDTH, CAPTURE_HEIGHT); + capturer = new DuplicationAPIScreenCapture(CAPTURE_WIDTH, CAPTURE_HEIGHT, config.monitor_idx); std::cout << "[Capture] Unknown capture_method. Set to duplication_api by default." << std::endl; } @@ -137,7 +138,8 @@ void captureThread(int CAPTURE_WIDTH, int CAPTURE_HEIGHT) if (detection_resolution_changed.load() || capture_method_changed.load() || capture_cursor_changed.load() || - capture_borders_changed.load()) + capture_borders_changed.load() || + capture_window_changed.load()) { delete capturer; capturer = nullptr; @@ -145,9 +147,9 @@ void captureThread(int CAPTURE_WIDTH, int CAPTURE_HEIGHT) int newWidth = config.detection_resolution; int newHeight = config.detection_resolution; - if (config.capture_method == "duplication_api") + if (config.capture_method == "duplication_api" || config.capture_method == "obs") { - capturer = new DuplicationAPIScreenCapture(newWidth, newHeight); + capturer = new DuplicationAPIScreenCapture(newWidth, newHeight, config.monitor_idx); if (config.verbose) std::cout << "[Capture] Re-init with Duplication API." << std::endl; } @@ -170,7 +172,7 @@ void captureThread(int CAPTURE_WIDTH, int CAPTURE_HEIGHT) { config.capture_method = "duplication_api"; config.saveConfig(); - capturer = new DuplicationAPIScreenCapture(newWidth, newHeight); + capturer = new DuplicationAPIScreenCapture(newWidth, newHeight, config.monitor_idx); std::cout << "[Capture] Unknown capture_method. Set to duplication_api." << std::endl; } @@ -178,9 +180,36 @@ void captureThread(int CAPTURE_WIDTH, int CAPTURE_HEIGHT) capture_method_changed.store(false); capture_cursor_changed.store(false); capture_borders_changed.store(false); + capture_window_changed.store(false); } cv::Mat screenshotCpu; + bool frameSubmittedToDetector = false; + +#ifdef USE_CUDA + const bool preferGpuCapturePath = + config.backend == "TRT" && + config.capture_method == "duplication_api" && + config.capture_use_cuda && + !config.circle_mask; + if (preferGpuCapturePath) + { + std::lock_guard lock(capturerMutex); + auto* duplicationCapture = dynamic_cast(capturer); + if (duplicationCapture) + { + cv::cuda::GpuMat gpuFrame; + if (duplicationCapture->GetNextFrameGpu(gpuFrame)) + { + trt_detector.processFrameGpu(gpuFrame); + frameSubmittedToDetector = true; + gpuFrame.download(screenshotCpu); + } + } + } +#endif + + if (!frameSubmittedToDetector) { std::lock_guard lock(capturerMutex); screenshotCpu = capturer->GetNextFrameCpu(); @@ -215,7 +244,7 @@ void captureThread(int CAPTURE_WIDTH, int CAPTURE_HEIGHT) dml_detector->processFrame(screenshotCpu); } #ifdef USE_CUDA - else if (config.backend == "TRT") + else if (config.backend == "TRT" && !frameSubmittedToDetector) { trt_detector.processFrame(screenshotCpu); } @@ -288,4 +317,4 @@ void captureThread(int CAPTURE_WIDTH, int CAPTURE_HEIGHT) { std::cerr << "[Capture] Unhandled exception: " << e.what() << std::endl; } -} \ No newline at end of file +} diff --git a/sunone_aimbot_cpp/capture/capture.h b/RN_AI_cpp/capture/capture.h similarity index 82% rename from sunone_aimbot_cpp/capture/capture.h rename to RN_AI_cpp/capture/capture.h index 31696fe6..4ddc1581 100644 --- a/sunone_aimbot_cpp/capture/capture.h +++ b/RN_AI_cpp/capture/capture.h @@ -7,12 +7,16 @@ #include #include #include +#ifdef USE_CUDA +#include +#endif extern std::atomic detection_resolution_changed; extern std::atomic capture_method_changed; extern std::atomic capture_cursor_changed; extern std::atomic capture_borders_changed; extern std::atomic capture_fps_changed; +extern std::atomic capture_window_changed; extern std::deque frameQueue; void captureThread(int CAPTURE_WIDTH, int CAPTURE_HEIGHT); @@ -35,6 +39,9 @@ class IScreenCapture public: virtual ~IScreenCapture() {} virtual cv::Mat GetNextFrameCpu() = 0; +#ifdef USE_CUDA + virtual bool GetNextFrameGpu(cv::cuda::GpuMat&) { return false; } +#endif }; -#endif // CAPTURE_H \ No newline at end of file +#endif // CAPTURE_H diff --git a/sunone_aimbot_cpp/capture/capture.zip b/RN_AI_cpp/capture/capture.zip similarity index 100% rename from sunone_aimbot_cpp/capture/capture.zip rename to RN_AI_cpp/capture/capture.zip diff --git a/sunone_aimbot_cpp/capture/capture_utils.cpp b/RN_AI_cpp/capture/capture_utils.cpp similarity index 100% rename from sunone_aimbot_cpp/capture/capture_utils.cpp rename to RN_AI_cpp/capture/capture_utils.cpp diff --git a/sunone_aimbot_cpp/capture/capture_utils.h b/RN_AI_cpp/capture/capture_utils.h similarity index 100% rename from sunone_aimbot_cpp/capture/capture_utils.h rename to RN_AI_cpp/capture/capture_utils.h diff --git a/sunone_aimbot_cpp/capture/duplication_api_capture.cpp b/RN_AI_cpp/capture/duplication_api_capture.cpp similarity index 57% rename from sunone_aimbot_cpp/capture/duplication_api_capture.cpp rename to RN_AI_cpp/capture/duplication_api_capture.cpp index 086c35cd..94d496b9 100644 --- a/sunone_aimbot_cpp/capture/duplication_api_capture.cpp +++ b/RN_AI_cpp/capture/duplication_api_capture.cpp @@ -1,12 +1,18 @@ #define WIN32_LEAN_AND_MEAN +#define NOMINMAX #define _WINSOCKAPI_ #include #include +#include +#include + +#ifdef USE_CUDA +#include +#include +#endif #include "duplication_api_capture.h" -#include "sunone_aimbot_cpp.h" -#include "config.h" -#include "other_tools.h" +#include "rn_ai_cpp.h" #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "dxgi.lib") @@ -24,6 +30,7 @@ inline void SafeRelease(T** ppInterface) struct FrameContext { ID3D11Texture2D* texture = nullptr; + bool hasAcquiredFrame = false; }; class DDAManager @@ -34,6 +41,7 @@ class DDAManager , m_context(nullptr) , m_duplication(nullptr) , m_output1(nullptr) + , m_frameAcquired(false) { ZeroMemory(&m_duplDesc, sizeof(m_duplDesc)); } @@ -164,12 +172,16 @@ class DDAManager HRESULT AcquireFrame(FrameContext& frameCtx, UINT timeout = 100) { + frameCtx.texture = nullptr; + frameCtx.hasAcquiredFrame = false; if (!m_duplication) return E_FAIL; DXGI_OUTDUPL_FRAME_INFO frameInfo{}; IDXGIResource* resource = nullptr; HRESULT hr = m_duplication->AcquireNextFrame(timeout, &frameInfo, &resource); if (FAILED(hr)) return hr; + frameCtx.hasAcquiredFrame = true; + m_frameAcquired = true; if (resource) { @@ -181,15 +193,19 @@ class DDAManager void ReleaseFrame() { - if (m_duplication) + if (!m_duplication || !m_frameAcquired) + return; + if (m_duplication) { m_duplication->ReleaseFrame(); + m_frameAcquired = false; + } } void Release() { if (m_duplication) { - m_duplication->ReleaseFrame(); + ReleaseFrame(); m_duplication->Release(); m_duplication = nullptr; } @@ -204,9 +220,10 @@ class DDAManager IDXGIOutputDuplication* m_duplication; IDXGIOutput1* m_output1; DXGI_OUTDUPL_DESC m_duplDesc; + bool m_frameAcquired; }; -DuplicationAPIScreenCapture::DuplicationAPIScreenCapture(int desiredWidth, int desiredHeight) +DuplicationAPIScreenCapture::DuplicationAPIScreenCapture(int desiredWidth, int desiredHeight, int monitorIndex) : d3dDevice(nullptr) , d3dContext(nullptr) , deskDupl(nullptr) @@ -221,7 +238,7 @@ DuplicationAPIScreenCapture::DuplicationAPIScreenCapture(int desiredWidth, int d m_ddaManager = std::make_unique(); HRESULT hr = m_ddaManager->Initialize( - config.monitor_idx, + monitorIndex, regionWidth, regionHeight, screenWidth, @@ -235,11 +252,20 @@ DuplicationAPIScreenCapture::DuplicationAPIScreenCapture(int desiredWidth, int d return; } + regionWidth = std::clamp(regionWidth, 1, std::max(1, screenWidth)); + regionHeight = std::clamp(regionHeight, 1, std::max(1, screenHeight)); + createStagingTextureCPU(); +#ifdef USE_CUDA + createCudaInteropTexture(); +#endif } DuplicationAPIScreenCapture::~DuplicationAPIScreenCapture() { +#ifdef USE_CUDA + releaseCudaInteropTexture(); +#endif if (m_ddaManager) { m_ddaManager->Release(); @@ -267,32 +293,38 @@ cv::Mat DuplicationAPIScreenCapture::GetNextFrameCpu() { return cv::Mat(); } - else if (hr == DXGI_ERROR_ACCESS_LOST || hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DEVICE_REMOVED) + else if (hr == DXGI_ERROR_ACCESS_LOST || hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_INVALID_CALL) { capture_method_changed.store(true); - m_ddaManager->ReleaseFrame(); return cv::Mat(); } else if (FAILED(hr)) { std::cerr << "[DuplicationAPIScreenCapture] AcquireNextFrame (CPU) failed hr=0x" << std::hex << hr << std::endl; - m_ddaManager->ReleaseFrame(); + if (frameCtx.hasAcquiredFrame) + m_ddaManager->ReleaseFrame(); return cv::Mat(); } if (!frameCtx.texture) { - m_ddaManager->ReleaseFrame(); + if (frameCtx.hasAcquiredFrame) + m_ddaManager->ReleaseFrame(); return cv::Mat(); } + const int copyWidth = std::min(regionWidth, std::max(1, screenWidth)); + const int copyHeight = std::min(regionHeight, std::max(1, screenHeight)); + const int left = std::max(0, (screenWidth - copyWidth) / 2); + const int top = std::max(0, (screenHeight - copyHeight) / 2); + D3D11_BOX sourceRegion; - sourceRegion.left = (screenWidth - regionWidth) / 2; - sourceRegion.top = (screenHeight - regionHeight) / 2; + sourceRegion.left = left; + sourceRegion.top = top; sourceRegion.front = 0; - sourceRegion.right = sourceRegion.left + regionWidth; - sourceRegion.bottom = sourceRegion.top + regionHeight; + sourceRegion.right = sourceRegion.left + copyWidth; + sourceRegion.bottom = sourceRegion.top + copyHeight; sourceRegion.back = 1; d3dContext->CopySubresourceRegion( @@ -312,6 +344,8 @@ cv::Mat DuplicationAPIScreenCapture::GetNextFrameCpu() if (FAILED(hrMap)) { std::cerr << "[DDA] Map stagingTextureCPU failed hr=" << std::hex << hrMap << std::endl; + if (hrMap == DXGI_ERROR_DEVICE_REMOVED || hrMap == DXGI_ERROR_DEVICE_RESET) + capture_method_changed.store(true); return cv::Mat(); } @@ -327,9 +361,156 @@ cv::Mat DuplicationAPIScreenCapture::GetNextFrameCpu() return cpuFrame; } +#ifdef USE_CUDA +bool DuplicationAPIScreenCapture::GetNextFrameGpu(cv::cuda::GpuMat& gpuFrameBgra) +{ + if (!m_ddaManager || !m_ddaManager->m_duplication || !interopTextureGPU || !cudaInteropResource || !cudaInteropReady) + return false; + + FrameContext frameCtx; + HRESULT hr = m_ddaManager->AcquireFrame(frameCtx, 5); + if (hr == DXGI_ERROR_WAIT_TIMEOUT) + return false; + if (hr == DXGI_ERROR_ACCESS_LOST || hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_INVALID_CALL) + { + capture_method_changed.store(true); + return false; + } + if (FAILED(hr)) + { + std::cerr << "[DuplicationAPIScreenCapture] AcquireNextFrame (GPU) failed hr=0x" << std::hex << hr << std::endl; + if (frameCtx.hasAcquiredFrame) + m_ddaManager->ReleaseFrame(); + return false; + } + if (!frameCtx.texture) + { + if (frameCtx.hasAcquiredFrame) + m_ddaManager->ReleaseFrame(); + return false; + } + + const int copyWidth = std::min(regionWidth, std::max(1, screenWidth)); + const int copyHeight = std::min(regionHeight, std::max(1, screenHeight)); + const int left = std::max(0, (screenWidth - copyWidth) / 2); + const int top = std::max(0, (screenHeight - copyHeight) / 2); + + D3D11_BOX sourceRegion{}; + sourceRegion.left = left; + sourceRegion.top = top; + sourceRegion.front = 0; + sourceRegion.right = left + copyWidth; + sourceRegion.bottom = top + copyHeight; + sourceRegion.back = 1; + + d3dContext->CopySubresourceRegion(interopTextureGPU, 0, 0, 0, 0, frameCtx.texture, 0, &sourceRegion); + m_ddaManager->ReleaseFrame(); + frameCtx.texture->Release(); + + cudaError_t cuErr = cudaGraphicsMapResources(1, &cudaInteropResource, 0); + if (cuErr != cudaSuccess) + { + std::cerr << "[DDA] cudaGraphicsMapResources failed: " << cudaGetErrorString(cuErr) << std::endl; + cudaInteropReady = false; + return false; + } + + cudaArray_t mappedArray = nullptr; + cuErr = cudaGraphicsSubResourceGetMappedArray(&mappedArray, cudaInteropResource, 0, 0); + if (cuErr != cudaSuccess) + { + std::cerr << "[DDA] cudaGraphicsSubResourceGetMappedArray failed: " << cudaGetErrorString(cuErr) << std::endl; + cudaGraphicsUnmapResources(1, &cudaInteropResource, 0); + cudaInteropReady = false; + return false; + } + + gpuFrameBgra.create(regionHeight, regionWidth, CV_8UC4); + cuErr = cudaMemcpy2DFromArray( + gpuFrameBgra.ptr(), + gpuFrameBgra.step, + mappedArray, + 0, + 0, + static_cast(regionWidth) * 4, + static_cast(regionHeight), + cudaMemcpyDeviceToDevice); + + cudaError_t unmapErr = cudaGraphicsUnmapResources(1, &cudaInteropResource, 0); + if (unmapErr != cudaSuccess) + { + std::cerr << "[DDA] cudaGraphicsUnmapResources failed: " << cudaGetErrorString(unmapErr) << std::endl; + cudaInteropReady = false; + } + + if (cuErr != cudaSuccess) + { + std::cerr << "[DDA] cudaMemcpy2DFromArray failed: " << cudaGetErrorString(cuErr) << std::endl; + cudaInteropReady = false; + return false; + } + + return true; +} + +bool DuplicationAPIScreenCapture::createCudaInteropTexture() +{ + if (!d3dDevice) + return false; + + releaseCudaInteropTexture(); + + D3D11_TEXTURE2D_DESC desc{}; + desc.Width = regionWidth; + desc.Height = regionHeight; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT hr = d3dDevice->CreateTexture2D(&desc, nullptr, &interopTextureGPU); + if (FAILED(hr)) + { + std::cerr << "[DDA] CreateTexture2D(interop) failed hr=" << std::hex << hr << std::endl; + return false; + } + + cudaError_t cuErr = cudaGraphicsD3D11RegisterResource(&cudaInteropResource, interopTextureGPU, cudaGraphicsRegisterFlagsNone); + if (cuErr != cudaSuccess) + { + std::cerr << "[DDA] cudaGraphicsD3D11RegisterResource failed: " << cudaGetErrorString(cuErr) << std::endl; + SafeRelease(&interopTextureGPU); + cudaInteropResource = nullptr; + cudaInteropReady = false; + return false; + } + + cudaInteropReady = true; + return true; +} + +void DuplicationAPIScreenCapture::releaseCudaInteropTexture() +{ + if (cudaInteropResource) + { + cudaError_t cuErr = cudaGraphicsUnregisterResource(cudaInteropResource); + if (cuErr != cudaSuccess) + std::cerr << "[DDA] cudaGraphicsUnregisterResource failed: " << cudaGetErrorString(cuErr) << std::endl; + cudaInteropResource = nullptr; + } + SafeRelease(&interopTextureGPU); + cudaInteropReady = false; +} +#endif + bool DuplicationAPIScreenCapture::createStagingTextureCPU() { if (!d3dDevice) return false; + SafeRelease(&stagingTextureCPU); D3D11_TEXTURE2D_DESC desc{}; desc.Width = regionWidth; @@ -350,4 +531,4 @@ bool DuplicationAPIScreenCapture::createStagingTextureCPU() return false; } return true; -} \ No newline at end of file +} diff --git a/sunone_aimbot_cpp/capture/duplication_api_capture.h b/RN_AI_cpp/capture/duplication_api_capture.h similarity index 65% rename from sunone_aimbot_cpp/capture/duplication_api_capture.h rename to RN_AI_cpp/capture/duplication_api_capture.h index 7e1aa16d..7c9d2741 100644 --- a/sunone_aimbot_cpp/capture/duplication_api_capture.h +++ b/RN_AI_cpp/capture/duplication_api_capture.h @@ -5,6 +5,11 @@ #include #include #include +#ifdef USE_CUDA +#include +#include +struct cudaGraphicsResource; +#endif #include "capture.h" @@ -13,10 +18,13 @@ class DDAManager; class DuplicationAPIScreenCapture : public IScreenCapture { public: - DuplicationAPIScreenCapture(int desiredWidth, int desiredHeight); + DuplicationAPIScreenCapture(int desiredWidth, int desiredHeight, int monitorIndex); ~DuplicationAPIScreenCapture(); cv::Mat GetNextFrameCpu() override; +#ifdef USE_CUDA + bool GetNextFrameGpu(cv::cuda::GpuMat& gpuFrameBgra) override; +#endif private: std::unique_ptr m_ddaManager; @@ -29,6 +37,11 @@ class DuplicationAPIScreenCapture : public IScreenCapture ID3D11Texture2D* sharedTexture = nullptr; ID3D11Texture2D* stagingTextureCPU = nullptr; +#ifdef USE_CUDA + ID3D11Texture2D* interopTextureGPU = nullptr; + cudaGraphicsResource* cudaInteropResource = nullptr; + bool cudaInteropReady = false; +#endif int screenWidth = 0; int screenHeight = 0; @@ -36,6 +49,10 @@ class DuplicationAPIScreenCapture : public IScreenCapture int regionHeight = 0; bool createStagingTextureCPU(); +#ifdef USE_CUDA + bool createCudaInteropTexture(); + void releaseCudaInteropTexture(); +#endif }; #endif // DUPLICATION_API_CAPTURE_H diff --git a/sunone_aimbot_cpp/capture/udp_capture.cpp b/RN_AI_cpp/capture/udp_capture.cpp similarity index 100% rename from sunone_aimbot_cpp/capture/udp_capture.cpp rename to RN_AI_cpp/capture/udp_capture.cpp diff --git a/sunone_aimbot_cpp/capture/udp_capture.h b/RN_AI_cpp/capture/udp_capture.h similarity index 100% rename from sunone_aimbot_cpp/capture/udp_capture.h rename to RN_AI_cpp/capture/udp_capture.h diff --git a/sunone_aimbot_cpp/capture/virtual_camera.cpp b/RN_AI_cpp/capture/virtual_camera.cpp similarity index 100% rename from sunone_aimbot_cpp/capture/virtual_camera.cpp rename to RN_AI_cpp/capture/virtual_camera.cpp diff --git a/sunone_aimbot_cpp/capture/virtual_camera.h b/RN_AI_cpp/capture/virtual_camera.h similarity index 100% rename from sunone_aimbot_cpp/capture/virtual_camera.h rename to RN_AI_cpp/capture/virtual_camera.h diff --git a/sunone_aimbot_cpp/capture/winrt_capture.cpp b/RN_AI_cpp/capture/winrt_capture.cpp similarity index 99% rename from sunone_aimbot_cpp/capture/winrt_capture.cpp rename to RN_AI_cpp/capture/winrt_capture.cpp index 19f15610..b895c0d2 100644 --- a/sunone_aimbot_cpp/capture/winrt_capture.cpp +++ b/RN_AI_cpp/capture/winrt_capture.cpp @@ -4,7 +4,7 @@ #include #include "winrt_capture.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "config.h" #include "other_tools.h" diff --git a/sunone_aimbot_cpp/capture/winrt_capture.h b/RN_AI_cpp/capture/winrt_capture.h similarity index 100% rename from sunone_aimbot_cpp/capture/winrt_capture.h rename to RN_AI_cpp/capture/winrt_capture.h diff --git a/RN_AI_cpp/config.ini b/RN_AI_cpp/config.ini new file mode 100644 index 00000000..7b8a7ca6 --- /dev/null +++ b/RN_AI_cpp/config.ini @@ -0,0 +1,232 @@ +# An explanation of the options can be found at: +# https://github.com/RN-AI/RN_AI_cpp + +# Capture +capture_method = duplication_api +detection_resolution = 640 +capture_fps = 400 +monitor_idx = 0 +circle_mask = false +capture_borders = true +capture_cursor = true +virtual_camera_name = None +virtual_camera_width = 1920 +virtual_camera_heigth = 1080 + +# Target +disable_headshot = false +body_y_offset = 0.15 +head_y_offset = 0.05 +ignore_third_person = false +shooting_range_targets = false +focusTarget = false +auto_aim = false +target_lock_enabled = true +target_lock_distance = 40.0 +target_lock_reacquire_time = 0.10 +smart_target_lock = true +target_reference_class = 0 +target_lock_fallback_class = -1 +target_switch_delay = 54 +aim_bot_scope = 226.3 +aim_bot_position = 0.50 +aim_bot_position2 = 0.50 +allowed_classes = 0-7 +class_priority_order = +distance_scoring_weight = 1.00 +center_scoring_weight = 1.00 +size_scoring_weight = 1.00 +aim_weight_tiebreak_ratio = 0.10 +small_target_enhancement_enabled = false +small_target_boost_factor = 0.10 +small_target_threshold = 0.02 +small_target_medium_threshold = 0.05 +small_target_medium_boost = 1.50 +small_target_smooth_enabled = true +small_target_smooth_frames = 2 + +# Mouse move +fovX = 106 +fovY = 74 +minSpeedMultiplier = 0.50 +maxSpeedMultiplier = 0.70 +smoothness = 1 +use_smoothing = true +tracking_smoothing = true +use_kalman = false + +kalman_process_noise = 0.98 +kalman_measurement_noise = 0.40 +kalman_speed_multiplier_x = 1.00 +kalman_speed_multiplier_y = 1.00 +resetThreshold = 5.00 + +predictionInterval = 0.01 +prediction_mode = 0 +prediction_kalman_lead_ms = 0.00 +prediction_kalman_max_lead_ms = 0.00 +prediction_velocity_smoothing = 0.40 +prediction_velocity_scale = 1.00 +prediction_kalman_process_noise = 0.01 +prediction_kalman_measurement_noise = 0.10 +prediction_use_future_for_aim = false +prediction_futurePositions = 20 +draw_futurePositions = true +camera_compensation_enabled = false +camera_compensation_max_shift = 50.00 +camera_compensation_strength = 1.00 +snapRadius = 1.50 +nearRadius = 24.00 +speedCurveExponent = 3.00 +snapBoostFactor = 1.15 +easynorecoil = false +easynorecoilstrength = 0.0 +# WIN32, ARDUINO, MAKCU, KMBOX_B, KMBOX_NET +input_method = WIN32 + +# Wind mouse +wind_mouse_enabled = false +wind_G = 18.0 +wind_W = 15.0 +wind_M = 10.0 +wind_D = 8.0 + +# Makcu +makcu_baudrate = 4000000 +makcu_port = COM14 + +# Kmbox_B +kmbox_baudrate = 115200 +kmbox_port = COM0 + +# Mouse shooting +auto_shoot = false +triggerbot = true +triggerbot_reaction_ms = 0 +triggerbot_interval = 0.00 +bScope_multiplier = 1.0 +triggerbot_bScope_multiplier = 1.0 + +# AI +backend = TRT +dml_device_id = 0 +ai_model = sunxds_0.5.6.engine +confidence_threshold = 0.10 +nms_threshold = 0.50 +adaptive_nms = true +max_detections = 0 +postprocess = yolo10 +batch_size = 8 +export_enable_fp8 = false +export_enable_fp16 = true +fixed_input_size = false + +# CUDA +use_cuda_graph = false +use_pinned_memory = false +capture_use_cuda = true + +# Buttons +button_targeting = RightMouseButton +button_shoot = LeftMouseButton +button_triggerbot = X2MouseButton +button_disable_headshot = M +button_exit = F2 +button_pause = F3 +button_reload_config = F4 +button_open_overlay = Home +enable_arrows_settings = false + +# Overlay +overlay_opacity = 255 +overlay_snow_theme = true +overlay_ui_scale = 2.13 +game_overlay_enabled = false +game_overlay_max_fps = 57 +game_overlay_draw_boxes = true +game_overlay_draw_future = true +game_overlay_draw_wind_tail = true +game_overlay_draw_frame = true +game_overlay_show_target_correction = true +game_overlay_show_fps_counter = true +game_overlay_show_latency = true +game_overlay_box_a = 255 +game_overlay_box_r = 0 +game_overlay_box_g = 255 +game_overlay_box_b = 0 +game_overlay_frame_a = 180 +game_overlay_frame_r = 255 +game_overlay_frame_g = 255 +game_overlay_frame_b = 255 +game_overlay_box_thickness = 4.70 +game_overlay_frame_thickness = 2.50 +game_overlay_future_point_radius = 5.00 +game_overlay_future_alpha_falloff = 1.00 +game_overlay_icon_enabled = true +game_overlay_icon_path = icon.png +game_overlay_icon_width = 64 +game_overlay_icon_height = 64 +game_overlay_icon_offset_x = 0.00 +game_overlay_icon_offset_y = 0.00 +game_overlay_icon_anchor = center +game_overlay_icon_class = -1 +aim_sim_enabled = true +aim_sim_x = 24 +aim_sim_y = 24 +aim_sim_width = 560 +aim_sim_height = 360 +aim_sim_fps_min = 90 +aim_sim_fps_max = 120 +aim_sim_fps_jitter = 0.15 +aim_sim_capture_delay_ms = 8.62 +aim_sim_inference_delay_ms = 2.40 +aim_sim_use_live_inference = true +aim_sim_input_delay_ms = 2.00 +aim_sim_extra_delay_ms = 0.73 +aim_sim_target_max_speed = 560.00 +aim_sim_target_accel = 1850.00 +aim_sim_target_stop_chance = 0.25 +aim_sim_show_observed = true +aim_sim_show_history = true + +# OBS +is_obs = false +obs_ip = 0.0.0.0 +obs_port = 4455 +obs_fps = 240 + +# Color detection +color_erode_iter = 1 +color_dilate_iter = 2 +color_min_area = 50 +color_target = Yellow +tinyArea = 2 +isOnlyTop = 1 +scanError = 0.10 + +# Debug +show_window = true +show_fps = false +screenshot_button = None +screenshot_delay = 500 +verbose = true + +# Active game profile +active_game = dwa + +[Colors] +Purple = 220,100,195,255,195,255 +Yellow = 30,125,150,30,255,255 +Yellow2 = 20,100,120,35,255,255 + +[Games] +dwa = 10.00,0.02,0.02 +UNIFIED = 1.00,0.02,0.02 + +[ClassAim] +0 = 0.10,0.10 + +[ClassNames] +0 = class_player +7 = class_head + diff --git a/sunone_aimbot_cpp/config/config.cpp b/RN_AI_cpp/config/config.cpp similarity index 50% rename from sunone_aimbot_cpp/config/config.cpp rename to RN_AI_cpp/config/config.cpp index 7237bb96..a03fb7ec 100644 --- a/sunone_aimbot_cpp/config/config.cpp +++ b/RN_AI_cpp/config/config.cpp @@ -1,4 +1,4 @@ -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #define _WINSOCKAPI_ #include #include @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "config.h" #include "modules/SimpleIni.h" @@ -69,6 +71,28 @@ bool Config::loadConfig(const std::string& filename) target_lock_enabled = false; target_lock_distance = 100.0f; target_lock_reacquire_time = 0.30f; + smart_target_lock = true; + target_reference_class = 0; + target_lock_fallback_class = -1; + target_switch_delay = 0; + aim_bot_scope = 160.0f; + aim_bot_position = 0.5f; + aim_bot_position2 = 0.5f; + allowed_classes = ""; + class_priority_order = ""; + distance_scoring_weight = 1.0f; + center_scoring_weight = 1.0f; + size_scoring_weight = 1.0f; + aim_weight_tiebreak_ratio = 0.1f; + small_target_enhancement_enabled = true; + small_target_boost_factor = 0.1f; + small_target_threshold = 0.02f; + small_target_medium_threshold = 0.05f; + small_target_medium_boost = 1.5f; + small_target_smooth_enabled = true; + small_target_smooth_frames = 2; + class_aim_positions.clear(); + custom_class_names.clear(); // Mouse fovX = 106; @@ -78,6 +102,7 @@ bool Config::loadConfig(const std::string& filename) smoothness = 100; use_smoothing = true; + tracking_smoothing = false; use_kalman = false; kalman_process_noise = 0.01f; @@ -87,9 +112,21 @@ bool Config::loadConfig(const std::string& filename) resetThreshold = 5; predictionInterval = 0.01f; + prediction_mode = 0; + prediction_kalman_lead_ms = 0.0f; + prediction_kalman_max_lead_ms = 0.0f; + prediction_velocity_smoothing = 0.4f; + prediction_velocity_scale = 1.0f; + prediction_kalman_process_noise = 0.01f; + prediction_kalman_measurement_noise = 0.10f; + prediction_use_future_for_aim = false; prediction_futurePositions = 20; draw_futurePositions = true; + camera_compensation_enabled = false; + camera_compensation_max_shift = 50.0f; + camera_compensation_strength = 1.0f; + snapRadius = 1.5f; nearRadius = 25.0f; speedCurveExponent = 3.0f; @@ -105,6 +142,9 @@ bool Config::loadConfig(const std::string& filename) wind_W = 15.0f; wind_M = 10.0f; wind_D = 8.0f; + // Makcu + makcu_baudrate = 4000000; + makcu_port = "COM1"; // kmbox_B kmbox_b_baudrate = 115200; @@ -113,9 +153,7 @@ bool Config::loadConfig(const std::string& filename) // Mouse shooting auto_shoot = false; triggerbot = false; - triggerbot_interval = 0.0; - triggerbot_predict_ms = 0.0; - triggerbot_predict_alpha = 0.5; + triggerbot_reaction_ms = 0; bScope_multiplier = 1.0f; triggerbot_bScope_multiplier = 1.0f; @@ -150,6 +188,7 @@ bool Config::loadConfig(const std::string& filename) #ifdef USE_CUDA use_cuda_graph = false; use_pinned_memory = false; + capture_use_cuda = true; #endif // Buttons @@ -167,6 +206,59 @@ bool Config::loadConfig(const std::string& filename) overlay_opacity = 225; overlay_snow_theme = true; overlay_ui_scale = 1.0f; + game_overlay_enabled = false; + game_overlay_max_fps = 0; + game_overlay_draw_boxes = true; + game_overlay_draw_future = true; + game_overlay_draw_wind_tail = true; + game_overlay_draw_frame = true; + game_overlay_show_target_correction = true; + game_overlay_show_fps_counter = true; + game_overlay_show_latency = true; + game_overlay_box_a = 255; + game_overlay_box_r = 0; + game_overlay_box_g = 255; + game_overlay_box_b = 0; + game_overlay_frame_a = 180; + game_overlay_frame_r = 255; + game_overlay_frame_g = 255; + game_overlay_frame_b = 255; + game_overlay_box_thickness = 2.0f; + game_overlay_frame_thickness = 1.5f; + game_overlay_future_point_radius = 5.0f; + game_overlay_future_alpha_falloff = 1.0f; + game_overlay_icon_enabled = false; + game_overlay_icon_path = "icon.png"; + game_overlay_icon_width = 64; + game_overlay_icon_height = 64; + game_overlay_icon_offset_x = 0.0f; + game_overlay_icon_offset_y = 0.0f; + game_overlay_icon_anchor = "center"; + game_overlay_icon_class = -1; + aim_sim_enabled = false; + aim_sim_x = 24; + aim_sim_y = 24; + aim_sim_width = 560; + aim_sim_height = 360; + aim_sim_fps_min = 90; + aim_sim_fps_max = 120; + aim_sim_fps_jitter = 0.15f; + aim_sim_capture_delay_ms = 6.0f; + aim_sim_inference_delay_ms = 12.0f; + aim_sim_use_live_inference = true; + aim_sim_input_delay_ms = 2.0f; + aim_sim_extra_delay_ms = 2.0f; + aim_sim_target_max_speed = 560.0f; + aim_sim_target_accel = 1850.0f; + aim_sim_target_stop_chance = 0.25f; + aim_sim_show_observed = true; + aim_sim_show_history = true; + + // OBS + is_obs = false; + obs_ip = "0.0.0.0"; + obs_port = 4455; + obs_fps = 240; // Custom classes class_player = 0; @@ -189,7 +281,7 @@ bool Config::loadConfig(const std::string& filename) isOnlyTop = true; scanError = 0.1f; - // Заполняем дефолтные диапазоны HSV + // ????????? ????????? ????????? HSV color_ranges.clear(); // Yellow @@ -215,6 +307,7 @@ bool Config::loadConfig(const std::string& filename) // Debug show_window = true; + show_fps = false; screenshot_button = splitString("None"); screenshot_delay = 500; verbose = false; @@ -232,25 +325,56 @@ bool Config::loadConfig(const std::string& filename) return false; } + auto get_raw_value_compat = [&](const char* key) -> const char* + { + const char* val = ini.GetValue("", key, nullptr); + if (val == nullptr) + val = ini.GetValue("ClassNames", key, nullptr); + if (val == nullptr) + val = ini.GetValue("Colors", key, nullptr); + return val; + }; + auto get_string = [&](const char* key, const std::string& defval) { - const char* val = ini.GetValue("", key, defval.c_str()); + const char* val = get_raw_value_compat(key); return val ? std::string(val) : defval; }; auto get_bool = [&](const char* key, bool defval) { - return ini.GetBoolValue("", key, defval); + std::string value = get_string(key, defval ? "true" : "false"); + std::transform(value.begin(), value.end(), value.begin(), + [](unsigned char c) { return static_cast(std::tolower(c)); }); + if (value == "1" || value == "true" || value == "yes" || value == "on") + return true; + if (value == "0" || value == "false" || value == "no" || value == "off") + return false; + return defval; }; auto get_long = [&](const char* key, long defval) { - return (int)ini.GetLongValue("", key, defval); + try + { + return static_cast(std::stol(get_string(key, std::to_string(defval)))); + } + catch (...) + { + return static_cast(defval); + } }; auto get_double = [&](const char* key, double defval) { - return ini.GetDoubleValue("", key, defval); + try + { + return std::stod(get_string(key, std::to_string(defval))); + } + catch (...) + { + return defval; + } }; game_profiles.clear(); @@ -328,6 +452,75 @@ bool Config::loadConfig(const std::string& filename) target_lock_enabled = get_bool("target_lock_enabled", false); target_lock_distance = static_cast(get_double("target_lock_distance", 100.0)); target_lock_reacquire_time = static_cast(get_double("target_lock_reacquire_time", 0.30)); + smart_target_lock = get_bool("smart_target_lock", true); + target_reference_class = get_long("target_reference_class", 0); + target_lock_fallback_class = get_long("target_lock_fallback_class", -1); + target_switch_delay = get_long("target_switch_delay", 0); + aim_bot_scope = static_cast(get_double("aim_bot_scope", 160.0)); + if (aim_bot_scope < 0.0f) + aim_bot_scope = 0.0f; + aim_bot_position = static_cast(get_double("aim_bot_position", 0.5)); + aim_bot_position2 = static_cast(get_double("aim_bot_position2", 0.5)); + allowed_classes = get_string("allowed_classes", ""); + class_priority_order = get_string("class_priority_order", ""); + distance_scoring_weight = static_cast(get_double("distance_scoring_weight", 1.0)); + center_scoring_weight = static_cast(get_double("center_scoring_weight", 1.0)); + size_scoring_weight = static_cast(get_double("size_scoring_weight", 1.0)); + aim_weight_tiebreak_ratio = static_cast(get_double("aim_weight_tiebreak_ratio", 0.1)); + small_target_enhancement_enabled = get_bool("small_target_enhancement_enabled", true); + small_target_boost_factor = static_cast(get_double("small_target_boost_factor", 0.1)); + small_target_threshold = static_cast(get_double("small_target_threshold", 0.02)); + small_target_medium_threshold = static_cast(get_double("small_target_medium_threshold", 0.05)); + small_target_medium_boost = static_cast(get_double("small_target_medium_boost", 1.5)); + small_target_smooth_enabled = get_bool("small_target_smooth_enabled", true); + small_target_smooth_frames = get_long("small_target_smooth_frames", 2); + if (small_target_smooth_frames < 1) + small_target_smooth_frames = 1; + + class_aim_positions.clear(); + CSimpleIniA::TNamesDepend classAimKeys; + ini.GetAllKeys("ClassAim", classAimKeys); + for (const auto& k : classAimKeys) + { + std::string key = k.pItem; + if (key.empty() || !std::all_of(key.begin(), key.end(), + [](unsigned char c) { return std::isdigit(c) != 0; })) + continue; + std::string val = ini.GetValue("ClassAim", key.c_str(), ""); + auto parts = splitString(val, ','); + if (parts.size() < 2) + continue; + try + { + int class_id = std::stoi(key); + float pos1 = std::stof(parts[0]); + float pos2 = std::stof(parts[1]); + class_aim_positions[class_id] = { pos1, pos2 }; + } + catch (...) + { + std::cerr << "[Config] Invalid ClassAim entry: " << key << " = " << val << std::endl; + } + } + + custom_class_names.clear(); + CSimpleIniA::TNamesDepend classNameKeys; + ini.GetAllKeys("ClassNames", classNameKeys); + for (const auto& k : classNameKeys) + { + std::string key = k.pItem; + if (key.empty() || !std::all_of(key.begin(), key.end(), + [](unsigned char c) { return std::isdigit(c) != 0; })) + continue; + std::string val = ini.GetValue("ClassNames", key.c_str(), ""); + try + { + int class_id = std::stoi(key); + if (!val.empty()) + custom_class_names[class_id] = val; + } + catch (...) {} + } // Mouse fovX = get_long("fovX", 106); @@ -337,6 +530,7 @@ bool Config::loadConfig(const std::string& filename) smoothness = get_long("smoothness", 100); use_smoothing = get_bool("use_smoothing", true); + tracking_smoothing = get_bool("tracking_smoothing", false); use_kalman = get_bool("use_kalman", false); kalman_process_noise = (float)get_double("kalman_process_noise", 0.01); @@ -346,8 +540,22 @@ bool Config::loadConfig(const std::string& filename) resetThreshold = (float)get_double("resetThreshold", 5); predictionInterval = (float)get_double("predictionInterval", 0.01); + prediction_mode = get_long("prediction_mode", 0); + if (prediction_mode < 0) prediction_mode = 0; + if (prediction_mode > 2) prediction_mode = 2; + prediction_kalman_lead_ms = (float)get_double("prediction_kalman_lead_ms", 0.0); + prediction_kalman_max_lead_ms = (float)get_double("prediction_kalman_max_lead_ms", 0.0); + prediction_velocity_smoothing = (float)get_double("prediction_velocity_smoothing", 0.4); + prediction_velocity_scale = (float)get_double("prediction_velocity_scale", 1.0); + prediction_kalman_process_noise = (float)get_double("prediction_kalman_process_noise", 0.01); + prediction_kalman_measurement_noise = (float)get_double("prediction_kalman_measurement_noise", 0.10); + prediction_use_future_for_aim = get_bool("prediction_use_future_for_aim", false); prediction_futurePositions = get_long("prediction_futurePositions", 20); draw_futurePositions = get_bool("draw_futurePositions", true); + + camera_compensation_enabled = get_bool("camera_compensation_enabled", false); + camera_compensation_max_shift = (float)get_double("camera_compensation_max_shift", 50.0); + camera_compensation_strength = (float)get_double("camera_compensation_strength", 1.0); snapRadius = (float)get_double("snapRadius", 1.5); nearRadius = (float)get_double("nearRadius", 25.0); @@ -365,6 +573,11 @@ bool Config::loadConfig(const std::string& filename) wind_W = (float)get_double("wind_W", 15.0f); wind_M = (float)get_double("wind_M", 10.0f); wind_D = (float)get_double("wind_D", 8.0f); + // Makcu + makcu_baudrate = get_long("makcu_baudrate", 4000000); + makcu_port = get_string("makcu_port", "COM1"); + if (makcu_port.empty() || makcu_port == "COM0") + makcu_port = "COM1"; // kmbox_B kmbox_b_baudrate = get_long("kmbox_baudrate", 115200); @@ -373,9 +586,18 @@ bool Config::loadConfig(const std::string& filename) // Mouse shooting auto_shoot = get_bool("auto_shoot", false); triggerbot = get_bool("triggerbot", false); - triggerbot_interval = get_double("triggerbot_interval", 0.0); - triggerbot_predict_ms = get_double("triggerbot_predict_ms", 0.0); - triggerbot_predict_alpha = get_double("triggerbot_predict_alpha", 0.5); + long reaction_ms_raw = get_long("triggerbot_reaction_ms", -1); + if (reaction_ms_raw >= 0) + { + triggerbot_reaction_ms = static_cast(reaction_ms_raw); + } + else + { + double legacy_interval_s = get_double("triggerbot_interval", 0.0); + triggerbot_reaction_ms = static_cast(legacy_interval_s * 1000.0 + 0.5); + } + if (triggerbot_reaction_ms < 0) + triggerbot_reaction_ms = 0; bScope_multiplier = (float)get_double("bScope_multiplier", 1.2); triggerbot_bScope_multiplier = (float)get_double("triggerbot_bScope_multiplier", 1.2); @@ -386,7 +608,7 @@ bool Config::loadConfig(const std::string& filename) color_target = get_string("color_target", "yellow"); tinyArea = get_long("tinyArea", 2); isOnlyTop = get_bool("isOnlyTop", true); - scanError = get_long("scanError", 0.1f); + scanError = static_cast(get_double("scanError", 0.1)); // HSV ranges color_ranges.clear(); @@ -394,7 +616,7 @@ bool Config::loadConfig(const std::string& filename) ini.GetAllKeys("Colors", colorKeys); for (const auto& k : colorKeys) { - std::string key = k.pItem; // например "Yellow" + std::string key = k.pItem; // ???????? "Yellow" std::string val = ini.GetValue("Colors", key.c_str(), ""); auto parts = splitString(val, ','); if (parts.size() == 6) { @@ -424,7 +646,7 @@ bool Config::loadConfig(const std::string& filename) #endif ); - // Проверка допустимых значений (TRT / DML / COLOR) + // ???????? ?????????? ???????? (TRT / DML / COLOR) if (backend != "TRT" && backend != "DML" && backend != "COLOR") { #ifdef USE_CUDA backend = "TRT"; @@ -461,6 +683,7 @@ bool Config::loadConfig(const std::string& filename) #ifdef USE_CUDA use_cuda_graph = get_bool("use_cuda_graph", false); use_pinned_memory = get_bool("use_pinned_memory", true); + capture_use_cuda = get_bool("capture_use_cuda", true); #endif // Buttons @@ -478,6 +701,85 @@ bool Config::loadConfig(const std::string& filename) overlay_opacity = get_long("overlay_opacity", 225); overlay_snow_theme = get_bool("overlay_snow_theme", true); overlay_ui_scale = (float)get_double("overlay_ui_scale", 1.0); + game_overlay_enabled = get_bool("game_overlay_enabled", false); + game_overlay_max_fps = get_long("game_overlay_max_fps", 0); + game_overlay_draw_boxes = get_bool("game_overlay_draw_boxes", true); + game_overlay_draw_future = get_bool("game_overlay_draw_future", true); + game_overlay_draw_wind_tail = get_bool("game_overlay_draw_wind_tail", true); + game_overlay_draw_frame = get_bool("game_overlay_draw_frame", true); + game_overlay_show_target_correction = get_bool("game_overlay_show_target_correction", true); + game_overlay_show_fps_counter = get_bool("game_overlay_show_fps_counter", true); + game_overlay_show_latency = get_bool("game_overlay_show_latency", true); + game_overlay_box_a = get_long("game_overlay_box_a", 255); + game_overlay_box_r = get_long("game_overlay_box_r", 0); + game_overlay_box_g = get_long("game_overlay_box_g", 255); + game_overlay_box_b = get_long("game_overlay_box_b", 0); + game_overlay_frame_a = get_long("game_overlay_frame_a", 180); + game_overlay_frame_r = get_long("game_overlay_frame_r", 255); + game_overlay_frame_g = get_long("game_overlay_frame_g", 255); + game_overlay_frame_b = get_long("game_overlay_frame_b", 255); + game_overlay_box_thickness = static_cast(get_double("game_overlay_box_thickness", 2.0)); + game_overlay_frame_thickness = static_cast(get_double("game_overlay_frame_thickness", 1.5)); + game_overlay_future_point_radius = static_cast(get_double("game_overlay_future_point_radius", 5.0)); + game_overlay_future_alpha_falloff = static_cast(get_double("game_overlay_future_alpha_falloff", 1.0)); + game_overlay_icon_enabled = get_bool("game_overlay_icon_enabled", false); + game_overlay_icon_path = get_string("game_overlay_icon_path", "icon.png"); + game_overlay_icon_width = get_long("game_overlay_icon_width", 64); + game_overlay_icon_height = get_long("game_overlay_icon_height", 64); + game_overlay_icon_offset_x = static_cast(get_double("game_overlay_icon_offset_x", 0.0)); + game_overlay_icon_offset_y = static_cast(get_double("game_overlay_icon_offset_y", 0.0)); + game_overlay_icon_anchor = get_string("game_overlay_icon_anchor", "center"); + game_overlay_icon_class = get_long("game_overlay_icon_class", -1); + clampGameOverlayColor(); + aim_sim_enabled = get_bool("aim_sim_enabled", false); + aim_sim_x = get_long("aim_sim_x", 24); + aim_sim_y = get_long("aim_sim_y", 24); + aim_sim_width = get_long("aim_sim_width", 560); + aim_sim_height = get_long("aim_sim_height", 360); + aim_sim_fps_min = get_long("aim_sim_fps_min", 90); + aim_sim_fps_max = get_long("aim_sim_fps_max", 120); + aim_sim_fps_jitter = static_cast(get_double("aim_sim_fps_jitter", 0.15)); + aim_sim_capture_delay_ms = static_cast(get_double("aim_sim_capture_delay_ms", 6.0)); + aim_sim_inference_delay_ms = static_cast(get_double("aim_sim_inference_delay_ms", 12.0)); + aim_sim_use_live_inference = get_bool("aim_sim_use_live_inference", true); + aim_sim_input_delay_ms = static_cast(get_double("aim_sim_input_delay_ms", 2.0)); + aim_sim_extra_delay_ms = static_cast(get_double("aim_sim_extra_delay_ms", 2.0)); + aim_sim_target_max_speed = static_cast(get_double("aim_sim_target_max_speed", 560.0)); + aim_sim_target_accel = static_cast(get_double("aim_sim_target_accel", 1850.0)); + aim_sim_target_stop_chance = static_cast(get_double("aim_sim_target_stop_chance", 0.25)); + aim_sim_show_observed = get_bool("aim_sim_show_observed", true); + aim_sim_show_history = get_bool("aim_sim_show_history", true); + if (aim_sim_width < 220) aim_sim_width = 220; + if (aim_sim_width > 1920) aim_sim_width = 1920; + if (aim_sim_height < 180) aim_sim_height = 180; + if (aim_sim_height > 1080) aim_sim_height = 1080; + if (aim_sim_fps_min < 15) aim_sim_fps_min = 15; + if (aim_sim_fps_min > 360) aim_sim_fps_min = 360; + if (aim_sim_fps_max < 15) aim_sim_fps_max = 15; + if (aim_sim_fps_max > 360) aim_sim_fps_max = 360; + if (aim_sim_fps_min > aim_sim_fps_max) std::swap(aim_sim_fps_min, aim_sim_fps_max); + if (aim_sim_fps_jitter < 0.0f) aim_sim_fps_jitter = 0.0f; + if (aim_sim_fps_jitter > 0.8f) aim_sim_fps_jitter = 0.8f; + if (aim_sim_capture_delay_ms < 0.0f) aim_sim_capture_delay_ms = 0.0f; + if (aim_sim_capture_delay_ms > 80.0f) aim_sim_capture_delay_ms = 80.0f; + if (aim_sim_inference_delay_ms < 0.0f) aim_sim_inference_delay_ms = 0.0f; + if (aim_sim_inference_delay_ms > 120.0f) aim_sim_inference_delay_ms = 120.0f; + if (aim_sim_input_delay_ms < 0.0f) aim_sim_input_delay_ms = 0.0f; + if (aim_sim_input_delay_ms > 60.0f) aim_sim_input_delay_ms = 60.0f; + if (aim_sim_extra_delay_ms < 0.0f) aim_sim_extra_delay_ms = 0.0f; + if (aim_sim_extra_delay_ms > 60.0f) aim_sim_extra_delay_ms = 60.0f; + if (aim_sim_target_max_speed < 20.0f) aim_sim_target_max_speed = 20.0f; + if (aim_sim_target_max_speed > 2500.0f) aim_sim_target_max_speed = 2500.0f; + if (aim_sim_target_accel < 20.0f) aim_sim_target_accel = 20.0f; + if (aim_sim_target_accel > 10000.0f) aim_sim_target_accel = 10000.0f; + if (aim_sim_target_stop_chance < 0.0f) aim_sim_target_stop_chance = 0.0f; + if (aim_sim_target_stop_chance > 0.95f) aim_sim_target_stop_chance = 0.95f; + + // OBS + is_obs = get_bool("is_obs", false); + obs_ip = get_string("obs_ip", "0.0.0.0"); + obs_port = get_long("obs_port", 4455); + obs_fps = get_long("obs_fps", 240); // Custom Classes class_player = get_long("class_player", 0); @@ -494,6 +796,7 @@ bool Config::loadConfig(const std::string& filename) // Debug window show_window = get_bool("show_window", true); + show_fps = get_bool("show_fps", false); screenshot_button = splitString(get_string("screenshot_button", "None")); screenshot_delay = get_long("screenshot_delay", 500); verbose = get_bool("verbose", false); @@ -511,7 +814,7 @@ bool Config::saveConfig(const std::string& filename) } file << "# An explanation of the options can be found at:\n"; - file << "# https://github.com/SunOner/sunone_aimbot_docs/blob/main/config/config_cpp.md\n\n"; + file << "# https://github.com/RN-AI/RN_AI_cpp\n\n"; // Capture file << "# Capture\n" @@ -540,7 +843,29 @@ bool Config::saveConfig(const std::string& filename) << std::fixed << std::setprecision(1) << "target_lock_distance = " << target_lock_distance << "\n" << std::fixed << std::setprecision(2) - << "target_lock_reacquire_time = " << target_lock_reacquire_time << "\n\n"; + << "target_lock_reacquire_time = " << target_lock_reacquire_time << "\n" + << "smart_target_lock = " << (smart_target_lock ? "true" : "false") << "\n" + << "target_reference_class = " << target_reference_class << "\n" + << "target_lock_fallback_class = " << target_lock_fallback_class << "\n" + << "target_switch_delay = " << target_switch_delay << "\n" + << std::fixed << std::setprecision(1) + << "aim_bot_scope = " << aim_bot_scope << "\n" + << std::fixed << std::setprecision(2) + << "aim_bot_position = " << aim_bot_position << "\n" + << "aim_bot_position2 = " << aim_bot_position2 << "\n" + << "allowed_classes = " << allowed_classes << "\n" + << "class_priority_order = " << class_priority_order << "\n" + << "distance_scoring_weight = " << distance_scoring_weight << "\n" + << "center_scoring_weight = " << center_scoring_weight << "\n" + << "size_scoring_weight = " << size_scoring_weight << "\n" + << "aim_weight_tiebreak_ratio = " << aim_weight_tiebreak_ratio << "\n" + << "small_target_enhancement_enabled = " << (small_target_enhancement_enabled ? "true" : "false") << "\n" + << "small_target_boost_factor = " << small_target_boost_factor << "\n" + << "small_target_threshold = " << small_target_threshold << "\n" + << "small_target_medium_threshold = " << small_target_medium_threshold << "\n" + << "small_target_medium_boost = " << small_target_medium_boost << "\n" + << "small_target_smooth_enabled = " << (small_target_smooth_enabled ? "true" : "false") << "\n" + << "small_target_smooth_frames = " << small_target_smooth_frames << "\n\n"; // Mouse file << "# Mouse move\n" @@ -550,6 +875,7 @@ bool Config::saveConfig(const std::string& filename) << "maxSpeedMultiplier = " << maxSpeedMultiplier << "\n" << "smoothness = " << smoothness << "\n" << "use_smoothing = " << (use_smoothing ? "true" : "false") << "\n" + << "tracking_smoothing = " << (tracking_smoothing ? "true" : "false") << "\n" << "use_kalman = " << (use_kalman ? "true" : "false") << "\n\n" << "kalman_process_noise = " << kalman_process_noise << "\n" << "kalman_measurement_noise = " << kalman_measurement_noise << "\n" @@ -559,9 +885,21 @@ bool Config::saveConfig(const std::string& filename) << std::fixed << std::setprecision(2) << "predictionInterval = " << predictionInterval << "\n" + << "prediction_mode = " << prediction_mode << "\n" + << "prediction_kalman_lead_ms = " << prediction_kalman_lead_ms << "\n" + << "prediction_kalman_max_lead_ms = " << prediction_kalman_max_lead_ms << "\n" + << "prediction_velocity_smoothing = " << prediction_velocity_smoothing << "\n" + << "prediction_velocity_scale = " << prediction_velocity_scale << "\n" + << "prediction_kalman_process_noise = " << prediction_kalman_process_noise << "\n" + << "prediction_kalman_measurement_noise = " << prediction_kalman_measurement_noise << "\n" + << "prediction_use_future_for_aim = " << (prediction_use_future_for_aim ? "true" : "false") << "\n" << "prediction_futurePositions = " << prediction_futurePositions << "\n" << "draw_futurePositions = " << (draw_futurePositions ? "true" : "false") << "\n" + << "camera_compensation_enabled = " << (camera_compensation_enabled ? "true" : "false") << "\n" + << "camera_compensation_max_shift = " << camera_compensation_max_shift << "\n" + << "camera_compensation_strength = " << camera_compensation_strength << "\n" + << "snapRadius = " << snapRadius << "\n" << "nearRadius = " << nearRadius << "\n" << "speedCurveExponent = " << speedCurveExponent << "\n" @@ -582,6 +920,10 @@ bool Config::saveConfig(const std::string& filename) << "wind_W = " << wind_W << "\n" << "wind_M = " << wind_M << "\n" << "wind_D = " << wind_D << "\n\n"; + // Makcu + file << "# Makcu\n" + << "makcu_baudrate = " << makcu_baudrate << "\n" + << "makcu_port = " << makcu_port << "\n\n"; // kmbox_B file << "# Kmbox_B\n" @@ -592,10 +934,9 @@ bool Config::saveConfig(const std::string& filename) file << "# Mouse shooting\n" << "auto_shoot = " << (auto_shoot ? "true" : "false") << "\n" << "triggerbot = " << (triggerbot ? "true" : "false") << "\n" + << "triggerbot_reaction_ms = " << triggerbot_reaction_ms << "\n" << std::fixed << std::setprecision(2) - << "triggerbot_interval = " << triggerbot_interval << "\n" - << "triggerbot_predict_ms = " << triggerbot_predict_ms << "\n" - << "triggerbot_predict_alpha = " << triggerbot_predict_alpha << "\n" + << "triggerbot_interval = " << (static_cast(triggerbot_reaction_ms) / 1000.0) << "\n" << std::fixed << std::setprecision(1) << "bScope_multiplier = " << bScope_multiplier << "\n" << "triggerbot_bScope_multiplier = " << triggerbot_bScope_multiplier << "\n\n"; @@ -623,7 +964,8 @@ bool Config::saveConfig(const std::string& filename) #ifdef USE_CUDA file << "\n# CUDA\n" << "use_cuda_graph = " << (use_cuda_graph ? "true" : "false") << "\n" - << "use_pinned_memory = " << (use_pinned_memory ? "true" : "false") << "\n\n"; + << "use_pinned_memory = " << (use_pinned_memory ? "true" : "false") << "\n" + << "capture_use_cuda = " << (capture_use_cuda ? "true" : "false") << "\n\n"; #endif // Buttons @@ -643,21 +985,60 @@ bool Config::saveConfig(const std::string& filename) << "overlay_opacity = " << overlay_opacity << "\n" << "overlay_snow_theme = " << (overlay_snow_theme ? "true" : "false") << "\n" << std::fixed << std::setprecision(2) - << "overlay_ui_scale = " << overlay_ui_scale << "\n\n"; - - // Custom Classes - file << "# Custom Classes\n" - << "class_player = " << class_player << "\n" - << "class_bot = " << class_bot << "\n" - << "class_weapon = " << class_weapon << "\n" - << "class_outline = " << class_outline << "\n" - << "class_dead_body = " << class_dead_body << "\n" - << "class_hideout_target_human = " << class_hideout_target_human << "\n" - << "class_hideout_target_balls = " << class_hideout_target_balls << "\n" - << "class_head = " << class_head << "\n" - << "class_smoke = " << class_smoke << "\n" - << "class_fire = " << class_fire << "\n" - << "class_third_person = " << class_third_person << "\n\n"; + << "overlay_ui_scale = " << overlay_ui_scale << "\n" + << "game_overlay_enabled = " << (game_overlay_enabled ? "true" : "false") << "\n" + << "game_overlay_max_fps = " << game_overlay_max_fps << "\n" + << "game_overlay_draw_boxes = " << (game_overlay_draw_boxes ? "true" : "false") << "\n" + << "game_overlay_draw_future = " << (game_overlay_draw_future ? "true" : "false") << "\n" + << "game_overlay_draw_wind_tail = " << (game_overlay_draw_wind_tail ? "true" : "false") << "\n" + << "game_overlay_draw_frame = " << (game_overlay_draw_frame ? "true" : "false") << "\n" + << "game_overlay_show_target_correction = " << (game_overlay_show_target_correction ? "true" : "false") << "\n" + << "game_overlay_show_fps_counter = " << (game_overlay_show_fps_counter ? "true" : "false") << "\n" + << "game_overlay_show_latency = " << (game_overlay_show_latency ? "true" : "false") << "\n" + << "game_overlay_box_a = " << game_overlay_box_a << "\n" + << "game_overlay_box_r = " << game_overlay_box_r << "\n" + << "game_overlay_box_g = " << game_overlay_box_g << "\n" + << "game_overlay_box_b = " << game_overlay_box_b << "\n" + << "game_overlay_frame_a = " << game_overlay_frame_a << "\n" + << "game_overlay_frame_r = " << game_overlay_frame_r << "\n" + << "game_overlay_frame_g = " << game_overlay_frame_g << "\n" + << "game_overlay_frame_b = " << game_overlay_frame_b << "\n" + << "game_overlay_box_thickness = " << game_overlay_box_thickness << "\n" + << "game_overlay_frame_thickness = " << game_overlay_frame_thickness << "\n" + << "game_overlay_future_point_radius = " << game_overlay_future_point_radius << "\n" + << "game_overlay_future_alpha_falloff = " << game_overlay_future_alpha_falloff << "\n" + << "game_overlay_icon_enabled = " << (game_overlay_icon_enabled ? "true" : "false") << "\n" + << "game_overlay_icon_path = " << game_overlay_icon_path << "\n" + << "game_overlay_icon_width = " << game_overlay_icon_width << "\n" + << "game_overlay_icon_height = " << game_overlay_icon_height << "\n" + << "game_overlay_icon_offset_x = " << game_overlay_icon_offset_x << "\n" + << "game_overlay_icon_offset_y = " << game_overlay_icon_offset_y << "\n" + << "game_overlay_icon_anchor = " << game_overlay_icon_anchor << "\n" + << "game_overlay_icon_class = " << game_overlay_icon_class << "\n" + << "aim_sim_enabled = " << (aim_sim_enabled ? "true" : "false") << "\n" + << "aim_sim_x = " << aim_sim_x << "\n" + << "aim_sim_y = " << aim_sim_y << "\n" + << "aim_sim_width = " << aim_sim_width << "\n" + << "aim_sim_height = " << aim_sim_height << "\n" + << "aim_sim_fps_min = " << aim_sim_fps_min << "\n" + << "aim_sim_fps_max = " << aim_sim_fps_max << "\n" + << "aim_sim_fps_jitter = " << aim_sim_fps_jitter << "\n" + << "aim_sim_capture_delay_ms = " << aim_sim_capture_delay_ms << "\n" + << "aim_sim_inference_delay_ms = " << aim_sim_inference_delay_ms << "\n" + << "aim_sim_use_live_inference = " << (aim_sim_use_live_inference ? "true" : "false") << "\n" + << "aim_sim_input_delay_ms = " << aim_sim_input_delay_ms << "\n" + << "aim_sim_extra_delay_ms = " << aim_sim_extra_delay_ms << "\n" + << "aim_sim_target_max_speed = " << aim_sim_target_max_speed << "\n" + << "aim_sim_target_accel = " << aim_sim_target_accel << "\n" + << "aim_sim_target_stop_chance = " << aim_sim_target_stop_chance << "\n" + << "aim_sim_show_observed = " << (aim_sim_show_observed ? "true" : "false") << "\n" + << "aim_sim_show_history = " << (aim_sim_show_history ? "true" : "false") << "\n\n"; + + file << "# OBS\n" + << "is_obs = " << (is_obs ? "true" : "false") << "\n" + << "obs_ip = " << obs_ip << "\n" + << "obs_port = " << obs_port << "\n" + << "obs_fps = " << obs_fps << "\n\n"; // Color detection file << "# Color detection\n"; @@ -669,15 +1050,6 @@ bool Config::saveConfig(const std::string& filename) file << "isOnlyTop = " << isOnlyTop << "\n"; file << "scanError = " << scanError << "\n\n"; - file << "[Colors]\n"; - for (const auto& cr : color_ranges) { - file << cr.name << " = " - << cr.h_low << "," << cr.s_low << "," << cr.v_low << "," - << cr.h_high << "," << cr.s_high << "," << cr.v_high << "\n"; - } - file << "\n"; - - // Debug file << "# Debug\n" << "show_window = " << (show_window ? "true" : "false") << "\n" @@ -689,6 +1061,15 @@ bool Config::saveConfig(const std::string& filename) // Active game file << "# Active game profile\n"; file << "active_game = " << active_game << "\n\n"; + + file << "[Colors]\n"; + for (const auto& cr : color_ranges) { + file << cr.name << " = " + << cr.h_low << "," << cr.s_low << "," << cr.v_low << "," + << cr.h_high << "," << cr.s_high << "," << cr.v_high << "\n"; + } + file << "\n"; + file << "[Games]\n"; for (auto& kv : game_profiles) { @@ -700,6 +1081,44 @@ bool Config::saveConfig(const std::string& filename) file << ",true," << gp.baseFOV; file << "\n"; } + file << "\n"; + + if (!class_aim_positions.empty()) + { + std::vector class_ids; + class_ids.reserve(class_aim_positions.size()); + for (const auto& kv : class_aim_positions) + class_ids.push_back(kv.first); + std::sort(class_ids.begin(), class_ids.end()); + file << "[ClassAim]\n"; + file << std::fixed << std::setprecision(2); + for (int class_id : class_ids) + { + auto it = class_aim_positions.find(class_id); + if (it == class_aim_positions.end()) + continue; + file << class_id << " = " << it->second.first << "," << it->second.second << "\n"; + } + file << "\n"; + } + + if (!custom_class_names.empty()) + { + std::vector class_ids; + class_ids.reserve(custom_class_names.size()); + for (const auto& kv : custom_class_names) + class_ids.push_back(kv.first); + std::sort(class_ids.begin(), class_ids.end()); + file << "[ClassNames]\n"; + for (int class_id : class_ids) + { + auto it = custom_class_names.find(class_id); + if (it == custom_class_names.end()) + continue; + file << class_id << " = " << it->second << "\n"; + } + file << "\n"; + } file.close(); return true; @@ -724,3 +1143,6 @@ std::pair Config::degToCounts(double degX, double degY, double f double cy = degY / (gp.sens * gp.pitch * scale); return { cx, cy }; } + + + diff --git a/sunone_aimbot_cpp/config/config.h b/RN_AI_cpp/config/config.h similarity index 58% rename from sunone_aimbot_cpp/config/config.h rename to RN_AI_cpp/config/config.h index 83909c2d..06f7a958 100644 --- a/sunone_aimbot_cpp/config/config.h +++ b/RN_AI_cpp/config/config.h @@ -11,7 +11,7 @@ class Config { public: // Capture - std::string capture_method; // "duplication_api", "winrt", "virtual_camera" + std::string capture_method; // "duplication_api", "winrt", "virtual_camera", "obs" int detection_resolution; int capture_fps; int monitor_idx; @@ -33,6 +33,28 @@ class Config bool target_lock_enabled; float target_lock_distance; float target_lock_reacquire_time; + bool smart_target_lock; + int target_reference_class; + int target_lock_fallback_class; + int target_switch_delay; + float aim_bot_scope; + float aim_bot_position; + float aim_bot_position2; + std::string allowed_classes; + std::string class_priority_order; + std::unordered_map custom_class_names; + float distance_scoring_weight; + float center_scoring_weight; + float size_scoring_weight; + float aim_weight_tiebreak_ratio; + bool small_target_enhancement_enabled; + float small_target_boost_factor; + float small_target_threshold; + float small_target_medium_threshold; + float small_target_medium_boost; + bool small_target_smooth_enabled; + int small_target_smooth_frames; + std::unordered_map> class_aim_positions; // Mouse int fovX; @@ -42,6 +64,7 @@ class Config int smoothness; bool use_smoothing; + bool tracking_smoothing; bool use_kalman; float kalman_process_noise; @@ -51,9 +74,21 @@ class Config float resetThreshold; float predictionInterval; + int prediction_mode; + float prediction_kalman_lead_ms; + float prediction_kalman_max_lead_ms; + float prediction_velocity_smoothing; + float prediction_velocity_scale; + float prediction_kalman_process_noise; + float prediction_kalman_measurement_noise; + bool prediction_use_future_for_aim; int prediction_futurePositions; bool draw_futurePositions; + bool camera_compensation_enabled; + float camera_compensation_max_shift; + float camera_compensation_strength; + float snapRadius; float nearRadius; float speedCurveExponent; @@ -92,9 +127,7 @@ class Config // Mouse shooting bool auto_shoot; bool triggerbot; - double triggerbot_interval; // seconds between triggerbot shots (0 = continuous hold) - double triggerbot_predict_ms; // prediction lead for triggerbot (ms, 0 = off) - double triggerbot_predict_alpha; // smoothing factor for predicted velocity (0..1) + int triggerbot_reaction_ms; // delay between triggerbot shots in ms (0 = continuous hold) float bScope_multiplier; float triggerbot_bScope_multiplier; @@ -118,6 +151,7 @@ class Config #ifdef USE_CUDA bool use_cuda_graph; bool use_pinned_memory; + bool capture_use_cuda; #endif // Buttons std::vector button_targeting; @@ -135,6 +169,72 @@ class Config int overlay_opacity; bool overlay_snow_theme; float overlay_ui_scale; + bool game_overlay_enabled; + int game_overlay_max_fps; + bool game_overlay_draw_boxes; + bool game_overlay_draw_future; + bool game_overlay_draw_wind_tail; + bool game_overlay_draw_frame; + bool game_overlay_show_target_correction; + bool game_overlay_show_fps_counter; + bool game_overlay_show_latency; + int game_overlay_box_a; + int game_overlay_box_r; + int game_overlay_box_g; + int game_overlay_box_b; + int game_overlay_frame_a; + int game_overlay_frame_r; + int game_overlay_frame_g; + int game_overlay_frame_b; + float game_overlay_box_thickness; + float game_overlay_frame_thickness; + float game_overlay_future_point_radius; + float game_overlay_future_alpha_falloff; + bool game_overlay_icon_enabled; + std::string game_overlay_icon_path; + int game_overlay_icon_width; + int game_overlay_icon_height; + float game_overlay_icon_offset_x; + float game_overlay_icon_offset_y; + std::string game_overlay_icon_anchor; + int game_overlay_icon_class; + bool aim_sim_enabled; + int aim_sim_x; + int aim_sim_y; + int aim_sim_width; + int aim_sim_height; + int aim_sim_fps_min; + int aim_sim_fps_max; + float aim_sim_fps_jitter; + float aim_sim_capture_delay_ms; + float aim_sim_inference_delay_ms; + bool aim_sim_use_live_inference; + float aim_sim_input_delay_ms; + float aim_sim_extra_delay_ms; + float aim_sim_target_max_speed; + float aim_sim_target_accel; + float aim_sim_target_stop_chance; + bool aim_sim_show_observed; + bool aim_sim_show_history; + + void clampGameOverlayColor() + { + auto clamp255 = [](int& v) { if (v < 0) v = 0; if (v > 255) v = 255; }; + clamp255(game_overlay_box_a); + clamp255(game_overlay_box_r); + clamp255(game_overlay_box_g); + clamp255(game_overlay_box_b); + clamp255(game_overlay_frame_a); + clamp255(game_overlay_frame_r); + clamp255(game_overlay_frame_g); + clamp255(game_overlay_frame_b); + } + + // OBS + bool is_obs; + std::string obs_ip; + int obs_port; + int obs_fps; // Custom Classes int class_player; // 0 diff --git a/sunone_aimbot_cpp/detector/color_detector.cpp b/RN_AI_cpp/detector/color_detector.cpp similarity index 57% rename from sunone_aimbot_cpp/detector/color_detector.cpp rename to RN_AI_cpp/detector/color_detector.cpp index b8e0c7b9..33775e4c 100644 --- a/sunone_aimbot_cpp/detector/color_detector.cpp +++ b/RN_AI_cpp/detector/color_detector.cpp @@ -1,5 +1,5 @@ -#include "color_detector.h" -#include "sunone_aimbot_cpp.h" +#include "color_detector.h" +#include "rn_ai_cpp.h" ColorDetector::ColorDetector() : erodeIter(1), dilateIter(2), minArea(50), @@ -13,7 +13,7 @@ ColorDetector::~ColorDetector() { void ColorDetector::initializeFromConfig(const Config& cfg) { colorRanges.clear(); - // Если выбран конкретный цвет — берём его + // ???? ?????? ?????????? ???? ????? ??? for (const auto& cr : cfg.color_ranges) { if (cr.name == cfg.color_target) { colorRanges.push_back({ @@ -25,7 +25,7 @@ void ColorDetector::initializeFromConfig(const Config& cfg) { } } - // Если не нашли — fallback: берём все + // ???? ?? ????? fallback: ????? ??? if (colorRanges.empty()) { for (const auto& cr : cfg.color_ranges) { colorRanges.push_back({ @@ -76,7 +76,7 @@ void ColorDetector::inferenceThread() { #include // std::clamp void ColorDetector::detectColors(const cv::Mat& frame) { - // Преобразуем изображение в формат BGR (если оно в формате BGRA) + // ??????????? ??????????? ? ?????? BGR (???? ??? ? ??????? BGRA) cv::Mat bgr; if (frame.channels() == 4) { cv::cvtColor(frame, bgr, cv::COLOR_BGRA2BGR); @@ -85,96 +85,96 @@ void ColorDetector::detectColors(const cv::Mat& frame) { bgr = frame; } - // Преобразуем изображение в цветовую модель HSV + // ??????????? ??????????? ? ???????? ?????? HSV cv::Mat hsv; cv::cvtColor(bgr, hsv, cv::COLOR_BGR2HSV); - // Создаем пустую маску для всех выбранных цветовых диапазонов + // ??????? ?????? ????? ??? ???? ????????? ???????? ?????????? cv::Mat combinedMask = cv::Mat::zeros(bgr.size(), CV_8UC1); - // Собираем все выбранные диапазоны + // ???????? ??? ????????? ????????? for (const auto& range : colorRanges) { cv::Mat mask; - cv::inRange(hsv, range.lower, range.upper, mask); // Находим пиксели, попадающие в диапазон - combinedMask |= mask; // Объединяем маски (сейчас все диапазоны объединены в один) + cv::inRange(hsv, range.lower, range.upper, mask); // ??????? ???????, ?????????? ? ???????? + combinedMask |= mask; // ?????????? ????? (?????? ??? ????????? ?????????? ? ????) } - // Немного расширим пятна, чтобы мелкие объекты не пропали + // ??????? ???????? ?????, ????? ?????? ??????? ?? ??????? cv::dilate(combinedMask, combinedMask, cv::Mat(), cv::Point(-1, -1), dilateIter); - // Находим контуры на маске + // ??????? ??????? ?? ????? std::vector> contours; cv::findContours(combinedMask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); - // Вектор для хранения найденных прямоугольников + // ?????? ??? ???????? ????????? ??????????????? std::vector boxes; - // Переменная для хранения самого верхнего объекта + // ?????????? ??? ???????? ?????? ???????? ??????? cv::Rect topObject; bool foundTopObject = false; - // Если TopHead = true, ищем только самый верхний объект + // ???? TopHead = true, ???? ?????? ????? ??????? ?????? if (isOnlyTop) { for (auto& c : contours) { - double area = cv::contourArea(c); // Вычисляем площадь контура + double area = cv::contourArea(c); // ????????? ??????? ??????? - // Если площадь достаточна и объект не слишком маленький + // ???? ??????? ?????????? ? ?????? ?? ??????? ????????? if (area >= minArea) { - cv::Rect boundingBox = cv::boundingRect(c); // Получаем ограничивающий прямоугольник + cv::Rect boundingBox = cv::boundingRect(c); // ???????? ?????????????? ????????????? - // Пропускаем слишком маленькие объекты + // ?????????? ??????? ????????? ??????? if (area < tinyArea) { continue; } - // Если это первый объект, или он выше всех по Y, сохраняем его + // ???? ??? ?????? ??????, ??? ?? ???? ???? ?? Y, ????????? ??? if (topObject.area() == 0 || boundingBox.y < topObject.y) { topObject = boundingBox; - foundTopObject = true; // Устанавливаем флаг, что верхний объект найден + foundTopObject = true; // ????????????? ????, ??? ??????? ?????? ?????? } } } - // Если был найден верхний объект, добавляем его в список + // ???? ??? ?????? ??????? ??????, ????????? ??? ? ?????? if (foundTopObject) { boxes.push_back(topObject); } } else { - // Если TopHead = false, обрабатываем все объекты как раньше + // ???? TopHead = false, ???????????? ??? ??????? ??? ?????? for (auto& c : contours) { - double area = cv::contourArea(c); // Вычисляем площадь контура + double area = cv::contourArea(c); // ????????? ??????? ??????? - // Если площадь достаточна и объект не слишком маленький + // ???? ??????? ?????????? ? ?????? ?? ??????? ????????? if (area >= minArea) { - cv::Rect boundingBox = cv::boundingRect(c); // Получаем ограничивающий прямоугольник + cv::Rect boundingBox = cv::boundingRect(c); // ???????? ?????????????? ????????????? - // Пропускаем слишком маленькие объекты + // ?????????? ??????? ????????? ??????? if (area < tinyArea) { continue; } - boxes.push_back(boundingBox); // Добавляем прямоугольник в список + boxes.push_back(boundingBox); // ????????? ????????????? ? ?????? } } } - // Обрабатываем результаты + // ???????????? ?????????? postProcess(boxes); // === DEBUG WINDOW === if (debug_show_window) { cv::Mat dbg = bgr.clone(); - // Рисуем контуры на изображении для отладки + // ?????? ??????? ?? ??????????? ??? ??????? cv::drawContours(dbg, contours, -1, { 0, 0, 255 }, 1); - // Рисуем прямоугольники для каждого найденного объекта + // ?????? ?????????????? ??? ??????? ?????????? ??????? for (auto& b : boxes) { cv::rectangle(dbg, b, debug_bgr, 2); } - // Показываем FPS + // ?????????? FPS if (debug_show_fps) { auto now = std::chrono::steady_clock::now(); double dt = std::chrono::duration(now - dbg_prev_ts).count(); @@ -185,7 +185,7 @@ void ColorDetector::detectColors(const cv::Mat& frame) { cv::putText(dbg, buf, { 10, 30 }, cv::FONT_HERSHEY_SIMPLEX, 0.8, debug_bgr, 2); } - // Показываем изображение с отрисованными результатами + // ?????????? ??????????? ? ????????????? ???????????? cv::imshow(debug_window_name, dbg); cv::waitKey(1); } diff --git a/sunone_aimbot_cpp/detector/color_detector.h b/RN_AI_cpp/detector/color_detector.h similarity index 100% rename from sunone_aimbot_cpp/detector/color_detector.h rename to RN_AI_cpp/detector/color_detector.h diff --git a/sunone_aimbot_cpp/detector/cuda_12_8_fused_preprocess.cu b/RN_AI_cpp/detector/cuda_12_8_fused_preprocess.cu similarity index 100% rename from sunone_aimbot_cpp/detector/cuda_12_8_fused_preprocess.cu rename to RN_AI_cpp/detector/cuda_12_8_fused_preprocess.cu diff --git a/sunone_aimbot_cpp/detector/detection_buffer.cpp b/RN_AI_cpp/detector/detection_buffer.cpp similarity index 100% rename from sunone_aimbot_cpp/detector/detection_buffer.cpp rename to RN_AI_cpp/detector/detection_buffer.cpp diff --git a/sunone_aimbot_cpp/detector/detection_buffer.h b/RN_AI_cpp/detector/detection_buffer.h similarity index 100% rename from sunone_aimbot_cpp/detector/detection_buffer.h rename to RN_AI_cpp/detector/detection_buffer.h diff --git a/sunone_aimbot_cpp/detector/detector.zip b/RN_AI_cpp/detector/detector.zip similarity index 100% rename from sunone_aimbot_cpp/detector/detector.zip rename to RN_AI_cpp/detector/detector.zip diff --git a/sunone_aimbot_cpp/detector/dml_detector.cpp b/RN_AI_cpp/detector/dml_detector.cpp similarity index 95% rename from sunone_aimbot_cpp/detector/dml_detector.cpp rename to RN_AI_cpp/detector/dml_detector.cpp index 46caebf9..e227732d 100644 --- a/sunone_aimbot_cpp/detector/dml_detector.cpp +++ b/RN_AI_cpp/detector/dml_detector.cpp @@ -11,7 +11,7 @@ #include #include "dml_detector.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "postProcess.h" #include "capture.h" @@ -232,7 +232,11 @@ void DirectMLDetector::dmlInferenceThread() const std::vector& detections = detectionsBatch.back(); auto end = std::chrono::steady_clock::now(); + lastPreprocessTimeDML = std::chrono::duration(0.0); lastInferenceTimeDML = end - start; + lastCopyTimeDML = std::chrono::duration(0.0); + lastPostprocessTimeDML = std::chrono::duration(0.0); + lastNmsTimeDML = std::chrono::duration(0.0); std::lock_guard lock(detectionBuffer.mutex); detectionBuffer.boxes.clear(); @@ -245,4 +249,4 @@ void DirectMLDetector::dmlInferenceThread() detectionBuffer.cv.notify_all(); } } -} \ No newline at end of file +} diff --git a/sunone_aimbot_cpp/detector/dml_detector.h b/RN_AI_cpp/detector/dml_detector.h similarity index 79% rename from sunone_aimbot_cpp/detector/dml_detector.h rename to RN_AI_cpp/detector/dml_detector.h index e08f4920..cec6901c 100644 --- a/sunone_aimbot_cpp/detector/dml_detector.h +++ b/RN_AI_cpp/detector/dml_detector.h @@ -21,7 +21,11 @@ class DirectMLDetector int getNumberOfClasses(); + std::chrono::duration lastPreprocessTimeDML; std::chrono::duration lastInferenceTimeDML; + std::chrono::duration lastCopyTimeDML; + std::chrono::duration lastPostprocessTimeDML; + std::chrono::duration lastNmsTimeDML; std::condition_variable inferenceCV; std::atomic shouldExit = false; @@ -43,4 +47,4 @@ class DirectMLDetector Ort::MemoryInfo memory_info; }; -#endif // DIRECTML_DETECTOR_H \ No newline at end of file +#endif // DIRECTML_DETECTOR_H diff --git a/sunone_aimbot_cpp/detector/fused_preprocess.h b/RN_AI_cpp/detector/fused_preprocess.h similarity index 100% rename from sunone_aimbot_cpp/detector/fused_preprocess.h rename to RN_AI_cpp/detector/fused_preprocess.h diff --git a/sunone_aimbot_cpp/detector/postProcess.cpp b/RN_AI_cpp/detector/postProcess.cpp similarity index 99% rename from sunone_aimbot_cpp/detector/postProcess.cpp rename to RN_AI_cpp/detector/postProcess.cpp index ade514fe..c7deabc0 100644 --- a/sunone_aimbot_cpp/detector/postProcess.cpp +++ b/RN_AI_cpp/detector/postProcess.cpp @@ -3,7 +3,7 @@ #include #include "postProcess.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #ifdef USE_CUDA #include "trt_detector.h" #endif diff --git a/sunone_aimbot_cpp/detector/postProcess.h b/RN_AI_cpp/detector/postProcess.h similarity index 100% rename from sunone_aimbot_cpp/detector/postProcess.h rename to RN_AI_cpp/detector/postProcess.h diff --git a/sunone_aimbot_cpp/detector/sunone_aimbot_cpp.cpp b/RN_AI_cpp/detector/rn_ai_cpp.cpp similarity index 99% rename from sunone_aimbot_cpp/detector/sunone_aimbot_cpp.cpp rename to RN_AI_cpp/detector/rn_ai_cpp.cpp index 9d1c13c8..4f391c75 100644 --- a/sunone_aimbot_cpp/detector/sunone_aimbot_cpp.cpp +++ b/RN_AI_cpp/detector/rn_ai_cpp.cpp @@ -1,4 +1,4 @@ -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #define _WINSOCKAPI_ #include #include @@ -13,7 +13,7 @@ #include "capture.h" #include "mouse.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "keyboard_listener.h" #include "overlay.h" #include "other_tools.h" diff --git a/sunone_aimbot_cpp/detector/trt_detector.cpp b/RN_AI_cpp/detector/trt_detector.cpp similarity index 90% rename from sunone_aimbot_cpp/detector/trt_detector.cpp rename to RN_AI_cpp/detector/trt_detector.cpp index f3f0348d..8d872e87 100644 --- a/sunone_aimbot_cpp/detector/trt_detector.cpp +++ b/RN_AI_cpp/detector/trt_detector.cpp @@ -20,7 +20,7 @@ #include "trt_detector.h" #include "nvinf.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "other_tools.h" #include "postProcess.h" #include "fused_preprocess.h" @@ -39,7 +39,8 @@ TrtDetector::TrtDetector() shouldExit(false), inputBufferDevice(nullptr), img_scale(1.0f), - numClasses(0) + numClasses(0), + pendingFrameType(PendingFrameType::None) { cudaStreamCreate(&stream); cudaEventCreate(&inferStartEvent); @@ -429,6 +430,28 @@ void TrtDetector::processFrame(const cv::Mat& frame) std::unique_lock lock(inferenceMutex); currentFrame = frame.clone(); + currentFrameGpu.release(); + pendingFrameType = PendingFrameType::Cpu; + frameReady = true; + inferenceCV.notify_one(); +} + +void TrtDetector::processFrameGpu(const cv::cuda::GpuMat& frame) +{ + if (config.backend == "DML") return; + + if (detectionPaused) + { + std::lock_guard lock(detectionBuffer.mutex); + detectionBuffer.boxes.clear(); + detectionBuffer.classes.clear(); + return; + } + + std::unique_lock lock(inferenceMutex); + currentFrame.release(); + currentFrameGpu = frame; + pendingFrameType = PendingFrameType::Gpu; frameReady = true; inferenceCV.notify_one(); } @@ -449,6 +472,10 @@ void TrtDetector::inferenceThread() for (auto& binding : outputBindings) if (binding.second) cudaFree(binding.second); outputBindings.clear(); + currentFrame.release(); + currentFrameGpu.release(); + frameReady = false; + pendingFrameType = PendingFrameType::None; } initialize("models/" + config.ai_model); detection_resolution_changed.store(true); @@ -456,6 +483,8 @@ void TrtDetector::inferenceThread() } cv::Mat frame; + cv::cuda::GpuMat frameGpu; + PendingFrameType frameType = PendingFrameType::None; bool hasNewFrame = false; { @@ -467,7 +496,19 @@ void TrtDetector::inferenceThread() if (frameReady) { - frame = std::move(currentFrame); + frameType = pendingFrameType; + if (frameType == PendingFrameType::Gpu) + { + frameGpu = currentFrameGpu; + currentFrameGpu.release(); + currentFrame.release(); + } + else + { + frame = std::move(currentFrame); + currentFrameGpu.release(); + } + pendingFrameType = PendingFrameType::None; frameReady = false; hasNewFrame = true; } @@ -488,12 +529,19 @@ void TrtDetector::inferenceThread() error_logged = false; } - if (hasNewFrame && !frame.empty()) + if (hasNewFrame) { + const bool hasCpuFrame = (frameType == PendingFrameType::Cpu && !frame.empty()); + const bool hasGpuFrame = (frameType == PendingFrameType::Gpu && !frameGpu.empty()); + if (!hasCpuFrame && !hasGpuFrame) + continue; try { auto t0 = std::chrono::steady_clock::now(); - preProcess(frame); + if (hasGpuFrame) + preProcess(frameGpu); + else + preProcess(frame); auto t1 = std::chrono::steady_clock::now(); if (useCudaGraph && !cudaGraphCaptured) @@ -715,6 +763,15 @@ void TrtDetector::preProcess(const cv::Mat& frame) { if (frame.empty()) return; + cv::cuda::Stream cvStream = cv::cuda::StreamAccessor::wrapStream(stream); + gpuFrame.upload(frame, cvStream); + preProcess(gpuFrame); +} + +void TrtDetector::preProcess(const cv::cuda::GpuMat& frame) +{ + if (frame.empty()) return; + void* inputBuffer = inputBindings[inputName]; if (!inputBuffer) return; @@ -722,21 +779,24 @@ void TrtDetector::preProcess(const cv::Mat& frame) int h = dims.d[2]; int w = dims.d[3]; - cv::cuda::Stream cvStream = cv::cuda::StreamAccessor::wrapStream(stream); - gpuFrame.upload(frame, cvStream); - const cv::cuda::GpuMat* src = &gpuFrame; if (frame.channels() == 4) { - cv::cuda::cvtColor(gpuFrame, gpuBgr, cv::COLOR_BGRA2BGR, 0, cvStream); + cv::cuda::Stream cvStream = cv::cuda::StreamAccessor::wrapStream(stream); + cv::cuda::cvtColor(frame, gpuBgr, cv::COLOR_BGRA2BGR, 0, cvStream); src = &gpuBgr; } else if (frame.channels() == 1) { - cv::cuda::cvtColor(gpuFrame, gpuBgr, cv::COLOR_GRAY2BGR, 0, cvStream); + cv::cuda::Stream cvStream = cv::cuda::StreamAccessor::wrapStream(stream); + cv::cuda::cvtColor(frame, gpuBgr, cv::COLOR_GRAY2BGR, 0, cvStream); src = &gpuBgr; } - else if (frame.channels() != 3) + else if (frame.channels() == 3) + { + src = &frame; + } + else { return; } diff --git a/sunone_aimbot_cpp/detector/trt_detector.h b/RN_AI_cpp/detector/trt_detector.h similarity index 90% rename from sunone_aimbot_cpp/detector/trt_detector.h rename to RN_AI_cpp/detector/trt_detector.h index fa0e941a..a11e06ed 100644 --- a/sunone_aimbot_cpp/detector/trt_detector.h +++ b/RN_AI_cpp/detector/trt_detector.h @@ -28,6 +28,7 @@ class TrtDetector ~TrtDetector(); void initialize(const std::string& modelFile); void processFrame(const cv::Mat& frame); + void processFrameGpu(const cv::cuda::GpuMat& frame); void inferenceThread(); float img_scale; @@ -67,11 +68,21 @@ class TrtDetector std::condition_variable inferenceCV; std::atomic shouldExit; cv::Mat currentFrame; + cv::cuda::GpuMat currentFrameGpu; bool frameReady; + enum class PendingFrameType + { + None = 0, + Cpu = 1, + Gpu = 2 + }; + PendingFrameType pendingFrameType = PendingFrameType::None; + void loadEngine(const std::string& engineFile); void preProcess(const cv::Mat& frame); + void preProcess(const cv::cuda::GpuMat& frame); void postProcess( const float* output, diff --git a/RN_AI_cpp/imgui.ini b/RN_AI_cpp/imgui.ini new file mode 100644 index 00000000..d1fd161e --- /dev/null +++ b/RN_AI_cpp/imgui.ini @@ -0,0 +1,22 @@ +[Window][Debug##Default] +Pos=60,60 +Size=400,400 + +[Window][Options] +Pos=0,0 +Size=1448,1022 + +[Table][0xA73256D8,4] +RefScale=30.42 +Column 0 Width=94 +Column 1 Weight=1.0000 +Column 2 Width=365 +Column 3 Width=650 + +[Table][0xCB8CBC28,4] +RefScale=26.91 +Column 0 Width=90 +Column 1 Weight=1.0000 +Column 2 Width=90 +Column 3 Width=90 + diff --git a/sunone_aimbot_cpp/imgui/imconfig.h b/RN_AI_cpp/imgui/imconfig.h similarity index 100% rename from sunone_aimbot_cpp/imgui/imconfig.h rename to RN_AI_cpp/imgui/imconfig.h diff --git a/sunone_aimbot_cpp/imgui/imgui.cpp b/RN_AI_cpp/imgui/imgui.cpp similarity index 100% rename from sunone_aimbot_cpp/imgui/imgui.cpp rename to RN_AI_cpp/imgui/imgui.cpp diff --git a/sunone_aimbot_cpp/imgui/imgui.h b/RN_AI_cpp/imgui/imgui.h similarity index 100% rename from sunone_aimbot_cpp/imgui/imgui.h rename to RN_AI_cpp/imgui/imgui.h diff --git a/sunone_aimbot_cpp/imgui/imgui_draw.cpp b/RN_AI_cpp/imgui/imgui_draw.cpp similarity index 100% rename from sunone_aimbot_cpp/imgui/imgui_draw.cpp rename to RN_AI_cpp/imgui/imgui_draw.cpp diff --git a/sunone_aimbot_cpp/imgui/imgui_impl_dx11.cpp b/RN_AI_cpp/imgui/imgui_impl_dx11.cpp similarity index 100% rename from sunone_aimbot_cpp/imgui/imgui_impl_dx11.cpp rename to RN_AI_cpp/imgui/imgui_impl_dx11.cpp diff --git a/sunone_aimbot_cpp/imgui/imgui_impl_dx11.h b/RN_AI_cpp/imgui/imgui_impl_dx11.h similarity index 100% rename from sunone_aimbot_cpp/imgui/imgui_impl_dx11.h rename to RN_AI_cpp/imgui/imgui_impl_dx11.h diff --git a/sunone_aimbot_cpp/imgui/imgui_impl_win32.cpp b/RN_AI_cpp/imgui/imgui_impl_win32.cpp similarity index 100% rename from sunone_aimbot_cpp/imgui/imgui_impl_win32.cpp rename to RN_AI_cpp/imgui/imgui_impl_win32.cpp diff --git a/sunone_aimbot_cpp/imgui/imgui_impl_win32.h b/RN_AI_cpp/imgui/imgui_impl_win32.h similarity index 100% rename from sunone_aimbot_cpp/imgui/imgui_impl_win32.h rename to RN_AI_cpp/imgui/imgui_impl_win32.h diff --git a/sunone_aimbot_cpp/imgui/imgui_internal.h b/RN_AI_cpp/imgui/imgui_internal.h similarity index 100% rename from sunone_aimbot_cpp/imgui/imgui_internal.h rename to RN_AI_cpp/imgui/imgui_internal.h diff --git a/sunone_aimbot_cpp/imgui/imgui_tables.cpp b/RN_AI_cpp/imgui/imgui_tables.cpp similarity index 100% rename from sunone_aimbot_cpp/imgui/imgui_tables.cpp rename to RN_AI_cpp/imgui/imgui_tables.cpp diff --git a/sunone_aimbot_cpp/imgui/imgui_widgets.cpp b/RN_AI_cpp/imgui/imgui_widgets.cpp similarity index 100% rename from sunone_aimbot_cpp/imgui/imgui_widgets.cpp rename to RN_AI_cpp/imgui/imgui_widgets.cpp diff --git a/sunone_aimbot_cpp/imgui/imstb_rectpack.h b/RN_AI_cpp/imgui/imstb_rectpack.h similarity index 100% rename from sunone_aimbot_cpp/imgui/imstb_rectpack.h rename to RN_AI_cpp/imgui/imstb_rectpack.h diff --git a/sunone_aimbot_cpp/imgui/imstb_textedit.h b/RN_AI_cpp/imgui/imstb_textedit.h similarity index 100% rename from sunone_aimbot_cpp/imgui/imstb_textedit.h rename to RN_AI_cpp/imgui/imstb_textedit.h diff --git a/sunone_aimbot_cpp/imgui/imstb_truetype.h b/RN_AI_cpp/imgui/imstb_truetype.h similarity index 100% rename from sunone_aimbot_cpp/imgui/imstb_truetype.h rename to RN_AI_cpp/imgui/imstb_truetype.h diff --git a/sunone_aimbot_cpp/include/memory_images.h b/RN_AI_cpp/include/memory_images.h similarity index 100% rename from sunone_aimbot_cpp/include/memory_images.h rename to RN_AI_cpp/include/memory_images.h diff --git a/sunone_aimbot_cpp/include/other_tools.h b/RN_AI_cpp/include/other_tools.h similarity index 100% rename from sunone_aimbot_cpp/include/other_tools.h rename to RN_AI_cpp/include/other_tools.h diff --git a/sunone_aimbot_cpp/keyboard/keyboard_listener.cpp b/RN_AI_cpp/keyboard/keyboard_listener.cpp similarity index 68% rename from sunone_aimbot_cpp/keyboard/keyboard_listener.cpp rename to RN_AI_cpp/keyboard/keyboard_listener.cpp index 91810536..f83f0d9e 100644 --- a/sunone_aimbot_cpp/keyboard/keyboard_listener.cpp +++ b/RN_AI_cpp/keyboard/keyboard_listener.cpp @@ -1,4 +1,4 @@ -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #define _WINSOCKAPI_ #include #include @@ -13,7 +13,7 @@ #include "keyboard_listener.h" #include "mouse.h" #include "keycodes.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "capture.h" #include "KmboxNetConnection.h" @@ -45,6 +45,12 @@ bool prevRightArrow = false; bool isAnyKeyPressed(const std::vector& keys) { + bool usePhysicalDevice = + (kmboxNetSerial && kmboxNetSerial->isOpen()) || + (kmboxSerial && kmboxSerial->isOpen()) || + (makcu_conn && makcu_conn->isOpen()) || + (config.arduino_enable_keys && arduinoSerial && arduinoSerial->isOpen()); + for (const auto& key_name : keys) { int key_code = KeyCodes::getKeyCode(key_name); @@ -61,15 +67,54 @@ bool isAnyKeyPressed(const std::vector& keys) else if(key_name == "X2MouseButton") pressed = kmboxNetSerial->monitorMouseSide2() == 1; } - // local mouse - if (!pressed && key_code != -1 && (GetAsyncKeyState(key_code) & 0x8000)) - pressed = true; + // kmbox_b button monitor + if (!pressed && kmboxSerial && kmboxSerial->isOpen()) + { + if (key_name == "LeftMouseButton") pressed = kmboxSerial->left_active; + else if(key_name == "RightMouseButton") pressed = kmboxSerial->right_active; + else if(key_name == "MiddleMouseButton") pressed = kmboxSerial->middle_active; + else if(key_name == "X1MouseButton") pressed = kmboxSerial->side1_active; + else if(key_name == "X2MouseButton") pressed = kmboxSerial->side2_active; + } + + // makcu button monitor + if (!pressed && makcu_conn && makcu_conn->isOpen()) + { + if (key_name == "LeftMouseButton") pressed = makcu_conn->left_active; + else if(key_name == "RightMouseButton") pressed = makcu_conn->right_active; + else if(key_name == "MiddleMouseButton") pressed = makcu_conn->middle_active; + else if(key_name == "X1MouseButton") pressed = makcu_conn->side1_active; + else if(key_name == "X2MouseButton") pressed = makcu_conn->side2_active; + } + + // arduino button monitor + if (!pressed && config.arduino_enable_keys && arduinoSerial && arduinoSerial->isOpen()) + { + if (key_name == "LeftMouseButton") pressed = arduinoSerial->shooting_active; + else if(key_name == "RightMouseButton") pressed = arduinoSerial->zooming_active; + else if(key_name == "X2MouseButton") pressed = arduinoSerial->aiming_active; + } + + // local win32 keyboard/mouse + if (!pressed && key_code != -1) + { + const bool is_mouse_key = + (key_name == "LeftMouseButton") || + (key_name == "RightMouseButton") || + (key_name == "MiddleMouseButton") || + (key_name == "X1MouseButton") || + (key_name == "X2MouseButton"); + + if (!is_mouse_key || !usePhysicalDevice) + { + pressed = (GetAsyncKeyState(key_code) & 0x8000) != 0; + } + } if (pressed) return true; } return false; } - void keyboardListener() { while (!shouldExit) @@ -77,33 +122,22 @@ void keyboardListener() // Aiming if (!config.auto_aim) { - aiming = isAnyKeyPressed(config.button_targeting) || - (config.arduino_enable_keys && arduinoSerial && arduinoSerial->isOpen() && arduinoSerial->aiming_active) || - (kmboxSerial && kmboxSerial->isOpen() && kmboxSerial->aiming_active) || - (kmboxNetSerial && kmboxNetSerial->isOpen() && kmboxNetSerial->aiming_active); + // Respect only configured targeting keys (from UI/config). + aiming = isAnyKeyPressed(config.button_targeting); } else { aiming = true; } - // Shooting - shooting = isAnyKeyPressed(config.button_shoot) || - (config.arduino_enable_keys && arduinoSerial && arduinoSerial->isOpen() && arduinoSerial->shooting_active) || - (kmboxSerial && kmboxSerial->isOpen() && kmboxSerial->shooting_active) || - (kmboxNetSerial && kmboxNetSerial->isOpen() && kmboxNetSerial->shooting_active); + // Respect only configured key lists for shoot/zoom as well. + shooting = isAnyKeyPressed(config.button_shoot); + zooming = isAnyKeyPressed(config.button_zoom); - // Zooming - zooming = isAnyKeyPressed(config.button_zoom) || - (config.arduino_enable_keys && arduinoSerial && arduinoSerial->isOpen() && arduinoSerial->zooming_active) || - (kmboxSerial && kmboxSerial->isOpen() && kmboxSerial->zooming_active); - - // Triggerbot button (клавиатура/макку дополняют состояние, которое ставит kmbox_b) + // Triggerbot button should reflect current physical state (no latch). { - const bool kb_trigger = isAnyKeyPressed(config.button_triggerbot); - const bool makcu_trigger = (makcu && makcu->isOpen() && makcu->triggerbot_active); - const bool current = triggerbot_button.load(); - triggerbot_button = current || kb_trigger || makcu_trigger; + const bool trigger_pressed = isAnyKeyPressed(config.button_triggerbot); + triggerbot_button.store(trigger_pressed); } // Disable Headshot toggle @@ -234,3 +268,7 @@ void keyboardListener() std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } + + + + diff --git a/sunone_aimbot_cpp/keyboard/keyboard_listener.h b/RN_AI_cpp/keyboard/keyboard_listener.h similarity index 100% rename from sunone_aimbot_cpp/keyboard/keyboard_listener.h rename to RN_AI_cpp/keyboard/keyboard_listener.h diff --git a/sunone_aimbot_cpp/keyboard/keycodes.cpp b/RN_AI_cpp/keyboard/keycodes.cpp similarity index 100% rename from sunone_aimbot_cpp/keyboard/keycodes.cpp rename to RN_AI_cpp/keyboard/keycodes.cpp diff --git a/sunone_aimbot_cpp/keyboard/keycodes.h b/RN_AI_cpp/keyboard/keycodes.h similarity index 100% rename from sunone_aimbot_cpp/keyboard/keycodes.h rename to RN_AI_cpp/keyboard/keycodes.h diff --git a/sunone_aimbot_cpp/manual_map_injector.cpp b/RN_AI_cpp/manual_map_injector.cpp similarity index 100% rename from sunone_aimbot_cpp/manual_map_injector.cpp rename to RN_AI_cpp/manual_map_injector.cpp diff --git a/RN_AI_cpp/models/sunxds_0.5.6.engine b/RN_AI_cpp/models/sunxds_0.5.6.engine new file mode 100644 index 00000000..155d9c86 Binary files /dev/null and b/RN_AI_cpp/models/sunxds_0.5.6.engine differ diff --git a/RN_AI_cpp/models/sunxds_0.5.6.onnx b/RN_AI_cpp/models/sunxds_0.5.6.onnx new file mode 100644 index 00000000..96bcc324 Binary files /dev/null and b/RN_AI_cpp/models/sunxds_0.5.6.onnx differ diff --git a/RN_AI_cpp/models/sunxds_0.7.6.engine b/RN_AI_cpp/models/sunxds_0.7.6.engine new file mode 100644 index 00000000..fe640d7c Binary files /dev/null and b/RN_AI_cpp/models/sunxds_0.7.6.engine differ diff --git a/RN_AI_cpp/models/sunxds_0.7.6.onnx b/RN_AI_cpp/models/sunxds_0.7.6.onnx new file mode 100644 index 00000000..2776bec5 Binary files /dev/null and b/RN_AI_cpp/models/sunxds_0.7.6.onnx differ diff --git a/sunone_aimbot_cpp/mouse/AimbotTarget.cpp b/RN_AI_cpp/mouse/AimbotTarget.cpp similarity index 99% rename from sunone_aimbot_cpp/mouse/AimbotTarget.cpp rename to RN_AI_cpp/mouse/AimbotTarget.cpp index 9eeb753b..c5f6977f 100644 --- a/sunone_aimbot_cpp/mouse/AimbotTarget.cpp +++ b/RN_AI_cpp/mouse/AimbotTarget.cpp @@ -7,7 +7,7 @@ #include #include -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "AimbotTarget.h" #include "config.h" diff --git a/sunone_aimbot_cpp/mouse/AimbotTarget.h b/RN_AI_cpp/mouse/AimbotTarget.h similarity index 100% rename from sunone_aimbot_cpp/mouse/AimbotTarget.h rename to RN_AI_cpp/mouse/AimbotTarget.h diff --git a/sunone_aimbot_cpp/mouse/Kmbox_b.cpp b/RN_AI_cpp/mouse/Kmbox_b.cpp similarity index 70% rename from sunone_aimbot_cpp/mouse/Kmbox_b.cpp rename to RN_AI_cpp/mouse/Kmbox_b.cpp index 5e711501..671867d3 100644 --- a/sunone_aimbot_cpp/mouse/Kmbox_b.cpp +++ b/RN_AI_cpp/mouse/Kmbox_b.cpp @@ -8,13 +8,13 @@ #include "Kmbox_b.h" #include "config.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" -/* ---------------- Makcu-константы ---------------- */ -static const uint32_t BOOT_BAUD = 115200; // при подключении -static const uint32_t WORK_BAUD = 4000000; // рабочая 4 Мбит/с +/* ---------------- Makcu-????????? ---------------- */ +static const uint32_t BOOT_BAUD = 115200; // ??? ??????????? +static const uint32_t WORK_BAUD = 4000000; // ??????? 4 ????/? -/* секретный пакет смены скорости */ +/* ????????? ????? ????? ???????? */ static const uint8_t BAUD_CHANGE_CMD[9] = { 0xDE,0xAD,0x05,0x00,0xA5,0x00,0x09,0x3D,0x00 }; @@ -25,22 +25,27 @@ KmboxConnection::KmboxConnection(const std::string& port, unsigned int /*baud_ra listening_(false), aiming_active(false), shooting_active(false), - zooming_active(false) + zooming_active(false), + side1_active(false), + side2_active(false), + left_active(false), + right_active(false), + middle_active(false) { try { - /* 1. открываем порт @115 200 */ + /* 1. ????????? ???? @115 200 */ serial_.setPort(port); serial_.setBaudrate(BOOT_BAUD); serial_.open(); if (!serial_.isOpen()) throw std::runtime_error("open failed"); - /* 2. посылаем пакет — MCU перезапускается @4 Мбит */ + /* 2. ???????? ????? — MCU ??????????????? @4 ???? */ serial_.write(BAUD_CHANGE_CMD, sizeof(BAUD_CHANGE_CMD)); serial_.close(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); - /* 3. открываем заново @4 Мбит */ + /* 3. ????????? ?????? @4 ???? */ serial_.setBaudrate(WORK_BAUD); serial_.open(); if (!serial_.isOpen()) @@ -49,7 +54,7 @@ KmboxConnection::KmboxConnection(const std::string& port, unsigned int /*baud_ra is_open_ = true; std::cout << "[Makcu] Connected @4 Mbps on " << port << '\n'; - /* 4. убираем echo и включаем поток кнопок */ + /* 4. ??????? echo ? ???????? ????? ?????? */ sendCommand("km.echo(0)"); sendCommand("km.buttons(1)"); @@ -97,7 +102,7 @@ std::string KmboxConnection::read() return {}; } -/* --- команды km.* ---------------------------------------------------- */ +/* --- ??????? km.* ---------------------------------------------------- */ void KmboxConnection::move(int x, int y) { @@ -133,7 +138,7 @@ void KmboxConnection::sendCommand(const std::string& cmd) { write(cmd + "\r\n"); std::vector KmboxConnection::splitValue(int value) { return {}; } -/* --------------------------- Слушатель -------------------------- */ +/* --------------------------- ????????? -------------------------- */ void KmboxConnection::startListening() { @@ -145,14 +150,8 @@ void KmboxConnection::startListening() void KmboxConnection::listeningThreadFunc() { - // биты 0..5: ЛКМ/ПКМ/СКМ/Side4/Side5 (+ запас 0x20) - constexpr uint8_t button_mask = 0x3F; - auto popcount8 = [](uint8_t v) { - v = (v & 0x55) + ((v >> 1) & 0x55); - v = (v & 0x33) + ((v >> 2) & 0x33); - return static_cast((v + (v >> 4)) & 0x0F); - }; - uint8_t last_buttons = 0; + // allowed bits: 0x01 (LMB), 0x02 (RMB), 0x10 (side2) + constexpr uint8_t allowed_mask = 0x01 | 0x02 | 0x10; while (listening_ && is_open_) { try { @@ -163,30 +162,25 @@ void KmboxConnection::listeningThreadFunc() uint8_t b = 0; serial_.read(&b, 1); - const uint8_t filtered = b & button_mask; - const int bit_cnt = popcount8(filtered); - const bool valid_empty = filtered == 0x00; - const bool valid_single = (filtered <= 0x1F) && (bit_cnt == 1); - - if (valid_empty) { - last_buttons = 0; - } - else if (valid_single) { - last_buttons = filtered; - } - else { - // шумовой пакет — не трогаем состояние + // drop byte if it contains unexpected bits + if (b & ~allowed_mask) continue; - } - /* обновляем флаги */ - shooting_active = last_buttons & 0x01; // ЛКМ - aiming_active = last_buttons & 0x10; // боковая (mouse5) - triggerbot_button.store(static_cast(last_buttons & 0x08)); // mouse4 -> триггербот + // update state flags + shooting_active = (b & 0x01) != 0; // LMB + zooming_active = (b & 0x02) != 0; // RMB + aiming_active = (b & 0x10) != 0; // side2 + + left_active = shooting_active; + right_active = zooming_active; + middle_active = false; + side1_active = false; + side2_active = aiming_active; + shooting.store(shooting_active); aiming.store(aiming_active); - /* отладочный вывод */ + // debug output std::cout << "LMB: " << (shooting_active ? "PRESS" : "release") << " | SIDE: " << (aiming_active ? "PRESS" : "release") << '\n'; @@ -195,7 +189,7 @@ void KmboxConnection::listeningThreadFunc() } } -/* ---------- старый парсер строк (остаётся без изменений) ------------- */ +/* ---------- ?????? ?????? ????? (???????? ??? ?????????) ------------- */ void KmboxConnection::processIncomingLine(const std::string& line) { try { diff --git a/sunone_aimbot_cpp/mouse/Kmbox_b.h b/RN_AI_cpp/mouse/Kmbox_b.h similarity index 90% rename from sunone_aimbot_cpp/mouse/Kmbox_b.h rename to RN_AI_cpp/mouse/Kmbox_b.h index bd0e101b..e0b22c9a 100644 --- a/sunone_aimbot_cpp/mouse/Kmbox_b.h +++ b/RN_AI_cpp/mouse/Kmbox_b.h @@ -35,6 +35,11 @@ class KmboxConnection bool aiming_active; bool shooting_active; bool zooming_active; + bool side1_active; + bool side2_active; + bool left_active; + bool right_active; + bool middle_active; private: void sendCommand(const std::string& command); @@ -53,3 +58,6 @@ class KmboxConnection }; #endif // KMBOXCONNECTION_H + + + diff --git a/RN_AI_cpp/mouse/MakcuConnection.cpp b/RN_AI_cpp/mouse/MakcuConnection.cpp new file mode 100644 index 00000000..89776d79 --- /dev/null +++ b/RN_AI_cpp/mouse/MakcuConnection.cpp @@ -0,0 +1,691 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MakcuConnection.h" +#include "config.h" +#include "rn_ai_cpp.h" +#ifdef makcu +#undef makcu +#endif + +namespace { +std::mutex g_makcu_state_log_mutex; + +void logMakcuButtons(const char* source, const MakcuConnection& connection, int raw_value = -1) +{ + std::lock_guard lock(g_makcu_state_log_mutex); + std::cout << "[Makcu][" << source << "]"; + if (raw_value >= 0) { + std::cout << " raw=" << raw_value; + } + std::cout + << " L=" << (connection.left_active ? 1 : 0) + << " R=" << (connection.right_active ? 1 : 0) + << " M=" << (connection.middle_active ? 1 : 0) + << " S1=" << (connection.side1_active ? 1 : 0) + << " S2=" << (connection.side2_active ? 1 : 0) + << " shoot=" << (connection.shooting_active ? 1 : 0) + << " aim=" << (connection.aiming_active ? 1 : 0) + << " zoom=" << (connection.zooming_active ? 1 : 0) + << " trig=" << (connection.triggerbot_active ? 1 : 0) + << std::endl; +} +} // namespace + +#if RN_MAKCU_SDK_AVAILABLE + +MakcuConnection::MakcuConnection(const std::string& port, unsigned int baud_rate) + : is_open_(false) + , sdk_listening_(false) + , aiming_active(false) + , shooting_active(false) + , zooming_active(false) + , triggerbot_active(false) + , side1_active(false) + , side2_active(false) + , left_active(false) + , right_active(false) + , middle_active(false) +{ + try + { + device_.setMouseButtonCallback([this](makcu::MouseButton button, bool pressed) { + onButtonCallback(button, pressed); + }); + + device_.enableButtonMonitoring(true); + + if (device_.connect(port)) + { + if (baud_rate > 0) + { + if (!device_.setBaudRate(baud_rate, true)) + { + std::cerr << "[Makcu] Failed to set baud rate to " << baud_rate + << ", continuing with current baud rate." << std::endl; + } + } + + is_open_ = true; + std::cout << "[Makcu] Connected! PORT: " << port << std::endl; + startSdkPolling(); + } + else + { + std::cerr << "[Makcu] Unable to connect to the port: " << port << std::endl; + } + } + catch (const makcu::MakcuException& e) + { + std::cerr << "[Makcu] Error: " << e.what() << std::endl; + } + catch (const std::exception& e) + { + std::cerr << "[Makcu] Error: " << e.what() << std::endl; + } +} + +MakcuConnection::~MakcuConnection() +{ + stopSdkPolling(); + try + { + device_.enableButtonMonitoring(false); + device_.disconnect(); + } + catch (...) + { + } + is_open_ = false; +} + +bool MakcuConnection::isOpen() const +{ + return is_open_ && device_.isConnected(); +} + +void MakcuConnection::write(const std::string&) +{ +} + +std::string MakcuConnection::read() +{ + return std::string(); +} + +void MakcuConnection::move(int x, int y) +{ + if (!isOpen()) + return; + + std::lock_guard lock(write_mutex_); + try + { + device_.mouseMove(x, y); + } + catch (...) + { + is_open_ = false; + } +} + +makcu::MouseButton MakcuConnection::toMouseButton(int button) const +{ + switch (button) + { + case 1: return makcu::MouseButton::RIGHT; + case 2: return makcu::MouseButton::MIDDLE; + case 3: return makcu::MouseButton::SIDE1; + case 4: return makcu::MouseButton::SIDE2; + case 0: + default: + return makcu::MouseButton::LEFT; + } +} + +void MakcuConnection::click(int button) +{ + if (!isOpen()) + return; + + std::lock_guard lock(write_mutex_); + try + { + device_.click(toMouseButton(button)); + } + catch (...) + { + is_open_ = false; + } +} + +void MakcuConnection::press(int button) +{ + if (!isOpen()) + return; + + std::lock_guard lock(write_mutex_); + try + { + device_.mouseDown(toMouseButton(button)); + } + catch (...) + { + is_open_ = false; + } +} + +void MakcuConnection::release(int button) +{ + if (!isOpen()) + return; + + std::lock_guard lock(write_mutex_); + try + { + device_.mouseUp(toMouseButton(button)); + } + catch (...) + { + is_open_ = false; + } +} + +void MakcuConnection::start_boot() +{ +} + +void MakcuConnection::reboot() +{ +} + +void MakcuConnection::send_stop() +{ +} + +void MakcuConnection::onButtonCallback(makcu::MouseButton button, bool pressed) +{ + switch (button) + { + case makcu::MouseButton::LEFT: + left_active = pressed; + shooting_active = pressed; + shooting.store(pressed); + break; + + case makcu::MouseButton::RIGHT: + right_active = pressed; + zooming_active = pressed; + zooming.store(pressed); + break; + + case makcu::MouseButton::MIDDLE: + middle_active = pressed; + break; + + case makcu::MouseButton::SIDE1: + side1_active = pressed; + triggerbot_active = pressed; + triggerbot_button.store(pressed); + break; + + case makcu::MouseButton::SIDE2: + side2_active = pressed; + aiming_active = pressed; + aiming.store(pressed); + break; + + default: + break; + } + + logMakcuButtons("callback", *this, static_cast(button)); +} + +void MakcuConnection::applyButtonMask(uint8_t mask, const char* source) +{ + left_active = (mask & 0x01) != 0; + right_active = (mask & 0x02) != 0; + middle_active = (mask & 0x04) != 0; + side1_active = (mask & 0x08) != 0; + side2_active = (mask & 0x10) != 0; + + shooting_active = left_active; + zooming_active = right_active; + triggerbot_active = side1_active; + aiming_active = side2_active; + + shooting.store(shooting_active); + zooming.store(zooming_active); + triggerbot_button.store(triggerbot_active); + aiming.store(aiming_active); + + logMakcuButtons(source, *this, static_cast(mask)); +} + +void MakcuConnection::startSdkPolling() +{ + sdk_listening_ = true; + if (sdk_listening_thread_.joinable()) + sdk_listening_thread_.join(); + sdk_listening_thread_ = std::thread(&MakcuConnection::sdkPollingThreadFunc, this); +} + +void MakcuConnection::stopSdkPolling() +{ + sdk_listening_ = false; + if (sdk_listening_thread_.joinable()) + sdk_listening_thread_.join(); +} + +void MakcuConnection::sdkPollingThreadFunc() +{ + uint8_t last_mask = 0xFF; + while (sdk_listening_ && isOpen()) + { + try + { + const uint8_t mask = device_.getButtonMask(); + if (mask != last_mask) + { + applyButtonMask(mask, "sdk-mask"); + last_mask = mask; + } + } + catch (...) + { + is_open_ = false; + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } +} + +#else + +/* ---------- Serial fallback constants ---------------------------- */ +static const uint32_t BOOT_BAUD = 115200; +static const uint32_t WORK_BAUD = 4000000; +static const uint8_t FRAME_START = 0x50; + +static const uint8_t BAUD_CHANGE_CMD[9] = +{ 0xDE, 0xAD, 0x05, 0x00, 0xA5, 0x00, 0x09, 0x3D, 0x00 }; + +static const uint8_t CMD_LEFT = 0x08; +static const uint8_t CMD_RIGHT = 0x11; +static const uint8_t CMD_MIDDLE = 0x0A; +static const uint8_t CMD_SIDE1 = 0x12; +static const uint8_t CMD_SIDE2 = 0x13; + +MakcuConnection::MakcuConnection(const std::string& port, unsigned int /*baud_rate*/) + : is_open_(false) + , listening_(false) + , aiming_active(false) + , shooting_active(false) + , zooming_active(false) + , triggerbot_active(false) + , side1_active(false) + , side2_active(false) + , left_active(false) + , right_active(false) + , middle_active(false) +{ + std::cerr << "[Makcu] SDK header not found. Using serial fallback (byte parser)." << std::endl; + + try { + serial_.setPort(port); + serial_.setBaudrate(BOOT_BAUD); + serial_.open(); + if (!serial_.isOpen()) + throw std::runtime_error("open failed"); + + serial_.write(BAUD_CHANGE_CMD, sizeof(BAUD_CHANGE_CMD)); + serial_.close(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + serial_.setBaudrate(WORK_BAUD); + serial_.open(); + if (!serial_.isOpen()) + throw std::runtime_error("re-open @4M failed"); + + is_open_ = true; + std::cout << "[Makcu] Connected @4 Mbps on " << port << '\n'; + + sendCommand("km.echo(0)"); + sendCommand("km.buttons(1)"); + + startListening(); + } + catch (const std::exception& e) { + std::cerr << "[Makcu] Error: " << e.what() << '\n'; + } +} + +MakcuConnection::~MakcuConnection() +{ + listening_ = false; + if (serial_.isOpen()) { + try { serial_.close(); } catch (...) {} + } + if (listening_thread_.joinable()) + listening_thread_.join(); + is_open_ = false; +} + +bool MakcuConnection::isOpen() const { return is_open_; } + +void MakcuConnection::write(const std::string& data) +{ + std::lock_guard lock(write_mutex_); + if (!is_open_) return; + try { serial_.write(data); } + catch (...) { is_open_ = false; } +} + +std::string MakcuConnection::read() +{ + if (!is_open_) + return std::string(); + + std::string result; + try + { + result = serial_.readline(65536, "\n"); + } + catch (...) + { + is_open_ = false; + } + return result; +} + +void MakcuConnection::move(int x, int y) +{ + if (!is_open_) + return; + + std::string cmd = "km.move(" + std::to_string(x) + "," + std::to_string(y) + ")\r\n"; + write(cmd); +} + +void MakcuConnection::click(int button) +{ + (void)button; + sendCommand("km.click(0)"); +} + +void MakcuConnection::press(int button) +{ + (void)button; + sendCommand("km.left(1)"); +} + +void MakcuConnection::release(int button) +{ + (void)button; + sendCommand("km.left(0)"); +} + +void MakcuConnection::start_boot() +{ + write("\x03\x03"); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + write("exec(open('boot.py').read(),globals())\r\n"); +} + +void MakcuConnection::reboot() +{ + write("\x03\x03"); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + write("km.reboot()"); +} + +void MakcuConnection::send_stop() +{ + write("\x03\x03"); +} + +void MakcuConnection::writeBinaryCommand(uint8_t cmd, const std::vector& payload) +{ + if (!is_open_) + return; + + const uint16_t len = static_cast(payload.size()); + std::vector frame; + frame.reserve(4 + payload.size()); + frame.push_back(FRAME_START); + frame.push_back(cmd); + frame.push_back(static_cast(len & 0xFF)); + frame.push_back(static_cast((len >> 8) & 0xFF)); + frame.insert(frame.end(), payload.begin(), payload.end()); + serial_.write(frame.data(), frame.size()); +} + +bool MakcuConnection::readBinaryFrame(uint8_t expected_cmd, std::vector& payload, int timeout_ms) +{ + payload.clear(); + auto deadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms); + + enum class ParseState { WaitStart, WaitCmd, WaitLenLo, WaitLenHi, WaitPayload }; + ParseState state = ParseState::WaitStart; + uint16_t length = 0; + size_t read_count = 0; + + while (std::chrono::steady_clock::now() < deadline) + { + if (!serial_.available()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + + uint8_t byte = 0; + serial_.read(&byte, 1); + + switch (state) + { + case ParseState::WaitStart: + if (byte == FRAME_START) + state = ParseState::WaitCmd; + break; + + case ParseState::WaitCmd: + if (byte != expected_cmd) + { + state = (byte == FRAME_START) ? ParseState::WaitCmd : ParseState::WaitStart; + break; + } + state = ParseState::WaitLenLo; + break; + + case ParseState::WaitLenLo: + length = byte; + state = ParseState::WaitLenHi; + break; + + case ParseState::WaitLenHi: + length |= static_cast(byte) << 8; + payload.assign(length, 0); + read_count = 0; + if (length == 0) + return true; + state = ParseState::WaitPayload; + break; + + case ParseState::WaitPayload: + payload[read_count++] = byte; + if (read_count >= length) + return true; + break; + } + } + + return false; +} + +bool MakcuConnection::queryButtonStateBinary(uint8_t cmd, bool& pressed) +{ + pressed = false; + if (!is_open_) + return false; + + try + { + std::lock_guard lock(write_mutex_); + writeBinaryCommand(cmd, {}); + + std::vector payload; + if (!readBinaryFrame(cmd, payload, 30)) + return false; + + if (payload.empty()) + return false; + + // 0=none, 1=raw, 2=injected, 3=both + pressed = payload[0] != 0; + return true; + } + catch (...) + { + is_open_ = false; + return false; + } +} + +void MakcuConnection::sendCommand(const std::string& cmd) { write(cmd + "\r\n"); } +std::vector MakcuConnection::splitValue(int) { return {}; } + +void MakcuConnection::startListening() +{ + listening_ = true; + if (listening_thread_.joinable()) + listening_thread_.join(); + + listening_thread_ = std::thread(&MakcuConnection::listeningThreadFunc, this); +} + +void MakcuConnection::listeningThreadFunc() +{ + // Kmbox-like parser logic for Makcu fallback. + // Allowed bits: 0x01 (LMB), 0x02 (RMB), 0x08 (side1 trigger), 0x10 (side2 aim) + constexpr uint8_t allowed_mask = 0x01 | 0x02 | 0x08 | 0x10; + + while (listening_ && is_open_) { + try { + if (!serial_.available()) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + + uint8_t b = 0; + serial_.read(&b, 1); + + // Drop byte if it contains unexpected bits. + if (b & ~allowed_mask) + continue; + + left_active = (b & 0x01) != 0; + right_active = (b & 0x02) != 0; + middle_active = false; + side1_active = (b & 0x08) != 0; + side2_active = (b & 0x10) != 0; + + shooting_active = left_active; + zooming_active = right_active; + triggerbot_active = side1_active; + aiming_active = side2_active; + + shooting.store(shooting_active); + zooming.store(zooming_active); + triggerbot_button.store(triggerbot_active); + aiming.store(aiming_active); + + logMakcuButtons("serial", *this, static_cast(b)); + + } + catch (...) { + is_open_ = false; + break; + } + } +} + +void MakcuConnection::processIncomingLine(const std::string& line) +{ + std::string token; + token.reserve(8); + + for (char ch : line) + { + const unsigned char c = static_cast(ch); + if (std::isdigit(c)) + { + token.push_back(static_cast(c)); + continue; + } + + if (!token.empty()) + break; + } + + if (token.empty()) + return; + + int value = -1; + try + { + value = std::stoi(token); + } + catch (...) + { + return; + } + + if (value < 0 || value > 63) + return; + + const uint8_t last_buttons = static_cast(value & 0x3F); + const uint8_t previous_buttons = static_cast((left_active ? 0x01 : 0x00) | + (right_active ? 0x02 : 0x00) | + (middle_active ? 0x04 : 0x00) | + (side1_active ? 0x08 : 0x00) | + (side2_active ? 0x10 : 0x00)); + + left_active = (last_buttons & 0x01) != 0; + right_active = (last_buttons & 0x02) != 0; + middle_active = (last_buttons & 0x04) != 0; + side1_active = (last_buttons & 0x08) != 0; + side2_active = (last_buttons & 0x10) != 0; + + shooting_active = left_active; + aiming_active = side2_active; + zooming_active = right_active; + triggerbot_active = side1_active; + + triggerbot_button.store(triggerbot_active); + shooting.store(shooting_active); + aiming.store(aiming_active); + zooming.store(zooming_active); + + const uint8_t current_buttons = static_cast((left_active ? 0x01 : 0x00) | + (right_active ? 0x02 : 0x00) | + (middle_active ? 0x04 : 0x00) | + (side1_active ? 0x08 : 0x00) | + (side2_active ? 0x10 : 0x00)); + + if (current_buttons != previous_buttons) + logMakcuButtons("serial", *this, value); +} + +#endif diff --git a/RN_AI_cpp/mouse/MakcuConnection.h b/RN_AI_cpp/mouse/MakcuConnection.h new file mode 100644 index 00000000..ad6b5352 --- /dev/null +++ b/RN_AI_cpp/mouse/MakcuConnection.h @@ -0,0 +1,80 @@ +#ifndef MAKCU_CONNECTION_H +#define MAKCU_CONNECTION_H + +#include +#include +#include +#include +#include + +#if __has_include("../modules/makcu/include/makcu.h") +#include "../modules/makcu/include/makcu.h" +#define RN_MAKCU_SDK_AVAILABLE 1 +#else +#define RN_MAKCU_SDK_AVAILABLE 0 +#include +#include "serial/serial.h" +#endif + +class MakcuConnection +{ +public: + MakcuConnection(const std::string& port, unsigned int baud_rate); + ~MakcuConnection(); + + bool isOpen() const; + + void write(const std::string& data); + std::string read(); + + void click(int button); + void press(int button); + void release(int button); + void move(int x, int y); + + void start_boot(); + void reboot(); + void send_stop(); + + bool aiming_active; + bool shooting_active; + bool zooming_active; + bool triggerbot_active; + bool side1_active; + bool side2_active; + bool left_active; + bool right_active; + bool middle_active; + +private: +#if RN_MAKCU_SDK_AVAILABLE + void startSdkPolling(); + void stopSdkPolling(); + void sdkPollingThreadFunc(); + void applyButtonMask(uint8_t mask, const char* source); + void onButtonCallback(makcu::MouseButton button, bool pressed); + makcu::MouseButton toMouseButton(int button) const; + makcu::Device device_; + std::atomic sdk_listening_; + std::thread sdk_listening_thread_; +#else + bool queryButtonStateBinary(uint8_t cmd, bool& pressed); + bool readBinaryFrame(uint8_t expected_cmd, std::vector& payload, int timeout_ms); + void writeBinaryCommand(uint8_t cmd, const std::vector& payload); + + void sendCommand(const std::string& command); + std::vector splitValue(int value); + void startListening(); + void listeningThreadFunc(); + void processIncomingLine(const std::string& line); + + serial::Serial serial_; + std::atomic listening_; + std::thread listening_thread_; +#endif + + std::atomic is_open_; + std::mutex write_mutex_; +}; + +#endif // MAKCU_CONNECTION_H diff --git a/sunone_aimbot_cpp/mouse/SerialConnection.cpp b/RN_AI_cpp/mouse/SerialConnection.cpp similarity index 99% rename from sunone_aimbot_cpp/mouse/SerialConnection.cpp rename to RN_AI_cpp/mouse/SerialConnection.cpp index 852b888b..df579d39 100644 --- a/sunone_aimbot_cpp/mouse/SerialConnection.cpp +++ b/RN_AI_cpp/mouse/SerialConnection.cpp @@ -1,11 +1,11 @@ -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #define _WINSOCKAPI_ #include #include #include #include -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "SerialConnection.h" SerialConnection::SerialConnection(const std::string& port, unsigned int baud_rate) diff --git a/sunone_aimbot_cpp/mouse/SerialConnection.h b/RN_AI_cpp/mouse/SerialConnection.h similarity index 100% rename from sunone_aimbot_cpp/mouse/SerialConnection.h rename to RN_AI_cpp/mouse/SerialConnection.h diff --git a/sunone_aimbot_cpp/mouse/kmboxNetConnection.cpp b/RN_AI_cpp/mouse/kmboxNetConnection.cpp similarity index 99% rename from sunone_aimbot_cpp/mouse/kmboxNetConnection.cpp rename to RN_AI_cpp/mouse/kmboxNetConnection.cpp index dffb174a..8f010ed8 100644 --- a/sunone_aimbot_cpp/mouse/kmboxNetConnection.cpp +++ b/RN_AI_cpp/mouse/kmboxNetConnection.cpp @@ -4,7 +4,7 @@ #include "kmbox_net/kmboxNet.h" #include "KmboxNetConnection.h" -#include +#include KmboxNetConnection::KmboxNetConnection(const std::string& ip, const std::string& port, const std::string& uuid) : is_open_(false), ip_(ip), port_(port), uuid_(uuid), monitor_(false) diff --git a/sunone_aimbot_cpp/mouse/kmboxNetConnection.h b/RN_AI_cpp/mouse/kmboxNetConnection.h similarity index 100% rename from sunone_aimbot_cpp/mouse/kmboxNetConnection.h rename to RN_AI_cpp/mouse/kmboxNetConnection.h diff --git a/sunone_aimbot_cpp/mouse/kmbox_net/HidTable.h b/RN_AI_cpp/mouse/kmbox_net/HidTable.h similarity index 100% rename from sunone_aimbot_cpp/mouse/kmbox_net/HidTable.h rename to RN_AI_cpp/mouse/kmbox_net/HidTable.h diff --git a/sunone_aimbot_cpp/mouse/kmbox_net/kmboxNet.cpp b/RN_AI_cpp/mouse/kmbox_net/kmboxNet.cpp similarity index 100% rename from sunone_aimbot_cpp/mouse/kmbox_net/kmboxNet.cpp rename to RN_AI_cpp/mouse/kmbox_net/kmboxNet.cpp diff --git a/sunone_aimbot_cpp/mouse/kmbox_net/kmboxNet.h b/RN_AI_cpp/mouse/kmbox_net/kmboxNet.h similarity index 100% rename from sunone_aimbot_cpp/mouse/kmbox_net/kmboxNet.h rename to RN_AI_cpp/mouse/kmbox_net/kmboxNet.h diff --git a/sunone_aimbot_cpp/mouse/kmbox_net/picture.h b/RN_AI_cpp/mouse/kmbox_net/picture.h similarity index 100% rename from sunone_aimbot_cpp/mouse/kmbox_net/picture.h rename to RN_AI_cpp/mouse/kmbox_net/picture.h diff --git a/RN_AI_cpp/mouse/mouse.cpp b/RN_AI_cpp/mouse/mouse.cpp new file mode 100644 index 00000000..3ae7ba17 --- /dev/null +++ b/RN_AI_cpp/mouse/mouse.cpp @@ -0,0 +1,1163 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include +#include + +#include "mouse.h" +#include "capture.h" +#include "SerialConnection.h" +#include "rn_ai_cpp.h" +#ifdef makcu +#undef makcu +#endif + +MouseThread::MouseThread( + int resolution, + int fovX, + int fovY, + double minSpeedMultiplier, + double maxSpeedMultiplier, + double predictionInterval, + bool auto_shoot, + float bScope_multiplier, + float triggerbot_bScope_multiplier, + SerialConnection* serialConnection, + KmboxConnection* kmboxConnection, + KmboxNetConnection* Kmbox_Net_Connection, + MakcuConnection* makcu) + : screen_width(resolution), + screen_height(resolution), + prediction_interval(predictionInterval), + fov_x(fovX), + fov_y(fovY), + max_distance(std::hypot(resolution, resolution) / 2.0), + min_speed_multiplier(minSpeedMultiplier), + max_speed_multiplier(maxSpeedMultiplier), + center_x(resolution / 2.0), + center_y(resolution / 2.0), + auto_shoot(auto_shoot), + bScope_multiplier(bScope_multiplier), + triggerbot_bScope_multiplier(triggerbot_bScope_multiplier), + serial(serialConnection), + kmbox(kmboxConnection), + kmbox_net(Kmbox_Net_Connection), + makcu(makcu), + + prev_velocity_x(0.0), + prev_velocity_y(0.0), + prev_x(0.0), + prev_y(0.0) +{ + prev_time = std::chrono::steady_clock::time_point(); + last_target_time = std::chrono::steady_clock::now(); + + wind_mouse_enabled = config.wind_mouse_enabled; + wind_G = config.wind_G; + wind_W = config.wind_W; + wind_M = config.wind_M; + wind_D = config.wind_D; + + use_smoothing = config.use_smoothing; + use_kalman = config.use_kalman; + + kfX = Kalman1D(config.kalman_process_noise, config.kalman_measurement_noise); + kfY = Kalman1D(config.kalman_process_noise, config.kalman_measurement_noise); + last_kalman_q = config.kalman_process_noise; + last_kalman_r = config.kalman_measurement_noise; + + last_prediction_q = config.prediction_kalman_process_noise; + last_prediction_r = config.prediction_kalman_measurement_noise; + resetAimState(); + + moveWorker = std::thread(&MouseThread::moveWorkerLoop, this); +} + +void MouseThread::updateConfig( + int resolution, + int fovX, + int fovY, + double minSpeedMultiplier, + double maxSpeedMultiplier, + double predictionInterval, + bool auto_shoot, + float bScope_multiplier, + float triggerbot_bScope_multiplier +) +{ + screen_width = screen_height = resolution; + fov_x = fovX; fov_y = fovY; + min_speed_multiplier = minSpeedMultiplier; + max_speed_multiplier = maxSpeedMultiplier; + prediction_interval = predictionInterval; + this->auto_shoot = auto_shoot; + this->bScope_multiplier = bScope_multiplier; + this->triggerbot_bScope_multiplier = triggerbot_bScope_multiplier; + + center_x = center_y = resolution / 2.0; + max_distance = std::hypot(resolution, resolution) / 2.0; + + wind_mouse_enabled = config.wind_mouse_enabled; + wind_G = config.wind_G; wind_W = config.wind_W; + wind_M = config.wind_M; wind_D = config.wind_D; + + use_smoothing = config.use_smoothing; + use_kalman = config.use_kalman; + + kfX = Kalman1D(config.kalman_process_noise, config.kalman_measurement_noise); + kfY = Kalman1D(config.kalman_process_noise, config.kalman_measurement_noise); + last_kalman_q = config.kalman_process_noise; + last_kalman_r = config.kalman_measurement_noise; + +} + +MouseThread::~MouseThread() +{ + workerStop = true; + queueCv.notify_all(); + if (moveWorker.joinable()) moveWorker.join(); +} + +void MouseThread::queueMove(int dx, int dy) +{ + std::lock_guard lg(queueMtx); + if (moveQueue.size() >= queueLimit) moveQueue.pop(); + moveQueue.push({ dx,dy }); + queueCv.notify_one(); +} + +void MouseThread::moveWorkerLoop() +{ + while (!workerStop) + { + std::unique_lock ul(queueMtx); + queueCv.wait(ul, [&] { return workerStop || !moveQueue.empty(); }); + + while (!moveQueue.empty()) + { + Move m = moveQueue.front(); + moveQueue.pop(); + ul.unlock(); + sendMovementToDriver(m.dx, m.dy); + ul.lock(); + } + } +} + +void MouseThread::windMouseMoveRelative(int dx, int dy) +{ + if (dx == 0 && dy == 0) return; + + constexpr double SQRT3 = 1.7320508075688772; + constexpr double SQRT5 = 2.23606797749979; + + double sx = 0, sy = 0; + double dxF = static_cast(dx); + double dyF = static_cast(dy); + double vx = 0, vy = 0, wX = 0, wY = 0; + int cx = 0, cy = 0; + + while (std::hypot(dxF - sx, dyF - sy) >= 1.0) + { + double dist = std::hypot(dxF - sx, dyF - sy); + double wMag = std::min(wind_W, dist); + + if (dist >= wind_D) + { + wX = wX / SQRT3 + ((double)rand() / RAND_MAX * 2.0 - 1.0) * wMag / SQRT5; + wY = wY / SQRT3 + ((double)rand() / RAND_MAX * 2.0 - 1.0) * wMag / SQRT5; + } + else + { + wX /= SQRT3; wY /= SQRT3; + wind_M = wind_M < 3.0 ? ((double)rand() / RAND_MAX) * 3.0 + 3.0 : wind_M / SQRT5; + } + + vx += wX + wind_G * (dxF - sx) / dist; + vy += wY + wind_G * (dyF - sy) / dist; + + double vMag = std::hypot(vx, vy); + if (vMag > wind_M) + { + double vClip = wind_M / 2.0 + ((double)rand() / RAND_MAX) * wind_M / 2.0; + vx = (vx / vMag) * vClip; + vy = (vy / vMag) * vClip; + } + + sx += vx; sy += vy; + int rx = static_cast(std::round(sx)); + int ry = static_cast(std::round(sy)); + int step_x = rx - cx; + int step_y = ry - cy; + if (step_x || step_y) + { + queueMove(step_x, step_y); + cx = rx; cy = ry; + } + } +} + +double MouseThread::clampValue(double v, double lo, double hi) +{ + return std::max(lo, std::min(hi, v)); +} + +void MouseThread::resetPredictionState() +{ + prediction_prev_time = std::chrono::steady_clock::time_point{}; + prediction_prev_x = 0.0; + prediction_prev_y = 0.0; + prediction_smoothed_velocity_x = 0.0; + prediction_smoothed_velocity_y = 0.0; + prediction_velocity_x = 0.0; + prediction_velocity_y = 0.0; + prediction_initialized = false; + prediction_kalman_time = std::chrono::steady_clock::time_point{}; + prediction_kalman_initialized = false; + last_prediction_mode = -1; + last_raw_velocity_x = 0.0; + last_raw_velocity_y = 0.0; + + double q = (last_prediction_q > 0.0) ? last_prediction_q : 0.01; + double r = (last_prediction_r > 0.0) ? last_prediction_r : 0.1; + prediction_kf_x = Kalman1D(q, r); + prediction_kf_y = Kalman1D(q, r); +} + +void MouseThread::resetKalmanState() +{ + kfX = Kalman1D(config.kalman_process_noise, config.kalman_measurement_noise); + kfY = Kalman1D(config.kalman_process_noise, config.kalman_measurement_noise); + prevKalmanTime = std::chrono::steady_clock::time_point{}; + kalman_smoothing_initialized = false; + last_raw_kalman_x = 0.0; + last_raw_kalman_y = 0.0; + last_kx = 0.0; + last_ky = 0.0; +} + +void MouseThread::resetSmoothingState() +{ + move_overflow_x = 0.0; + move_overflow_y = 0.0; + smooth_frame = 0; + smooth_start_x = 0.0; + smooth_start_y = 0.0; + smooth_prev_x = 0.0; + smooth_prev_y = 0.0; + smooth_last_tx = 0.0; + smooth_last_ty = 0.0; + + tracking_initialized = false; + track_x = 0.0; + track_y = 0.0; + track_prev_x = 0.0; + track_prev_y = 0.0; + track_time = std::chrono::steady_clock::time_point{}; + last_tracking_mode = -1; +} + +void MouseThread::resetAimState() +{ + prev_time = std::chrono::steady_clock::time_point{}; + prev_x = 0.0; + prev_y = 0.0; + prev_velocity_x = 0.0; + prev_velocity_y = 0.0; + last_target_time = std::chrono::steady_clock::time_point{}; + target_detected.store(false); + resetPredictionState(); + resetKalmanState(); + resetSmoothingState(); +} + +void MouseThread::markTargetSeen() +{ + last_target_time = std::chrono::steady_clock::now(); + target_detected.store(true); +} + +void MouseThread::resetIfStale(double timeout_s) +{ + if (!target_detected.load()) + return; + auto now = std::chrono::steady_clock::now(); + double elapsed = std::chrono::duration(now - last_target_time).count(); + if (elapsed > timeout_s) + { + resetAimState(); + } +} + +void MouseThread::ensurePredictionKalman(double q, double r) +{ + q = std::max(q, 1e-6); + r = std::max(r, 1e-6); + if (q != last_prediction_q || r != last_prediction_r) + { + last_prediction_q = q; + last_prediction_r = r; + resetPredictionState(); + } +} + +void MouseThread::ensureKalman(double q, double r) +{ + q = std::max(q, 1e-6); + r = std::max(r, 1e-6); + if (q != last_kalman_q || r != last_kalman_r) + { + kfX = Kalman1D(q, r); + kfY = Kalman1D(q, r); + last_kalman_q = q; + last_kalman_r = r; + kalman_smoothing_initialized = false; + prevKalmanTime = std::chrono::steady_clock::time_point{}; + } +} + +std::pair MouseThread::cameraVelocity(double camera_dx, double camera_dy, double dt) +{ + if (!config.camera_compensation_enabled || dt <= 0.0) + return { 0.0, 0.0 }; + double max_shift = std::max(0.0, static_cast(config.camera_compensation_max_shift)); + double strength = std::max(0.0, static_cast(config.camera_compensation_strength)); + double dx = clampValue(camera_dx, -max_shift, max_shift) * strength; + double dy = clampValue(camera_dy, -max_shift, max_shift) * strength; + return { dx / dt, dy / dt }; +} + +std::pair MouseThread::updateStandardVelocity( + double targetX, double targetY, double camera_dx, double camera_dy) +{ + auto now = std::chrono::steady_clock::now(); + if (prev_time.time_since_epoch().count() == 0 || !target_detected.load()) + { + prev_time = now; + prev_x = targetX; + prev_y = targetY; + prev_velocity_x = 0.0; + prev_velocity_y = 0.0; + return { 0.0, 0.0 }; + } + double dt = std::max(std::chrono::duration(now - prev_time).count(), 1e-8); + auto cam = cameraVelocity(camera_dx, camera_dy, dt); + double vx = (targetX - prev_x) / dt - cam.first; + double vy = (targetY - prev_y) / dt - cam.second; + prev_time = now; + prev_x = targetX; + prev_y = targetY; + prev_velocity_x = clampValue(vx, -20000.0, 20000.0); + prev_velocity_y = clampValue(vy, -20000.0, 20000.0); + return { prev_velocity_x, prev_velocity_y }; +} + +std::pair MouseThread::updatePredictionState( + double pivotX, double pivotY, double camera_dx, double camera_dy) +{ + int mode = config.prediction_mode; + if (mode != last_prediction_mode) + { + resetPredictionState(); + last_prediction_mode = mode; + } + + auto now = std::chrono::steady_clock::now(); + const double max_gap = 0.25; + if (prediction_prev_time.time_since_epoch().count() == 0) + { + prediction_prev_time = now; + prediction_prev_x = pivotX; + prediction_prev_y = pivotY; + if (mode != 0) + { + prediction_kf_x.reset(pivotX, 0.0); + prediction_kf_y.reset(pivotY, 0.0); + prediction_kalman_time = now; + prediction_kalman_initialized = true; + } + return { pivotX, pivotY }; + } + + double dt = std::chrono::duration(now - prediction_prev_time).count(); + if (dt > max_gap) + { + resetPredictionState(); + prediction_prev_time = now; + prediction_prev_x = pivotX; + prediction_prev_y = pivotY; + if (mode != 0) + { + prediction_kf_x.reset(pivotX, 0.0); + prediction_kf_y.reset(pivotY, 0.0); + prediction_kalman_time = now; + prediction_kalman_initialized = true; + } + return { pivotX, pivotY }; + } + + dt = std::max(dt, 1e-8); + auto cam = cameraVelocity(camera_dx, camera_dy, dt); + double raw_vx = (pivotX - prediction_prev_x) / dt - cam.first; + double raw_vy = (pivotY - prediction_prev_y) / dt - cam.second; + raw_vx = clampValue(raw_vx, -20000.0, 20000.0); + raw_vy = clampValue(raw_vy, -20000.0, 20000.0); + prediction_prev_x = pivotX; + prediction_prev_y = pivotY; + prediction_prev_time = now; + last_raw_velocity_x = raw_vx; + last_raw_velocity_y = raw_vy; + + double base_vx = raw_vx; + double base_vy = raw_vy; + double filt_x = pivotX; + double filt_y = pivotY; + + if (mode != 0) + { + double reset_threshold = std::max(1.0, static_cast(config.resetThreshold)); + if (!prediction_kalman_initialized || + std::hypot(pivotX - prediction_kf_x.x, pivotY - prediction_kf_y.x) > reset_threshold) + { + prediction_kf_x.reset(pivotX, 0.0); + prediction_kf_y.reset(pivotY, 0.0); + prediction_kalman_time = now; + prediction_kalman_initialized = true; + } + + double kdt = dt; + if (prediction_kalman_time.time_since_epoch().count() != 0) + kdt = std::max(std::chrono::duration(now - prediction_kalman_time).count(), 1e-8); + prediction_kalman_time = now; + + filt_x = prediction_kf_x.update(pivotX, kdt); + filt_y = prediction_kf_y.update(pivotY, kdt); + base_vx = prediction_kf_x.v - cam.first; + base_vy = prediction_kf_y.v - cam.second; + } + + double alpha = clampValue(config.prediction_velocity_smoothing, 0.0, 1.0); + if (!prediction_initialized) + { + prediction_smoothed_velocity_x = base_vx; + prediction_smoothed_velocity_y = base_vy; + prediction_initialized = true; + } + else + { + prediction_smoothed_velocity_x += (base_vx - prediction_smoothed_velocity_x) * alpha; + prediction_smoothed_velocity_y += (base_vy - prediction_smoothed_velocity_y) * alpha; + } + + double scale = std::max(0.0, static_cast(config.prediction_velocity_scale)); + prediction_velocity_x = prediction_smoothed_velocity_x * scale; + prediction_velocity_y = prediction_smoothed_velocity_y * scale; + + if (mode == 0) + return { pivotX, pivotY }; + + double lead_ms = std::max(0.0, static_cast(config.prediction_kalman_lead_ms)); + double max_lead_ms = std::max(0.0, static_cast(config.prediction_kalman_max_lead_ms)); + if (max_lead_ms > 0.0 && lead_ms > max_lead_ms) + lead_ms = max_lead_ms; + double lead_s = lead_ms / 1000.0; + + return { filt_x + prediction_velocity_x * lead_s, + filt_y + prediction_velocity_y * lead_s }; +} + +std::vector> MouseThread::predictFuturePositionsInternal( + double pivotX, double pivotY, int frames, double fps) +{ + std::vector> result; + if (frames <= 0) + return result; + if (prediction_prev_time.time_since_epoch().count() == 0) + return result; + + double dt = std::chrono::duration( + std::chrono::steady_clock::now() - prediction_prev_time).count(); + if (dt > 0.5) + return result; + + double frame_time = 1.0 / std::max(fps, 1.0); + double vx = prediction_initialized ? prediction_velocity_x : 0.0; + double vy = prediction_initialized ? prediction_velocity_y : 0.0; + + result.reserve(frames); + for (int i = 1; i <= frames; ++i) + { + double t = frame_time * i; + result.push_back({ pivotX + vx * t, pivotY + vy * t }); + } + return result; +} + +std::pair MouseThread::predict_target_position(double target_x, double target_y) +{ + ensurePredictionKalman(config.prediction_kalman_process_noise, + config.prediction_kalman_measurement_noise); + ensureKalman(config.kalman_process_noise, config.kalman_measurement_noise); + + double infer_ms = 0.0; + if (config.backend == "DML" && dml_detector) + { + infer_ms = dml_detector->lastInferenceTimeDML.count(); + } +#ifdef USE_CUDA + else if (config.backend != "COLOR") + { + infer_ms = trt_detector.lastInferenceTime.count(); + } +#endif + + auto pred = updatePredictionState(target_x, target_y, 0.0, 0.0); + double predX = pred.first; + double predY = pred.second; + + int mode = config.prediction_mode; + double interval = std::max(0.0, static_cast(config.predictionInterval)); + if (mode == 0) + { + auto vel = updateStandardVelocity(target_x, target_y, 0.0, 0.0); + double latency_s = std::max(0.0, infer_ms) / 1000.0; + predX = target_x + vel.first * (interval + latency_s); + predY = target_y + vel.second * (interval + latency_s); + } + else if (mode == 2) + { + predX += last_raw_velocity_x * interval; + predY += last_raw_velocity_y * interval; + } + + double latency_s = std::max(0.0, infer_ms) / 1000.0; + double extra_lead_s = latency_s; + if (mode == 1) + extra_lead_s += interval; + if ((mode == 1 || mode == 2) && extra_lead_s > 0.0) + { + predX += prediction_velocity_x * extra_lead_s; + predY += prediction_velocity_y * extra_lead_s; + } + + return { predX, predY }; +} + +void MouseThread::sendMovementToDriver(int dx, int dy) +{ + std::lock_guard lock(input_method_mutex); + if (makcu) + { + makcu->move(dx, dy); + } + else if (kmbox) + { + kmbox->move(dx, dy); + } + else if (kmbox_net) + { + kmbox_net->move(dx, dy); + } + else if (serial) + { + serial->move(dx, dy); + } + else + { + INPUT in{ 0 }; + in.type = INPUT_MOUSE; + in.mi.dx = dx; in.mi.dy = dy; + in.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK; + SendInput(1, &in, sizeof(INPUT)); + } +} + +std::pair MouseThread::calc_movement(double tx, double ty) +{ + double offx = tx - center_x; + double offy = ty - center_y; + double dist = std::hypot(offx, offy); + double speed = calculate_speed_multiplier(dist); + + double degPerPxX = fov_x / screen_width; + double degPerPxY = fov_y / screen_height; + + double mmx = offx * degPerPxX; + double mmy = offy * degPerPxY; + + double corr = 1.0; + double fps = static_cast(captureFps.load()); + if (fps > 30.0) corr = 30.0 / fps; + + auto counts_pair = config.degToCounts(mmx, mmy, fov_x); + double move_x = counts_pair.first * speed * corr; + double move_y = counts_pair.second * speed * corr; + + return { move_x, move_y }; +} + +double MouseThread::calculate_speed_multiplier(double distance) +{ + if (distance < config.snapRadius) + return min_speed_multiplier * config.snapBoostFactor; + + if (distance < config.nearRadius) + { + double t = distance / config.nearRadius; + double curve = 1.0 - std::pow(1.0 - t, config.speedCurveExponent); + return min_speed_multiplier + + (max_speed_multiplier - min_speed_multiplier) * curve; + } + + double norm = std::clamp(distance / max_distance, 0.0, 1.0); + return min_speed_multiplier + + (max_speed_multiplier - min_speed_multiplier) * norm; +} + +bool MouseThread::check_target_in_scope(double target_x, double target_y, double target_w, double target_h, double reduction_factor) +{ + double center_target_x = target_x + target_w / 2.0; + double center_target_y = target_y + target_h / 2.0; + + double reduced_w = target_w * (reduction_factor / 2.0); + double reduced_h = target_h * (reduction_factor / 2.0); + + double x1 = center_target_x - reduced_w; + double x2 = center_target_x + reduced_w; + double y1 = center_target_y - reduced_h; + double y2 = center_target_y + reduced_h; + + return (center_x > x1 && center_x < x2 && center_y > y1 && center_y < y2); +} + +void MouseThread::pressMouse(const AimbotTarget& target, float scope_multiplier) +{ + std::lock_guard lock(input_method_mutex); + + double multiplier = scope_multiplier > 0.0f ? scope_multiplier : bScope_multiplier; + bool bScope = check_target_in_scope(target.x, target.y, target.w, target.h, multiplier); + if (bScope && !mouse_pressed) + { + if (makcu) + { + makcu->press(0); + } + else if (kmbox) + { + kmbox->press(0); + } + else if (kmbox_net) + { + kmbox_net->keyDown(0); + } + else if (serial) + { + serial->press(); + } + else + { + INPUT input = { 0 }; + input.type = INPUT_MOUSE; + input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN; + SendInput(1, &input, sizeof(INPUT)); + } + mouse_pressed = true; + } + else if (!bScope && mouse_pressed) + { + if (makcu) + { + makcu->release(0); + } + else if (kmbox) + { + kmbox->release(0); + } + else if (kmbox_net) + { + kmbox_net->keyUp(0); + } + else if (serial) + { + serial->release(); + } + else + { + INPUT input = { 0 }; + input.type = INPUT_MOUSE; + input.mi.dwFlags = MOUSEEVENTF_LEFTUP; + SendInput(1, &input, sizeof(INPUT)); + } + mouse_pressed = false; + } +} + +void MouseThread::releaseMouse() +{ + std::lock_guard lock(input_method_mutex); + + if (mouse_pressed) + { + if (makcu) + { + makcu->release(0); + } + else if (kmbox) + { + kmbox->release(0); + } + else if (kmbox_net) + { + kmbox_net->keyUp(0); + } + else if (serial) + { + serial->release(); + } + else + { + INPUT input = { 0 }; + input.type = INPUT_MOUSE; + input.mi.dwFlags = MOUSEEVENTF_LEFTUP; + SendInput(1, &input, sizeof(INPUT)); + } + mouse_pressed = false; + } +} + +void MouseThread::resetPrediction() +{ + resetAimState(); +} + +void MouseThread::checkAndResetPredictions() +{ + resetIfStale(0.5); +} + +std::vector> MouseThread::predictFuturePositions(double pivotX, double pivotY, int frames) +{ + double fps = static_cast(captureFps.load()); + return predictFuturePositionsInternal(pivotX, pivotY, frames, fps); +} + +void MouseThread::storeFuturePositions(const std::vector>& positions) +{ + std::lock_guard lock(futurePositionsMutex); + futurePositions = positions; +} + +void MouseThread::clearFuturePositions() +{ + std::lock_guard lock(futurePositionsMutex); + futurePositions.clear(); +} + +std::vector> MouseThread::getFuturePositions() +{ + std::lock_guard lock(futurePositionsMutex); + return futurePositions; +} + +void MouseThread::setSerialConnection(SerialConnection* newSerial) +{ + std::lock_guard lock(input_method_mutex); + serial = newSerial; +} + +void MouseThread::setKmboxConnection(KmboxConnection* newKmbox) +{ + std::lock_guard lock(input_method_mutex); + kmbox = newKmbox; +} + +void MouseThread::setKmboxNetConnection(KmboxNetConnection* newKmbox_net) +{ + std::lock_guard lock(input_method_mutex); + kmbox_net = newKmbox_net; +} + +void MouseThread::setMakcuConnection(MakcuConnection* newMakcu) +{ + std::lock_guard lock( input_method_mutex); + makcu = newMakcu; +} +std::pair MouseThread::moveWithSmoothing(double targetX, double targetY, double fps) +{ + int N = smoothness > 0 ? smoothness : 1; + bool tracking = config.tracking_smoothing; + + int tracking_flag = tracking ? 1 : 0; + if (last_tracking_mode == -1 || last_tracking_mode != tracking_flag) + { + resetSmoothingState(); + last_tracking_mode = tracking_flag; + } + + if (tracking) + { + auto now = std::chrono::steady_clock::now(); + double dt; + if (track_time.time_since_epoch().count() == 0) + dt = 1.0 / std::max(fps, 1.0); + else + dt = std::max(std::chrono::duration(now - track_time).count(), 1e-8); + dt = std::min(dt, 0.25); + track_time = now; + + if (!tracking_initialized) + { + track_x = center_x; + track_y = center_y; + track_prev_x = track_x; + track_prev_y = track_y; + tracking_initialized = true; + } + + double delta = std::hypot(targetX - track_x, targetY - track_y); + double reset_threshold = std::max(1.0, static_cast(config.resetThreshold)); + double base_alpha = 1.0 - std::exp(-dt * std::max(fps, 1.0) / N); + double catchup = clampValue(delta / std::max(reset_threshold, 1e-3), 0.0, 1.0); + double alpha = clampValue(base_alpha + (0.65 - base_alpha) * catchup, base_alpha, 0.65); + + track_x += (targetX - track_x) * alpha; + track_y += (targetY - track_y) * alpha; + + double dx = track_x - track_prev_x; + double dy = track_y - track_prev_y; + + auto mv = addOverflow(dx, dy, move_overflow_x, move_overflow_y); + int ix = static_cast(mv.first); + int iy = static_cast(mv.second); + + track_prev_x = track_x; + track_prev_y = track_y; + smooth_last_tx = targetX; + smooth_last_ty = targetY; + return { ix, iy }; + } + + if (smooth_frame == 0 || + std::hypot(targetX - smooth_last_tx, targetY - smooth_last_ty) > 1.0) + { + smooth_start_x = center_x; + smooth_start_y = center_y; + smooth_prev_x = smooth_start_x; + smooth_prev_y = smooth_start_y; + smooth_frame = 0; + } + + smooth_last_tx = targetX; + smooth_last_ty = targetY; + smooth_frame = std::min(smooth_frame + 1, N); + double t = static_cast(smooth_frame) / N; + double p = easeInOut(t); + + double curX = smooth_start_x + (targetX - smooth_start_x) * p; + double curY = smooth_start_y + (targetY - smooth_start_y) * p; + + double dx = curX - smooth_prev_x; + double dy = curY - smooth_prev_y; + + auto mv = addOverflow(dx, dy, move_overflow_x, move_overflow_y); + int ix = static_cast(mv.first); + int iy = static_cast(mv.second); + + smooth_prev_x = curX; + smooth_prev_y = curY; + return { ix, iy }; +} + +std::pair MouseThread::moveWithKalman(double targetX, double targetY, double fps) +{ + double reset_threshold = std::max(1.0, static_cast(config.resetThreshold)); + auto now = std::chrono::steady_clock::now(); + + if (prevKalmanTime.time_since_epoch().count() == 0 || + std::hypot(targetX - last_raw_kalman_x, targetY - last_raw_kalman_y) > reset_threshold) + { + kfX.reset(targetX, 0.0); + kfY.reset(targetY, 0.0); + prevKalmanTime = now; + } + + last_raw_kalman_x = targetX; + last_raw_kalman_y = targetY; + + auto now2 = std::chrono::steady_clock::now(); + double dt; + if (prevKalmanTime.time_since_epoch().count() == 0) + dt = 1.0 / std::max(fps, 1.0); + else + dt = std::max(std::chrono::duration(now2 - prevKalmanTime).count(), 1e-8); + prevKalmanTime = now2; + + double filtX = kfX.update(targetX, dt); + double filtY = kfY.update(targetY, dt); + + auto mv = calc_movement(filtX, filtY); + double mvX = mv.first * kalman_speed_multiplier_x; + double mvY = mv.second * kalman_speed_multiplier_y; + + return { static_cast(std::round(mvX)), static_cast(std::round(mvY)) }; +} + +std::pair MouseThread::moveWithKalmanAndSmoothing(double targetX, double targetY, double fps) +{ + double reset_threshold = std::max(1.0, static_cast(config.resetThreshold)); + auto now = std::chrono::steady_clock::now(); + const double max_dt = 0.25; + + bool need_reset = !kalman_smoothing_initialized; + if (!need_reset) + { + double jump = std::hypot(targetX - last_raw_kalman_x, targetY - last_raw_kalman_y); + if (jump > reset_threshold) + need_reset = true; + if (prevKalmanTime.time_since_epoch().count() != 0) + { + double since_last = std::chrono::duration(now - prevKalmanTime).count(); + if (since_last > max_dt) + need_reset = true; + } + } + + if (need_reset || prevKalmanTime.time_since_epoch().count() == 0) + { + kfX.reset(targetX, 0.0); + kfY.reset(targetY, 0.0); + prevKalmanTime = now; + last_kx = targetX; + last_ky = targetY; + move_overflow_x = 0.0; + move_overflow_y = 0.0; + kalman_smoothing_initialized = true; + } + + last_raw_kalman_x = targetX; + last_raw_kalman_y = targetY; + + double dt; + if (prevKalmanTime.time_since_epoch().count() == 0 || need_reset) + dt = 1.0 / std::max(fps, 1.0); + else + dt = std::chrono::duration(now - prevKalmanTime).count(); + prevKalmanTime = now; + dt = clampValue(dt, 1e-8, max_dt); + + double filtX = kfX.update(targetX, dt); + double filtY = kfY.update(targetY, dt); + + int N = smoothness > 0 ? smoothness : 1; + double base_alpha = 1.0 - std::exp(-dt * std::max(fps, 1.0) / N); + double delta = std::hypot(filtX - last_kx, filtY - last_ky); + double catchup = clampValue(delta / std::max(reset_threshold, 1e-3), 0.0, 1.0); + double max_alpha = config.tracking_smoothing ? 0.65 : 0.45; + double alpha = clampValue(base_alpha + (max_alpha - base_alpha) * catchup, base_alpha, max_alpha); + + if (delta > reset_threshold) + { + last_kx = filtX; + last_ky = filtY; + } + else + { + last_kx += (filtX - last_kx) * alpha; + last_ky += (filtY - last_ky) * alpha; + } + + auto mv = calc_movement(last_kx, last_ky); + double mvX = mv.first * kalman_speed_multiplier_x; + double mvY = mv.second * kalman_speed_multiplier_y; + + auto step = addOverflow(mvX, mvY, move_overflow_x, move_overflow_y); + return { static_cast(step.first), static_cast(step.second) }; +} + +std::pair MouseThread::computeMove( + double targetX, double targetY, double fps, double infer_latency_ms, + double camera_dx, double camera_dy) +{ + markTargetSeen(); + ensurePredictionKalman(config.prediction_kalman_process_noise, + config.prediction_kalman_measurement_noise); + ensureKalman(config.kalman_process_noise, config.kalman_measurement_noise); + + auto pred = updatePredictionState(targetX, targetY, camera_dx, camera_dy); + double predX = pred.first; + double predY = pred.second; + + int mode = config.prediction_mode; + double interval = std::max(0.0, static_cast(config.predictionInterval)); + + if (mode == 0) + { + auto vel = updateStandardVelocity(targetX, targetY, camera_dx, camera_dy); + double latency_s = std::max(0.0, infer_latency_ms) / 1000.0; + predX = targetX + vel.first * (interval + latency_s); + predY = targetY + vel.second * (interval + latency_s); + } + else if (mode == 2) + { + predX += last_raw_velocity_x * interval; + predY += last_raw_velocity_y * interval; + } + + double latency_s = std::max(0.0, infer_latency_ms) / 1000.0; + double extra_lead_s = latency_s; + if (mode == 1) + extra_lead_s += interval; + if ((mode == 1 || mode == 2) && extra_lead_s > 0.0) + { + predX += prediction_velocity_x * extra_lead_s; + predY += prediction_velocity_y * extra_lead_s; + } + + bool use_future_for_aim = config.prediction_use_future_for_aim; + bool need_future = use_future_for_aim || config.draw_futurePositions; + if (need_future) + { + auto future = predictFuturePositionsInternal( + predX, predY, config.prediction_futurePositions, fps); + if (use_future_for_aim && !future.empty()) + { + predX = future.back().first; + predY = future.back().second; + } + storeFuturePositions(future); + } + else + { + clearFuturePositions(); + } + + if (use_kalman && use_smoothing) + return moveWithKalmanAndSmoothing(predX, predY, fps); + if (use_kalman) + return moveWithKalman(predX, predY, fps); + if (use_smoothing) + return moveWithSmoothing(predX, predY, fps); + + auto mv = calc_movement(predX, predY); + return { static_cast(std::round(mv.first)), static_cast(std::round(mv.second)) }; +} + +// Kalman (public wrappers) +void MouseThread::moveMouseWithKalman(double targetX, double targetY) +{ + double fps = std::max(1.0, static_cast(captureFps.load())); + auto delta = moveWithKalman(targetX, targetY, fps); + if (delta.first || delta.second) + { + if (wind_mouse_enabled) + windMouseMoveRelative(delta.first, delta.second); + else + queueMove(delta.first, delta.second); + } +} + +// Kalman + smoothing (public wrappers) +void MouseThread::moveMouseWithKalmanAndSmoothing(double targetX, double targetY) +{ + double fps = std::max(1.0, static_cast(captureFps.load())); + auto delta = moveWithKalmanAndSmoothing(targetX, targetY, fps); + if (delta.first || delta.second) + { + if (wind_mouse_enabled) + windMouseMoveRelative(delta.first, delta.second); + else + queueMove(delta.first, delta.second); + } +} + + +// easing-??????? ??? ????????? +double MouseThread::easeInOut(double t) { + return -0.5 * (std::cos(M_PI * t) - 1.0); +} + +// ?????????? ??????? ??????, ????? ?? ?????? ??????? +std::pair MouseThread::addOverflow( + double dx, double dy, + double& overflow_x, double& overflow_y) +{ + double int_x = 0.0, int_y = 0.0; + double frac_x = std::modf(dx + overflow_x, &int_x); + double frac_y = std::modf(dy + overflow_y, &int_y); + + if (std::abs(frac_x) > 1.0) { + double extra = 0.0; + frac_x = std::modf(frac_x, &extra); + int_x += extra; + } + if (std::abs(frac_y) > 1.0) { + double extra = 0.0; + frac_y = std::modf(frac_y, &extra); + int_y += extra; + } + + overflow_x = frac_x; + overflow_y = frac_y; + return { int_x, int_y }; +} + +void MouseThread::setKalmanParams(double processNoise, double measurementNoise) { + std::lock_guard lg(input_method_mutex); + // ?????? ????????????? ??????? ? ?????? Q/R + kfX = Kalman1D(processNoise, measurementNoise); + kfY = Kalman1D(processNoise, measurementNoise); + last_kalman_q = processNoise; + last_kalman_r = measurementNoise; + kalman_smoothing_initialized = false; + prevKalmanTime = std::chrono::steady_clock::time_point{}; +} + +void MouseThread::moveMouse(const AimbotTarget& target) +{ + double fps = std::max(1.0, static_cast(captureFps.load())); + double infer_ms = 0.0; + if (config.backend == "DML" && dml_detector) + infer_ms = dml_detector->lastInferenceTimeDML.count(); +#ifdef USE_CUDA + else if (config.backend != "COLOR") + infer_ms = trt_detector.lastInferenceTime.count(); +#endif + + auto delta = computeMove(target.pivotX, target.pivotY, fps, infer_ms, 0.0, 0.0); + if (delta.first || delta.second) + { + if (wind_mouse_enabled) + windMouseMoveRelative(delta.first, delta.second); + else + queueMove(delta.first, delta.second); + } +} + +// ?????????? ??? moveMousePivot +void MouseThread::moveMousePivot(double pivotX, double pivotY) +{ + double fps = std::max(1.0, static_cast(captureFps.load())); + double infer_ms = 0.0; + if (config.backend == "DML" && dml_detector) + infer_ms = dml_detector->lastInferenceTimeDML.count(); +#ifdef USE_CUDA + else if (config.backend != "COLOR") + infer_ms = trt_detector.lastInferenceTime.count(); +#endif + + auto delta = computeMove(pivotX, pivotY, fps, infer_ms, 0.0, 0.0); + if (delta.first || delta.second) + { + if (wind_mouse_enabled) + windMouseMoveRelative(delta.first, delta.second); + else + queueMove(delta.first, delta.second); + } +} diff --git a/sunone_aimbot_cpp/mouse/mouse.h b/RN_AI_cpp/mouse/mouse.h similarity index 66% rename from sunone_aimbot_cpp/mouse/mouse.h rename to RN_AI_cpp/mouse/mouse.h index 5d21d112..a6e02e79 100644 --- a/sunone_aimbot_cpp/mouse/mouse.h +++ b/RN_AI_cpp/mouse/mouse.h @@ -1,4 +1,4 @@ -// mouse.h +// mouse.h #ifndef MOUSE_H #define MOUSE_H @@ -26,7 +26,7 @@ class MouseThread { private: - // Основные параметры + // ???????? ????????? double screen_width, screen_height; double prediction_interval; double fov_x, fov_y; @@ -37,7 +37,7 @@ class MouseThread float bScope_multiplier; float triggerbot_bScope_multiplier; - // Для предсказания + // ??? ???????????? double prev_x, prev_y; double prev_velocity_x, prev_velocity_y; std::chrono::time_point prev_time; @@ -45,13 +45,13 @@ class MouseThread std::atomic target_detected{ false }; std::atomic mouse_pressed{ false }; - // Интерфейсы ввода + // ?????????? ????? SerialConnection* serial; KmboxConnection* kmbox; KmboxNetConnection* kmbox_net; MakcuConnection* makcu; - // Отправка движений + // ???????? ???????? void sendMovementToDriver(int dx, int dy); struct Move { int dx, dy; }; std::queue moveQueue; @@ -61,40 +61,45 @@ class MouseThread std::thread moveWorker; std::atomic workerStop{ false }; - // Флаг выбора логики + // ???? ?????? ?????? bool use_smoothing = { false }; bool use_kalman = { true }; - // Для «ветра» + // ??? ????? bool wind_mouse_enabled = true; double wind_G, wind_W, wind_M, wind_D; void windMouseMoveRelative(int dx, int dy); - // Расчёт базового движения и скорости + // ?????? ???????? ???????? ? ???????? std::pair calc_movement(double tx, double ty); double calculate_speed_multiplier(double distance); - // Хранение прогнозов + // ???????? ????????? std::vector> futurePositions; std::mutex futurePositionsMutex; void moveWorkerLoop(); void queueMove(int dx, int dy); - // Параметры для сглаживания + // ????????? ??? ??????????? int smoothness{ 100 }; double move_overflow_x{ 0.0 }, move_overflow_y{ 0.0 }; double easeInOut(double t); std::pair addOverflow(double dx, double dy, double& overflow_x, double& overflow_y); - void moveMouseWithSmoothing(double targetX, double targetY); struct Kalman1D { - double x{ 0 }, v{ 0 }, P{ 1 }, Q, R; + double x{ 0 }, v{ 0 }, P{ 1 }, Q{ 0.01 }, R{ 0.1 }; + Kalman1D() = default; Kalman1D(double processNoise, double measurementNoise) : Q(processNoise), R(measurementNoise) { } + void reset(double x0 = 0.0, double v0 = 0.0) { + x = x0; + v = v0; + P = 1.0; + } double update(double z, double dt) { x += v * dt; P += Q * dt; @@ -108,23 +113,70 @@ class MouseThread Kalman1D kfX{ 0.01, 0.1 }, kfY{ 0.01, 0.1 }; std::chrono::steady_clock::time_point prevKalmanTime{}; - bool smoothingActive = false; - int smoothingSteps = 0; - double smoothingStartX = 0, smoothingStartY = 0; - double smoothingTargetX = 0, smoothingTargetY = 0; - double smoothingDurationMs = 0; - std::chrono::steady_clock::time_point smoothingStartTime{}; - - double last_dx{ 0.0 }; - double last_dy{ 0.0 }; - double last_kX{ 0.0 }; - double last_kY{ 0.0 }; + double last_kx{ 0.0 }; + double last_ky{ 0.0 }; double last_raw_kalman_x{ 0.0 }; double last_raw_kalman_y{ 0.0 }; bool kalman_smoothing_initialized{ false }; + double last_kalman_q{ -1.0 }; + double last_kalman_r{ -1.0 }; + + // RN_AI prediction state + std::chrono::steady_clock::time_point prediction_prev_time{}; + double prediction_prev_x{ 0.0 }; + double prediction_prev_y{ 0.0 }; + double prediction_smoothed_velocity_x{ 0.0 }; + double prediction_smoothed_velocity_y{ 0.0 }; + double prediction_velocity_x{ 0.0 }; + double prediction_velocity_y{ 0.0 }; + bool prediction_initialized{ false }; + std::chrono::steady_clock::time_point prediction_kalman_time{}; + bool prediction_kalman_initialized{ false }; + int last_prediction_mode{ -1 }; + double last_prediction_q{ -1.0 }; + double last_prediction_r{ -1.0 }; + Kalman1D prediction_kf_x{ 0.01, 0.1 }; + Kalman1D prediction_kf_y{ 0.01, 0.1 }; + double last_raw_velocity_x{ 0.0 }; + double last_raw_velocity_y{ 0.0 }; + + // Smoothing state + int smooth_frame{ 0 }; + double smooth_start_x{ 0.0 }; + double smooth_start_y{ 0.0 }; + double smooth_prev_x{ 0.0 }; + double smooth_prev_y{ 0.0 }; + double smooth_last_tx{ 0.0 }; + double smooth_last_ty{ 0.0 }; + + bool tracking_initialized{ false }; + double track_x{ 0.0 }; + double track_y{ 0.0 }; + double track_prev_x{ 0.0 }; + double track_prev_y{ 0.0 }; + std::chrono::steady_clock::time_point track_time{}; + int last_tracking_mode{ -1 }; double kalman_speed_multiplier_x{ 1.0 }; double kalman_speed_multiplier_y{ 1.0 }; + + static double clampValue(double v, double lo, double hi); + void resetAimState(); + void resetPredictionState(); + void resetKalmanState(); + void resetSmoothingState(); + void markTargetSeen(); + void resetIfStale(double timeout_s); + void ensurePredictionKalman(double q, double r); + void ensureKalman(double q, double r); + std::pair cameraVelocity(double camera_dx, double camera_dy, double dt); + std::pair updateStandardVelocity(double targetX, double targetY, double camera_dx, double camera_dy); + std::pair updatePredictionState(double pivotX, double pivotY, double camera_dx, double camera_dy); + std::vector> predictFuturePositionsInternal(double pivotX, double pivotY, int frames, double fps); + std::pair moveWithSmoothing(double targetX, double targetY, double fps); + std::pair moveWithKalman(double targetX, double targetY, double fps); + std::pair moveWithKalmanAndSmoothing(double targetX, double targetY, double fps); + std::pair computeMove(double targetX, double targetY, double fps, double infer_latency_ms, double camera_dx, double camera_dy); public: std::mutex input_method_mutex; @@ -157,18 +209,18 @@ class MouseThread float triggerbot_bScope_multiplier ); - // Переключатель логики + // ????????????? ?????? void setUseSmoothing(bool v) { use_smoothing = v; } bool isUsingSmoothing() const { return use_smoothing; } void setUseKalman(bool v) { use_kalman = v; } bool isUsingKalman() const { return use_kalman; } - // Настройка «гладкости» + // ????????? ????????? void setSmoothness(int s) { smoothness = (s > 0 ? s : 1); } int getSmoothness() const { return smoothness; } - // API движения и кликов + // API ???????? ? ?????? void moveMousePivot(double pivotX, double pivotY); std::pair predict_target_position(double x, double y); void moveMouse(const AimbotTarget& target); @@ -179,7 +231,7 @@ class MouseThread bool check_target_in_scope(double x, double y, double w, double h, double reduction_factor); - // Будущие позиции + // ??????? ??????? std::vector> predictFuturePositions( double pivotX, double pivotY, int frames); void storeFuturePositions( @@ -187,7 +239,7 @@ class MouseThread void clearFuturePositions(); std::vector> getFuturePositions(); - // Сеттеры интерфейсов + // ??????? ??????????? void setSerialConnection(SerialConnection* s); void setKmboxConnection(KmboxConnection* k); void setKmboxNetConnection(KmboxNetConnection* k); diff --git a/sunone_aimbot_cpp/mouse/mouse.zip b/RN_AI_cpp/mouse/mouse.zip similarity index 100% rename from sunone_aimbot_cpp/mouse/mouse.zip rename to RN_AI_cpp/mouse/mouse.zip diff --git a/sunone_aimbot_cpp/overlay/Game_overlay.cpp b/RN_AI_cpp/overlay/Game_overlay.cpp similarity index 80% rename from sunone_aimbot_cpp/overlay/Game_overlay.cpp rename to RN_AI_cpp/overlay/Game_overlay.cpp index 5d5a5f02..30605028 100644 --- a/sunone_aimbot_cpp/overlay/Game_overlay.cpp +++ b/RN_AI_cpp/overlay/Game_overlay.cpp @@ -1,5 +1,3 @@ -#include "Game_overlay.h" - #define WIN32_LEAN_AND_MEAN #include #include @@ -20,6 +18,7 @@ #include #include #include +#include #pragma comment(lib, "dwmapi.lib") #pragma comment(lib, "d3d11.lib") @@ -29,6 +28,8 @@ #pragma comment(lib, "windowscodecs.lib") #pragma comment(lib, "dcomp.lib") +#include "Game_overlay.h" + using Microsoft::WRL::ComPtr; static void GetVirtualScreen(int& x, int& y, int& w, int& h) @@ -84,6 +85,11 @@ struct ImageRes ComPtr bmp; float w = 0.f; float h = 0.f; + std::vector pending; + int pendingW = 0; + int pendingH = 0; + int pendingStride = 0; + bool pendingDirty = false; }; struct Game_overlay::Impl @@ -113,9 +119,12 @@ struct Game_overlay::Impl ComPtr dcompTarget; ComPtr dcompRoot; + std::mutex d2dMutex; std::thread thread; std::atomic running{ false }; std::atomic visible{ true }; + std::atomic excludeFromCapture{ true }; + bool appliedExcludeFromCapture = true; std::atomic maxFps{ 0 }; std::mutex pendingMutex; @@ -139,6 +148,7 @@ struct Game_overlay::Impl int LoadImageFromFile(const std::wstring& path); void UnloadImage(int id); void DrawImage(int id, float x, float y, float w, float h, float opacity); + int UpdateImageFromBGRA(const void* data, int width, int height, int strideBytes, int imageId); static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); bool CreateWindowAndDevices(); @@ -150,6 +160,7 @@ struct Game_overlay::Impl HRESULT CreateTextFormat(const std::wstring& font, float size, IDWriteTextFormat** out); HRESULT CreateTargets(); void ReleaseTargets(); + void ApplyDisplayAffinity(); }; Game_overlay::Game_overlay() : impl_(new Impl) {} @@ -160,6 +171,8 @@ void Game_overlay::Stop() { impl_->Stop(); } bool Game_overlay::IsRunning() const { return impl_->running.load(); } void Game_overlay::SetVisible(bool v) { impl_->visible.store(v); } bool Game_overlay::GetVisible() const { return impl_->visible.load(); } +void Game_overlay::SetExcludeFromCapture(bool exclude) { impl_->excludeFromCapture.store(exclude); } +bool Game_overlay::GetExcludeFromCapture() const { return impl_->excludeFromCapture.load(); } void Game_overlay::UseVirtualScreen() { impl_->UseVirtualScreen(); } void Game_overlay::SetWindowBounds(int x, int y, int w, int h) { impl_->SetBounds(x, y, w, h); } void Game_overlay::SetMaxFPS(unsigned f) { impl_->maxFps.store(f); } @@ -202,6 +215,10 @@ void Game_overlay::AddText(float x, float y, const std::wstring& text, int Game_overlay::LoadImageFromFile(const std::wstring& path) { return impl_->LoadImageFromFile(path); } void Game_overlay::UnloadImage(int id) { impl_->UnloadImage(id); } void Game_overlay::DrawImage(int id, float x, float y, float w, float h, float op) { impl_->DrawImage(id, x, y, w, h, op); } +int Game_overlay::UpdateImageFromBGRA(const void* data, int width, int height, int strideBytes, int imageId) +{ + return impl_->UpdateImageFromBGRA(data, width, height, strideBytes, imageId); +} bool Game_overlay::Impl::Start() { @@ -209,16 +226,29 @@ bool Game_overlay::Impl::Start() running = true; thread = std::thread([this] { SetPerMonitorV2DpiAwareness(); - CoInitializeEx(nullptr, COINIT_MULTITHREADED); - hinst = GetModuleHandleW(nullptr); - if (!CreateWindowAndDevices()) { - running = false; - CoUninitialize(); - return; + HRESULT cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + const bool coinit_ok = SUCCEEDED(cohr); + try + { + hinst = GetModuleHandleW(nullptr); + if (!CreateWindowAndDevices()) { + running = false; + if (coinit_ok) CoUninitialize(); + return; + } + RenderLoop(); + } + catch (const std::exception& e) + { + std::cerr << "[GameOverlay] Render thread crashed: " << e.what() << std::endl; + } + catch (...) + { + std::cerr << "[GameOverlay] Render thread crashed: unknown exception." << std::endl; } - RenderLoop(); DestroyWindowAndDevices(); - CoUninitialize(); + if (coinit_ok) CoUninitialize(); + running = false; }); return true; } @@ -261,6 +291,7 @@ HRESULT Game_overlay::Impl::EnsureWic() int Game_overlay::Impl::LoadImageFromFile(const std::wstring& path) { + if (path.empty()) return 0; if (FAILED(EnsureWic())) return 0; ComPtr dec; @@ -273,17 +304,24 @@ int Game_overlay::Impl::LoadImageFromFile(const std::wstring& path) ComPtr conv; if (FAILED(wic->CreateFormatConverter(&conv))) return 0; + bool premultiplied = true; if (FAILED(conv->Initialize(frame.Get(), GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, nullptr, 0.f, WICBitmapPaletteTypeCustom))) - return 0; + { + premultiplied = false; + if (FAILED(conv->Initialize(frame.Get(), GUID_WICPixelFormat32bppBGRA, + WICBitmapDitherTypeNone, nullptr, 0.f, WICBitmapPaletteTypeCustom))) + return 0; + } if (!d2dCtx) return 0; + std::lock_guard d2dLock(d2dMutex); D2D1_BITMAP_PROPERTIES1 props = D2D1::BitmapProperties1( D2D1_BITMAP_OPTIONS_NONE, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, - D2D1_ALPHA_MODE_PREMULTIPLIED), + premultiplied ? D2D1_ALPHA_MODE_PREMULTIPLIED : D2D1_ALPHA_MODE_IGNORE), 96.f, 96.f); ComPtr bmp; @@ -315,6 +353,41 @@ void Game_overlay::Impl::DrawImage(int id, float x, float y, float w, float h, f AddCmd(c); } +int Game_overlay::Impl::UpdateImageFromBGRA(const void* data, int width, int height, int strideBytes, int imageId) +{ + if (!data || width <= 0 || height <= 0 || strideBytes <= 0) + return 0; + + std::lock_guard il(imgMutex); + ImageRes* target = nullptr; + if (imageId != 0) + { + auto it = images.find(imageId); + if (it != images.end()) + target = &it->second; + } + if (!target) + { + imageId = nextImageId++; + auto [it, _] = images.emplace(imageId, ImageRes{}); + target = &it->second; + } + + target->pendingW = width; + target->pendingH = height; + target->pendingStride = strideBytes; + target->pending.resize(static_cast(strideBytes) * static_cast(height)); + const uint8_t* src = static_cast(data); + for (int y = 0; y < height; ++y) + { + memcpy(target->pending.data() + static_cast(y) * strideBytes, + src + static_cast(y) * strideBytes, + strideBytes); + } + target->pendingDirty = true; + return imageId; +} + LRESULT CALLBACK Game_overlay::Impl::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { Impl* self = reinterpret_cast(GetWindowLongPtrW(hWnd, GWLP_USERDATA)); @@ -376,7 +449,7 @@ bool Game_overlay::Impl::CreateWindowAndDevices() } ShowWindow(hwnd, SW_SHOWNA); - SetWindowDisplayAffinity(hwnd, WDA_EXCLUDEFROMCAPTURE); + ApplyDisplayAffinity(); SetWindowPos(hwnd, HWND_TOPMOST, winX, winY, winW, winH, SWP_NOACTIVATE | SWP_SHOWWINDOW); @@ -578,10 +651,26 @@ HRESULT Game_overlay::Impl::CreateTextFormat( return S_OK; } +void Game_overlay::Impl::ApplyDisplayAffinity() +{ + if (!hwnd) + return; + + const bool wantedExclude = excludeFromCapture.load(); + appliedExcludeFromCapture = wantedExclude; + const DWORD affinity = wantedExclude ? WDA_EXCLUDEFROMCAPTURE : WDA_NONE; + if (SetWindowDisplayAffinity(hwnd, affinity)) + return; + + if (wantedExclude) + SetWindowDisplayAffinity(hwnd, WDA_MONITOR); +} + void Game_overlay::Impl::RenderLoop() { running = true; auto last = std::chrono::high_resolution_clock::now(); + appliedExcludeFromCapture = !excludeFromCapture.load(); MSG msg{}; while (running.load()) @@ -606,6 +695,9 @@ void Game_overlay::Impl::RenderLoop() if (now - last < minDelta) { Sleep(1); continue; } last = now; } + + if (appliedExcludeFromCapture != excludeFromCapture.load()) + ApplyDisplayAffinity(); RenderOne(); } } @@ -625,9 +717,50 @@ void Game_overlay::Impl::RenderOne() ShowWindow(hwnd, SW_SHOWNA); } + std::lock_guard d2dLock(d2dMutex); d2dCtx->BeginDraw(); d2dCtx->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.f)); + { + std::lock_guard il(imgMutex); + for (auto& kv : images) + { + auto& img = kv.second; + if (!img.pendingDirty || img.pending.empty()) + continue; + + D2D1_BITMAP_PROPERTIES1 props = + D2D1::BitmapProperties1( + D2D1_BITMAP_OPTIONS_NONE, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), + 96.f, 96.f); + + if (!img.bmp || img.w != img.pendingW || img.h != img.pendingH) + { + ComPtr bmp; + HRESULT hr = d2dCtx->CreateBitmap( + D2D1::SizeU(static_cast(img.pendingW), static_cast(img.pendingH)), + img.pending.data(), + static_cast(img.pendingStride), + props, + &bmp); + if (FAILED(hr)) + continue; + + img.bmp = bmp; + img.w = static_cast(img.pendingW); + img.h = static_cast(img.pendingH); + } + else + { + if (FAILED(img.bmp->CopyFromMemory(nullptr, img.pending.data(), static_cast(img.pendingStride)))) + continue; + } + + img.pendingDirty = false; + } + } + auto dl = std::atomic_load_explicit(¤t, std::memory_order_acquire); if (dl) { @@ -722,4 +855,4 @@ void Game_overlay::Impl::RenderOne() } swapChain->Present(0, 0); -} \ No newline at end of file +} diff --git a/sunone_aimbot_cpp/overlay/Game_overlay.h b/RN_AI_cpp/overlay/Game_overlay.h similarity index 90% rename from sunone_aimbot_cpp/overlay/Game_overlay.h rename to RN_AI_cpp/overlay/Game_overlay.h index 4e60f310..91a5d3f5 100644 --- a/sunone_aimbot_cpp/overlay/Game_overlay.h +++ b/RN_AI_cpp/overlay/Game_overlay.h @@ -23,6 +23,8 @@ class Game_overlay void SetVisible(bool visible); bool GetVisible() const; + void SetExcludeFromCapture(bool exclude); + bool GetExcludeFromCapture() const; void BeginFrame(); void EndFrame(); @@ -38,6 +40,7 @@ class Game_overlay int LoadImageFromFile(const std::wstring& path); void UnloadImage(int imageId); void DrawImage(int imageId, float x, float y, float w, float h, float opacity = 1.0f); + int UpdateImageFromBGRA(const void* data, int width, int height, int strideBytes, int imageId = 0); void UseVirtualScreen(); void SetWindowBounds(int x, int y, int w, int h); diff --git a/RN_AI_cpp/overlay/config_dirty.cpp b/RN_AI_cpp/overlay/config_dirty.cpp new file mode 100644 index 00000000..4917d896 --- /dev/null +++ b/RN_AI_cpp/overlay/config_dirty.cpp @@ -0,0 +1,53 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#include +#include + +#include "config_dirty.h" +#include "config.h" + +extern Config config; + +namespace +{ +std::atomic g_config_dirty{ false }; +std::chrono::steady_clock::time_point g_last_dirty_at = std::chrono::steady_clock::now(); +} + +void OverlayConfig_MarkDirty() +{ + g_last_dirty_at = std::chrono::steady_clock::now(); + g_config_dirty.store(true, std::memory_order_relaxed); +} + +bool OverlayConfig_IsDirty() +{ + return g_config_dirty.load(std::memory_order_relaxed); +} + +bool OverlayConfig_FlushIfDue(int debounceMs) +{ + if (!g_config_dirty.load(std::memory_order_relaxed)) + return false; + + const auto elapsed = + std::chrono::duration_cast(std::chrono::steady_clock::now() - g_last_dirty_at).count(); + if (elapsed < debounceMs) + return false; + + config.saveConfig(); + g_config_dirty.store(false, std::memory_order_relaxed); + return true; +} + +void OverlayConfig_FlushNow() +{ + if (!g_config_dirty.load(std::memory_order_relaxed)) + return; + + config.saveConfig(); + g_config_dirty.store(false, std::memory_order_relaxed); +} diff --git a/RN_AI_cpp/overlay/config_dirty.h b/RN_AI_cpp/overlay/config_dirty.h new file mode 100644 index 00000000..8ef16bb6 --- /dev/null +++ b/RN_AI_cpp/overlay/config_dirty.h @@ -0,0 +1,9 @@ +#ifndef OVERLAY_CONFIG_DIRTY_H +#define OVERLAY_CONFIG_DIRTY_H + +void OverlayConfig_MarkDirty(); +bool OverlayConfig_IsDirty(); +bool OverlayConfig_FlushIfDue(int debounceMs = 200); +void OverlayConfig_FlushNow(); + +#endif // OVERLAY_CONFIG_DIRTY_H diff --git a/sunone_aimbot_cpp/overlay/draw_ai.cpp b/RN_AI_cpp/overlay/draw_ai.cpp similarity index 62% rename from sunone_aimbot_cpp/overlay/draw_ai.cpp rename to RN_AI_cpp/overlay/draw_ai.cpp index c38a66c5..ded9178b 100644 --- a/sunone_aimbot_cpp/overlay/draw_ai.cpp +++ b/RN_AI_cpp/overlay/draw_ai.cpp @@ -1,11 +1,13 @@ -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #define _WINSOCKAPI_ #include #include +#include + #include "imgui/imgui.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "include/other_tools.h" #include "overlay.h" #ifdef USE_CUDA @@ -138,9 +140,21 @@ void draw_ai() ImGui::Separator(); ImGui::SliderFloat("Confidence Threshold", &config.confidence_threshold, 0.01f, 1.00f, "%.2f"); - ImGui::SliderFloat("NMS Threshold", &config.nms_threshold, 0.01f, 1.00f, "%.2f"); + ImGui::SliderFloat("IOU Threshold (NMS)", &config.nms_threshold, 0.01f, 1.00f, "%.2f"); ImGui::Checkbox("Adaptive NMS", &config.adaptive_nms); - ImGui::SliderInt("Max Detections", &config.max_detections, 1, 100); + static int max_detections_cache = 20; + if (config.max_detections > 0) + max_detections_cache = config.max_detections; + bool limit_max = config.max_detections > 0; + if (ImGui::Checkbox("Limit Max Detections", &limit_max)) + { + if (limit_max) + config.max_detections = std::max(1, max_detections_cache); + else + config.max_detections = 0; + } + if (limit_max) + ImGui::SliderInt("Max Detections", &config.max_detections, 1, 100); if (ImGui::Checkbox("Fixed model size", &config.fixed_input_size)) { @@ -168,42 +182,71 @@ void draw_ai() config.saveConfig(); } + bool small_changed = false; ImGui::Separator(); - ImGui::Text("Color Detection (HSV)"); - ImGui::Separator(); - - // выбор целевого цвета - std::vector colorItems; - for (const auto& cr : config.color_ranges) { - colorItems.push_back(cr.name.c_str()); + ImGui::Text("Small Target Enhancement"); + if (ImGui::Checkbox("Enable Small Target Enhancement", &config.small_target_enhancement_enabled)) + small_changed = true; + if (config.small_target_enhancement_enabled) + { + if (ImGui::SliderFloat("Small Target Boost", &config.small_target_boost_factor, 0.0f, 5.0f, "%.2f")) + small_changed = true; + if (ImGui::SliderFloat("Small Target Threshold", &config.small_target_threshold, 0.0f, 0.20f, "%.3f")) + small_changed = true; + if (ImGui::SliderFloat("Medium Target Threshold", &config.small_target_medium_threshold, 0.0f, 0.20f, "%.3f")) + small_changed = true; + if (ImGui::SliderFloat("Medium Target Boost", &config.small_target_medium_boost, 0.0f, 5.0f, "%.2f")) + small_changed = true; + if (ImGui::Checkbox("Small Target Smoothing", &config.small_target_smooth_enabled)) + small_changed = true; + if (config.small_target_smooth_enabled) + { + if (ImGui::SliderInt("Smooth Frames", &config.small_target_smooth_frames, 1, 10)) + small_changed = true; + } } + if (small_changed) + config.saveConfig(); - static int currentColorIndex = 0; - for (size_t i = 0; i < config.color_ranges.size(); ++i) { - if (config.color_ranges[i].name == config.color_target) { - currentColorIndex = static_cast(i); - break; + if (config.backend == "COLOR") + { + ImGui::Separator(); + ImGui::Text("Color Detection (HSV)"); + ImGui::Separator(); + + // ????? ???????? ????? + std::vector colorItems; + for (const auto& cr : config.color_ranges) { + colorItems.push_back(cr.name.c_str()); } - } - if (!colorItems.empty()) { - if (ImGui::Combo("Target Color", ¤tColorIndex, colorItems.data(), (int)colorItems.size())) { - config.color_target = config.color_ranges[currentColorIndex].name; + static int currentColorIndex = 0; + for (size_t i = 0; i < config.color_ranges.size(); ++i) { + if (config.color_ranges[i].name == config.color_target) { + currentColorIndex = static_cast(i); + break; + } + } + + if (!colorItems.empty()) { + if (ImGui::Combo("Target Color", ¤tColorIndex, colorItems.data(), (int)colorItems.size())) { + config.color_target = config.color_ranges[currentColorIndex].name; + config.saveConfig(); + detector_model_changed.store(true); + } + } + + if (ImGui::SliderInt("Erode Iterations", &config.color_erode_iter, 0, 5)) { + config.saveConfig(); + detector_model_changed.store(true); + } + if (ImGui::SliderInt("Dilate Iterations", &config.color_dilate_iter, 0, 5)) { + config.saveConfig(); + detector_model_changed.store(true); + } + if (ImGui::SliderInt("Min Area", &config.color_min_area, 10, 1000)) { config.saveConfig(); detector_model_changed.store(true); } - } - - if (ImGui::SliderInt("Erode Iterations", &config.color_erode_iter, 0, 5)) { - config.saveConfig(); - detector_model_changed.store(true); - } - if (ImGui::SliderInt("Dilate Iterations", &config.color_dilate_iter, 0, 5)) { - config.saveConfig(); - detector_model_changed.store(true); - } - if (ImGui::SliderInt("Min Area", &config.color_min_area, 10, 1000)) { - config.saveConfig(); - detector_model_changed.store(true); } } diff --git a/sunone_aimbot_cpp/overlay/draw_buttons.cpp b/RN_AI_cpp/overlay/draw_buttons.cpp similarity index 99% rename from sunone_aimbot_cpp/overlay/draw_buttons.cpp rename to RN_AI_cpp/overlay/draw_buttons.cpp index cdb6c42f..c12fab39 100644 --- a/sunone_aimbot_cpp/overlay/draw_buttons.cpp +++ b/RN_AI_cpp/overlay/draw_buttons.cpp @@ -4,7 +4,7 @@ #include #include "imgui/imgui.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "overlay.h" void draw_buttons() diff --git a/RN_AI_cpp/overlay/draw_capture.cpp b/RN_AI_cpp/overlay/draw_capture.cpp new file mode 100644 index 00000000..413c72ba --- /dev/null +++ b/RN_AI_cpp/overlay/draw_capture.cpp @@ -0,0 +1,342 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#include +#include +#include + +#include +#include "imgui/imgui_internal.h" + +#include "config.h" +#include "rn_ai_cpp.h" +#include "capture.h" +#include "other_tools.h" +#include "virtual_camera.h" +#include "draw_settings.h" +#include "overlay.h" +#include "ui_sections.h" +#include "config_dirty.h" +#include "ui_controls.h" +#include "ui_runtime.h" + +bool disable_winrt_futures = checkwin1903(); +int monitors = get_active_monitors(); + +static std::vector virtual_cameras; +static char virtual_camera_filter_buf[128] = ""; +static char obs_ip_buf[64] = ""; +static bool obs_buf_inited = false; + +void ensureVirtualCamerasLoaded() { + if (virtual_cameras.empty()) { + virtual_cameras = VirtualCameraCapture::GetAvailableVirtualCameras(); + } +} + +void draw_capture_settings() +{ + static const int allowed_resolutions[] = { 220, 320, 640 }; + static int winrt_source_mode = 0; // 0 = monitor, 1 = window title (preview UI) + static char winrt_window_title_buf[128] = ""; + if (OverlayUI::BeginCard("GENERAL CAPTURE SETTINGS", "capture_core_card")) + { + std::vector captureMethodOptions = { "duplication_api", "winrt", "virtual_camera", "obs" }; + std::vector captureMethodItems; + captureMethodItems.push_back("duplication_api"); + captureMethodItems.push_back("winrt"); + captureMethodItems.push_back("virtual_camera"); + captureMethodItems.push_back("obs"); + + int currentcaptureMethodIndex = 0; + for (size_t i = 0; i < captureMethodOptions.size(); ++i) + { + if (captureMethodOptions[i] == config.capture_method) + { + currentcaptureMethodIndex = static_cast(i); + break; + } + } + + int current_resolution_idx = 1; + for (int i = 0; i < 3; ++i) + if (config.detection_resolution == allowed_resolutions[i]) + current_resolution_idx = i; + OverlayUI::AdaptiveItemWidth(1.0f, 220.0f, 560.0f); + if (ImGui::Combo("Detection Resolution", ¤t_resolution_idx, "220\0""320\0""640\0")) + { + const int chosen = allowed_resolutions[current_resolution_idx]; + if (chosen != config.detection_resolution) + { + config.detection_resolution = chosen; + detection_resolution_changed.store(true); + detector_model_changed.store(true); + + globalMouseThread->updateConfig( + config.detection_resolution, + config.fovX, + config.fovY, + config.minSpeedMultiplier, + config.maxSpeedMultiplier, + config.predictionInterval, + config.auto_shoot, + config.bScope_multiplier, + config.triggerbot_bScope_multiplier); + OverlayConfig_MarkDirty(); + } + } + if (OverlayUI::g_show_descriptions) + ImGui::TextDisabled("Input size for AI model - higher = more accurate but slower"); + + ImGui::TextUnformatted("Capture Method"); + OverlayUI::AdaptiveItemWidth(1.0f, 220.0f, 560.0f); + if (ImGui::Combo("##capture_method_combo", ¤tcaptureMethodIndex, captureMethodItems.data(), static_cast(captureMethodItems.size()))) + { + config.capture_method = captureMethodOptions[currentcaptureMethodIndex]; + capture_method_changed.store(true); + OverlayConfig_MarkDirty(); + } + if (OverlayUI::g_show_descriptions) + ImGui::TextDisabled("duplication_api / winrt / virtual_camera / obs"); + + if (OverlayUI::IntControlRow( + "Capture FPS", + &config.capture_fps, + 0, + 400, + 1, + "FPS", + config.capture_fps == 0 ? "Capture thread disabled" : nullptr)) + { + capture_fps_changed.store(true); + OverlayConfig_MarkDirty(); + } + if (OverlayUI::g_show_descriptions) + ImGui::TextDisabled("Current: %d FPS", config.capture_fps); + + if (config.capture_fps == 0 || config.capture_fps >= 61) + { + ImGui::TextColored(ImVec4(1.0f, 0.85f, 0.35f, 1.0f), "Warning: high FPS may reduce performance."); + } + + if (ImGui::Checkbox("Enable Circle Mask", &config.circle_mask)) + { + capture_method_changed.store(true); + OverlayConfig_MarkDirty(); + } + if (OverlayUI::g_show_descriptions) + ImGui::TextDisabled("Only detect targets in circular FOV (reduces false positives)"); + +#ifdef USE_CUDA + if (config.backend == "TRT") + { + const bool cudaCaptureAvailable = (config.capture_method == "duplication_api"); + if (!cudaCaptureAvailable) + ImGui::BeginDisabled(); + + if (ImGui::Checkbox("CUDA Direct Capture", &config.capture_use_cuda)) + { + capture_method_changed.store(true); + OverlayConfig_MarkDirty(); + } + if (OverlayUI::g_show_descriptions) + ImGui::TextDisabled("Zero-copy GPU capture for lowest latency (requires NVIDIA GPU)"); + + if (!cudaCaptureAvailable) + { + ImGui::EndDisabled(); + ImGui::TextDisabled("Available only with duplication_api."); + } + } +#endif + + if (config.capture_method == "duplication_api" || config.capture_method == "winrt" || config.capture_method == "obs") + { + std::vector monitorNames; + if (monitors == -1) + { + monitorNames.push_back("Monitor 1"); + } + else + { + for (int i = -1; i < monitors; ++i) + { + monitorNames.push_back("Monitor " + std::to_string(i + 1)); + } + } + + std::vector monitorItems; + for (const auto& name : monitorNames) + { + monitorItems.push_back(name.c_str()); + } + + OverlayUI::AdaptiveItemWidth(); + if (ImGui::Combo("Capture monitor", &config.monitor_idx, monitorItems.data(), static_cast(monitorItems.size()))) + { + capture_method_changed.store(true); + OverlayConfig_MarkDirty(); + } + } + } + OverlayUI::EndCard(); + + if (config.capture_method == "winrt") + { + if (OverlayUI::BeginCard("WINRT SETTINGS", "capture_winrt")) + { + OverlayUI::AdaptiveItemWidth(); + ImGui::Combo("Source mode", &winrt_source_mode, "Monitor\0Window title (preview)\0"); + if (winrt_source_mode == 1) + { + OverlayUI::AdaptiveItemWidth(); + ImGui::InputText("Window title", winrt_window_title_buf, IM_ARRAYSIZE(winrt_window_title_buf)); + ImGui::TextDisabled("Current backend uses monitor capture only."); + } + + if (disable_winrt_futures) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + + if (ImGui::Checkbox("Capture Borders", &config.capture_borders)) + { + capture_borders_changed.store(true); + OverlayConfig_MarkDirty(); + } + + if (ImGui::Checkbox("Capture Cursor", &config.capture_cursor)) + { + capture_cursor_changed.store(true); + OverlayConfig_MarkDirty(); + } + + if (disable_winrt_futures) + { + ImGui::PopStyleVar(); + ImGui::PopItemFlag(); + } + } + OverlayUI::EndCard(); + } + + if (config.capture_method == "virtual_camera") + { + if (OverlayUI::BeginCard("VIRTUAL CAMERA", "capture_virtual_camera")) + { + ensureVirtualCamerasLoaded(); + ImGui::Text("Select virtual camera:"); + + ImGui::Text("Filter:"); + OverlayUI::AdaptiveItemWidth(); + ImGui::InputText("##VCFilter", virtual_camera_filter_buf, IM_ARRAYSIZE(virtual_camera_filter_buf)); + + std::string filter_lower = virtual_camera_filter_buf; + std::transform(filter_lower.begin(), filter_lower.end(), filter_lower.begin(), ::tolower); + + std::vector filtered_indices; + for (int i = 0; i < static_cast(virtual_cameras.size()); ++i) + { + std::string name_lower = virtual_cameras[i]; + std::transform(name_lower.begin(), name_lower.end(), name_lower.begin(), ::tolower); + if (filter_lower.empty() || name_lower.find(filter_lower) != std::string::npos) + { + filtered_indices.push_back(i); + } + } + + if (!filtered_indices.empty()) + { + int currentIndex = 0; + for (int fi = 0; fi < static_cast(filtered_indices.size()); ++fi) + { + if (virtual_cameras[filtered_indices[fi]] == config.virtual_camera_name) + { + currentIndex = fi; + break; + } + } + + std::vector items; + items.reserve(filtered_indices.size()); + for (int idx : filtered_indices) + { + items.push_back(virtual_cameras[idx].c_str()); + } + + OverlayUI::AdaptiveItemWidth(); + if (ImGui::Combo("##virtual_camera_combo", ¤tIndex, items.data(), static_cast(items.size()))) + { + config.virtual_camera_name = virtual_cameras[filtered_indices[currentIndex]]; + capture_method_changed.store(true); + OverlayConfig_MarkDirty(); + } + } + else + { + ImGui::TextDisabled("No matching virtual cameras"); + } + + ImGui::SameLine(); + if (ImGui::Button("Refresh")) + { + VirtualCameraCapture::ClearCachedCameraList(); + virtual_cameras = VirtualCameraCapture::GetAvailableVirtualCameras(true); + virtual_camera_filter_buf[0] = '\0'; + } + + if (OverlayUI::IntControlRow("Virtual camera width", &config.virtual_camera_width, 128, 3840, 8, "px")) + { + capture_method_changed.store(true); + OverlayConfig_MarkDirty(); + } + + if (OverlayUI::IntControlRow("Virtual camera heigth", &config.virtual_camera_heigth, 128, 2160, 8, "px")) + { + capture_method_changed.store(true); + OverlayConfig_MarkDirty(); + } + } + OverlayUI::EndCard(); + } + + if (config.capture_method == "obs") + { + if (OverlayUI::BeginCard("OBS", "capture_obs")) + { + if (ImGui::Checkbox("Enable OBS", &config.is_obs)) + { + OverlayConfig_MarkDirty(); + } + if (!obs_buf_inited) + { + strncpy_s(obs_ip_buf, sizeof(obs_ip_buf), config.obs_ip.c_str(), _TRUNCATE); + obs_buf_inited = true; + } + OverlayUI::AdaptiveItemWidth(); + if (ImGui::InputText("OBS IP", obs_ip_buf, IM_ARRAYSIZE(obs_ip_buf))) + { + config.obs_ip = obs_ip_buf; + OverlayConfig_MarkDirty(); + } + OverlayUI::AdaptiveItemWidth(); + if (ImGui::InputInt("OBS Port", &config.obs_port)) + { + if (config.obs_port < 0) + config.obs_port = 0; + OverlayConfig_MarkDirty(); + } + OverlayUI::AdaptiveItemWidth(); + if (ImGui::InputInt("OBS FPS", &config.obs_fps)) + { + if (config.obs_fps < 0) + config.obs_fps = 0; + OverlayConfig_MarkDirty(); + } + } + OverlayUI::EndCard(); + } +} diff --git a/RN_AI_cpp/overlay/draw_classes.cpp b/RN_AI_cpp/overlay/draw_classes.cpp new file mode 100644 index 00000000..6c5437de --- /dev/null +++ b/RN_AI_cpp/overlay/draw_classes.cpp @@ -0,0 +1,235 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "imgui/imgui.h" + +#include "rn_ai_cpp.h" + +static const char* get_class_name(int cls) +{ + if (cls == config.class_player) return "Player"; + if (cls == config.class_bot) return "Bot"; + if (cls == config.class_weapon) return "Weapon"; + if (cls == config.class_outline) return "Outline"; + if (cls == config.class_dead_body) return "Dead Body"; + if (cls == config.class_hideout_target_human) return "Hideout Human"; + if (cls == config.class_hideout_target_balls) return "Hideout Balls"; + if (cls == config.class_head) return "Head"; + if (cls == config.class_smoke) return "Smoke"; + if (cls == config.class_fire) return "Fire"; + if (cls == config.class_third_person) return "Third Person"; + return nullptr; +} + +static std::string trim_ascii(const std::string& s) +{ + size_t start = 0; + while (start < s.size() && (s[start] == ' ' || s[start] == '\t' || s[start] == '\r' || s[start] == '\n')) + ++start; + size_t end = s.size(); + while (end > start && (s[end - 1] == ' ' || s[end - 1] == '\t' || s[end - 1] == '\r' || s[end - 1] == '\n')) + --end; + return s.substr(start, end - start); +} + +static bool load_names_file(const std::string& path, std::vector& out) +{ + std::ifstream file(path); + if (!file.is_open()) + return false; + + out.clear(); + std::string line; + while (std::getline(file, line)) + { + std::string trimmed = trim_ascii(line); + if (trimmed.empty()) + continue; + if (!trimmed.empty() && trimmed[0] == '#') + continue; + out.push_back(trimmed); + } + return !out.empty(); +} + +static bool load_model_class_names( + const std::string& model_name, + std::vector& out, + std::string& source_path) +{ + out.clear(); + source_path.clear(); + if (model_name.empty()) + return false; + + std::filesystem::path model_path = std::filesystem::path("models") / model_name; + std::string stem = model_path.stem().string(); + + const std::vector candidates = { + model_path.parent_path() / (stem + ".names"), + model_path.parent_path() / (stem + ".txt"), + model_path.parent_path() / "classes.txt", + model_path.parent_path() / "labels.txt" + }; + + for (const auto& candidate : candidates) + { + if (!std::filesystem::exists(candidate)) + continue; + std::vector names; + if (load_names_file(candidate.string(), names)) + { + out = std::move(names); + source_path = candidate.string(); + return true; + } + } + + return false; +} + +static void draw_detected_classes() +{ + static std::map seen_classes; + std::map current_counts; + + { + std::lock_guard lock(detectionBuffer.mutex); + for (int cls : detectionBuffer.classes) + { + current_counts[cls] += 1; + seen_classes[cls] = 1; + } + } + + ImGui::SeparatorText("Detected Classes"); + if (ImGui::Button("Clear Seen Classes")) + { + seen_classes.clear(); + } + + if (current_counts.empty()) + { + ImGui::TextDisabled("Current frame: no detections"); + } + else + { + ImGui::Text("Current frame:"); + for (const auto& kv : current_counts) + { + int cls = kv.first; + int count = kv.second; + const char* name = get_class_name(cls); + if (name) + ImGui::Text(" - %s [%d] x%d", name, cls, count); + else + ImGui::Text(" - Class %d x%d", cls, count); + } + } + + if (seen_classes.empty()) + { + ImGui::TextDisabled("Seen this session: none"); + } + else + { + ImGui::Text("Seen this session:"); + for (const auto& kv : seen_classes) + { + int cls = kv.first; + const char* name = get_class_name(cls); + if (name) + ImGui::Text(" - %s [%d]", name, cls); + else + ImGui::Text(" - Class %d", cls); + } + } +} + +static void draw_class_mapping() +{ + ImGui::SeparatorText("Class Mapping"); + + auto edit_class = [](const char* label, int& value) -> bool { + int prev = value; + if (ImGui::InputInt(label, &value)) + { + if (value < 0) value = 0; + return value != prev; + } + return false; + }; + + bool class_changed = false; + class_changed |= edit_class("Player Class Id", config.class_player); + class_changed |= edit_class("Bot Class Id", config.class_bot); + class_changed |= edit_class("Head Class Id", config.class_head); + class_changed |= edit_class("Third Person Class Id", config.class_third_person); + class_changed |= edit_class("Hideout Human Class Id", config.class_hideout_target_human); + class_changed |= edit_class("Hideout Balls Class Id", config.class_hideout_target_balls); + class_changed |= edit_class("Weapon Class Id", config.class_weapon); + class_changed |= edit_class("Outline Class Id", config.class_outline); + class_changed |= edit_class("Dead Body Class Id", config.class_dead_body); + class_changed |= edit_class("Smoke Class Id", config.class_smoke); + class_changed |= edit_class("Fire Class Id", config.class_fire); + + if (class_changed) + { + config.saveConfig(); + } +} + +static void draw_model_classes() +{ + static std::string cached_model; + static std::vector cached_names; + static std::string cached_source; + static bool cached_loaded = false; + + bool reload = false; + if (ImGui::Button("Reload Class Names")) + reload = true; + + if (cached_model != config.ai_model || reload) + { + cached_model = config.ai_model; + cached_loaded = load_model_class_names(cached_model, cached_names, cached_source); + } + + ImGui::SeparatorText("Model Classes"); + if (cached_loaded) + { + ImGui::Text("Source: %s", cached_source.c_str()); + ImGui::Text("Total: %d", static_cast(cached_names.size())); + + ImGui::BeginChild("##model_class_list", ImVec2(0, 90), true); + for (size_t i = 0; i < cached_names.size(); ++i) + { + ImGui::Text(" - %zu: %s", i, cached_names[i].c_str()); + } + ImGui::EndChild(); + } + else + { + ImGui::TextDisabled("No labels file found for current model."); + ImGui::TextDisabled("Expected: models/.names or models/.txt"); + } +} + +void draw_classes() +{ + draw_class_mapping(); + ImGui::Separator(); + draw_model_classes(); + ImGui::Separator(); + draw_detected_classes(); +} diff --git a/RN_AI_cpp/overlay/draw_components.cpp b/RN_AI_cpp/overlay/draw_components.cpp new file mode 100644 index 00000000..6def47c5 --- /dev/null +++ b/RN_AI_cpp/overlay/draw_components.cpp @@ -0,0 +1,95 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#include +#include + +#include "imgui/imgui.h" + +#include "ui_sections.h" +#include "ui_theme.h" +#include "ui_runtime.h" + +void draw_components() +{ + ImGuiStyle& style = ImGui::GetStyle(); + bool changed = false; + static std::array bg_path_buf{}; + static bool bg_path_init = false; + if (!bg_path_init) + { + const std::string p = OverlayUI::g_menu_bg_path.empty() ? "ui_bg.png" : OverlayUI::g_menu_bg_path; + const size_t n = (std::min)(p.size(), bg_path_buf.size() - 1); + memcpy(bg_path_buf.data(), p.data(), n); + bg_path_buf[n] = '\0'; + bg_path_init = true; + } + + if (OverlayUI::BeginCard("DESIGN TOKENS", "components_tokens")) + { + changed |= ImGui::Checkbox("Show descriptions", &OverlayUI::g_show_descriptions); + + if (ImGui::BeginTable("components_layout", 2, ImGuiTableFlags_SizingStretchSame)) + { + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(160.0f); + changed |= ImGui::SliderFloat("Button width", &OverlayUI::g_row_button_width, 18.0f, 40.0f, "%.0f"); + ImGui::SetNextItemWidth(160.0f); + changed |= ImGui::SliderFloat("Input width", &OverlayUI::g_row_input_width, 46.0f, 120.0f, "%.0f"); + ImGui::SetNextItemWidth(160.0f); + changed |= ImGui::SliderFloat("Nav width", &OverlayUI::g_nav_width, 120.0f, 360.0f, "%.0f"); + changed |= ImGui::Checkbox("Enable menu background", &OverlayUI::g_menu_bg_enabled); + ImGui::SetNextItemWidth(160.0f); + changed |= ImGui::SliderFloat("BG opacity", &OverlayUI::g_menu_bg_opacity, 0.02f, 1.0f, "%.2f"); + ImGui::SetNextItemWidth(280.0f); + if (ImGui::InputText("BG image path", bg_path_buf.data(), bg_path_buf.size())) + { + OverlayUI::g_menu_bg_path = bg_path_buf.data(); + changed = true; + } + ImGui::SetNextItemWidth(160.0f); + changed |= ImGui::SliderFloat("Item Spacing X", &style.ItemSpacing.x, 2.0f, 24.0f, "%.1f"); + ImGui::SetNextItemWidth(160.0f); + changed |= ImGui::SliderFloat("Item Spacing Y", &style.ItemSpacing.y, 2.0f, 24.0f, "%.1f"); + ImGui::SetNextItemWidth(160.0f); + changed |= ImGui::SliderFloat("Frame Padding X", &style.FramePadding.x, 2.0f, 24.0f, "%.1f"); + ImGui::SetNextItemWidth(160.0f); + changed |= ImGui::SliderFloat("Frame Padding Y", &style.FramePadding.y, 1.0f, 20.0f, "%.1f"); + ImGui::SetNextItemWidth(160.0f); + changed |= ImGui::SliderFloat("Frame Rounding", &style.FrameRounding, 0.0f, 8.0f, "%.1f"); + ImGui::SetNextItemWidth(160.0f); + changed |= ImGui::SliderFloat("Window Rounding", &style.WindowRounding, 0.0f, 8.0f, "%.1f"); + ImGui::SetNextItemWidth(160.0f); + changed |= ImGui::SliderFloat("Alpha", &style.Alpha, 0.2f, 1.0f, "%.2f"); + + ImGui::TableNextColumn(); + changed |= ImGui::ColorEdit4("Text", (float*)&style.Colors[ImGuiCol_Text], ImGuiColorEditFlags_NoInputs); + changed |= ImGui::ColorEdit4("Window Bg", (float*)&style.Colors[ImGuiCol_WindowBg], ImGuiColorEditFlags_NoInputs); + changed |= ImGui::ColorEdit4("Frame Bg", (float*)&style.Colors[ImGuiCol_FrameBg], ImGuiColorEditFlags_NoInputs); + changed |= ImGui::ColorEdit4("Button", (float*)&style.Colors[ImGuiCol_Button], ImGuiColorEditFlags_NoInputs); + changed |= ImGui::ColorEdit4("Border", (float*)&style.Colors[ImGuiCol_Border], ImGuiColorEditFlags_NoInputs); + changed |= ImGui::ColorEdit4("Tab", (float*)&style.Colors[ImGuiCol_Tab], ImGuiColorEditFlags_NoInputs); + changed |= ImGui::ColorEdit4("Tab Active", (float*)&style.Colors[ImGuiCol_TabActive], ImGuiColorEditFlags_NoInputs); + ImGui::EndTable(); + } + + if (ImGui::Button("Reload ui_theme.ini")) + changed |= OverlayTheme_Reload("ui_theme.ini"); + + } + OverlayUI::EndCard(); + + if (OverlayUI::BeginCard("ADVANCED", "components_advanced")) + { + ImGui::SetNextItemWidth(220.0f); + changed |= ImGui::SliderFloat("Overlay FPS text size", &OverlayUI::g_overlay_fps_text_size, 10.0f, 48.0f, "%.1f"); + ImGui::SetNextItemWidth(220.0f); + changed |= ImGui::SliderFloat("Overlay Latency text size", &OverlayUI::g_overlay_latency_text_size, 10.0f, 48.0f, "%.1f"); + } + OverlayUI::EndCard(); + + if (changed) + OverlayTheme_Save("ui_theme.ini"); +} diff --git a/sunone_aimbot_cpp/overlay/draw_debug.cpp b/RN_AI_cpp/overlay/draw_debug.cpp similarity index 54% rename from sunone_aimbot_cpp/overlay/draw_debug.cpp rename to RN_AI_cpp/overlay/draw_debug.cpp index 8a00fdc9..40369e33 100644 --- a/sunone_aimbot_cpp/overlay/draw_debug.cpp +++ b/RN_AI_cpp/overlay/draw_debug.cpp @@ -1,15 +1,22 @@ -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #define _WINSOCKAPI_ #include #include #include +#include +#include +#include +#include +#include +#include #include "imgui/imgui.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "overlay.h" #include "include/other_tools.h" #include "capture.h" +#include "ui_sections.h" #ifndef SAFE_RELEASE #define SAFE_RELEASE(p) \ @@ -21,7 +28,6 @@ } while (0) #endif -int prev_screenshot_delay = config.screenshot_delay; bool prev_verbose = config.verbose; static ID3D11Texture2D* g_debugTex = nullptr; @@ -31,6 +37,25 @@ static int texW = 0, texH = 0; static float debug_scale = 1.0f; +static std::vector parse_int_list_local(const std::string& text) +{ + std::vector values; + std::string cleaned; + cleaned.reserve(text.size()); + for (char c : text) + { + if (std::isdigit(static_cast(c))) + cleaned.push_back(c); + else + cleaned.push_back(' '); + } + std::stringstream ss(cleaned); + int val = 0; + while (ss >> val) + values.push_back(val); + return values; +} + static void uploadDebugFrame(const cv::Mat& bgr) { if (bgr.empty()) return; @@ -88,6 +113,7 @@ void draw_debug_frame() if (!g_debugSRV) return; + ImGui::SetNextItemWidth((std::min)(220.0f, ImGui::GetContentRegionAvail().x)); ImGui::SliderFloat("Debug scale", &debug_scale, 0.1f, 2.0f, "%.1fx"); ImVec2 image_size(texW * debug_scale, texH * debug_scale); @@ -97,9 +123,35 @@ void draw_debug_frame() ImDrawList* draw_list = ImGui::GetWindowDrawList(); { + auto allowed_list = parse_int_list_local(config.allowed_classes); + std::unordered_set allowed_set(allowed_list.begin(), allowed_list.end()); + + auto is_class_visible = [&](int cls) -> bool + { + auto it_name = config.custom_class_names.find(cls); + if (it_name != config.custom_class_names.end() && it_name->second == "__deleted__") + return false; + if (config.disable_headshot && cls == config.class_head) + return false; + if (cls == config.class_third_person && config.ignore_third_person) + return false; + if ((cls == config.class_hideout_target_human || cls == config.class_hideout_target_balls) && + !config.shooting_range_targets) + return false; + if (allowed_set.empty()) + return false; + return allowed_set.count(cls) > 0; + }; + std::lock_guard lock(detectionBuffer.mutex); for (size_t i = 0; i < detectionBuffer.boxes.size(); ++i) { + int cls = -1; + if (i < detectionBuffer.classes.size()) + cls = detectionBuffer.classes[i]; + if (cls >= 0 && !is_class_visible(cls)) + continue; + const cv::Rect& box = detectionBuffer.boxes[i]; ImVec2 p1(image_pos.x + box.x * debug_scale, @@ -111,9 +163,9 @@ void draw_debug_frame() draw_list->AddRect(p1, p2, color, 0.0f, 0, 2.0f); - if (i < detectionBuffer.classes.size()) + if (cls >= 0) { - std::string label = "Class " + std::to_string(detectionBuffer.classes[i]); + std::string label = "Class " + std::to_string(cls); draw_list->AddText(ImVec2(p1.x, p1.y - 16), IM_COL32(255, 255, 0, 255), label.c_str()); } } @@ -158,90 +210,85 @@ void draw_debug_frame() void draw_debug() { + static bool show_raw_preview = false; + ImGui::Checkbox("Show Debug Window", &config.show_window); - if (config.show_window) + ImGui::SameLine(); + ImGui::Checkbox("Raw Preview", &show_raw_preview); + if (config.show_window && show_raw_preview) { draw_debug_frame(); ImGui::Separator(); } - ImGui::Text("Screenshot Buttons"); - - for (size_t i = 0; i < config.screenshot_button.size(); ) + if (OverlayUI::BeginCard("PIPELINE STATUS", "debug_pipeline")) { - std::string& current_key_name = config.screenshot_button[i]; - - int current_index = -1; - for (size_t k = 0; k < key_names.size(); ++k) + if (ImGui::BeginTable("debug_pipeline_tbl", 2, ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_BordersInnerV)) { - if (key_names[k] == current_key_name) + auto row = [](const char* left, const char* right) { - current_index = static_cast(k); - break; - } - } - - if (current_index == -1) - { - current_index = 0; - } - - std::string combo_label = "Screenshot Button " + std::to_string(i); - - if (ImGui::Combo(combo_label.c_str(), ¤t_index, key_names_cstrs.data(), static_cast(key_names_cstrs.size()))) - { - current_key_name = key_names[current_index]; - config.saveConfig("config.ini"); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(left); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(right); + }; + row("Capture Thread", "Running"); + row("Preprocessor", "Active"); + row("AI Detector", "Inference OK"); + row("Mouse Controller", "Idle"); + row("OBS Connection", config.is_obs ? "Enabled" : "Disabled"); + ImGui::EndTable(); } + } + OverlayUI::EndCard(); - ImGui::SameLine(); - std::string remove_button_label = "Remove##button_screenshot" + std::to_string(i); - if (ImGui::Button(remove_button_label.c_str())) + if (OverlayUI::BeginCard("RUNTIME INFO", "debug_runtime")) + { + static int totalFrames = 0; + totalFrames += 1; + if (ImGui::BeginTable("debug_runtime_tbl", 2, ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_BordersInnerV)) { - if (config.screenshot_button.size() <= 1) - { - config.screenshot_button[0] = std::string("None"); - config.saveConfig(); - continue; - } - else + auto rowf = [](const char* left, const char* fmt, auto val) { - config.screenshot_button.erase(config.screenshot_button.begin() + i); - config.saveConfig(); - continue; - } + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(left); + ImGui::TableNextColumn(); + ImGui::Text(fmt, val); + }; + rowf("Uptime", "%.2f s", ImGui::GetTime()); + rowf("Total Frames", "%d", totalFrames); + rowf("Dropped Frames", "%d", 0); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Memory Usage"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("n/a"); + rowf("Thread Count", "%d", 8); + ImGui::EndTable(); } - - ++i; - } - - if (ImGui::Button("Add button##button_screenshot")) - { - config.screenshot_button.push_back("None"); - config.saveConfig(); } - - ImGui::InputInt("Screenshot delay", &config.screenshot_delay, 50, 500); - ImGui::Checkbox("Verbose console output", &config.verbose); + OverlayUI::EndCard(); ImGui::Separator(); + ImGui::Checkbox("Verbose console output", &config.verbose); + ImGui::TextDisabled("Writes all std::cout/std::cerr to runtime_console.log"); - ImGui::Text("Test functions"); - if (ImGui::Button("Free terminal")) - { - HideConsole(); - } - ImGui::SameLine(); - if (ImGui::Button("Restore terminal")) + if (prev_verbose != config.verbose) { - ShowConsole(); + prev_verbose = config.verbose; + SetConsoleFileLoggingEnabled(config.verbose, false); + config.saveConfig(); } - if (prev_screenshot_delay != config.screenshot_delay || - prev_verbose != config.verbose) + if (OverlayUI::BeginCard("LOG ACTIONS", "debug_actions")) { - prev_screenshot_delay = config.screenshot_delay; - prev_verbose = config.verbose; - config.saveConfig(); + if (ImGui::Button("Open Log Folder")) + std::cout << "[INFO] Open log folder clicked" << std::endl; + ImGui::SameLine(); + if (ImGui::Button("Export Logs")) + std::cout << "[INFO] Export logs clicked" << std::endl; } -} \ No newline at end of file + OverlayUI::EndCard(); +} diff --git a/RN_AI_cpp/overlay/draw_game_overlay.cpp b/RN_AI_cpp/overlay/draw_game_overlay.cpp new file mode 100644 index 00000000..54e4e5c6 --- /dev/null +++ b/RN_AI_cpp/overlay/draw_game_overlay.cpp @@ -0,0 +1,416 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#include +#include +#include +#include + +#include "imgui/imgui.h" +#include "config.h" +#include "rn_ai_cpp.h" +#include "capture.h" +#include "overlay/config_dirty.h" +#include "overlay/ui_sections.h" + +std::string g_iconLastError; + +void draw_game_overlay_settings() +{ + if (OverlayUI::BeginSection("General", "game_overlay_section_general")) + { + if (ImGui::Checkbox("Enable", &config.game_overlay_enabled)) + OverlayConfig_MarkDirty(); + + ImGui::SliderInt("Overlay Max FPS (0 = uncapped)", &config.game_overlay_max_fps, 0, 256); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + if (ImGui::Checkbox("Draw Detection Boxes", &config.game_overlay_draw_boxes)) + OverlayConfig_MarkDirty(); + + if (ImGui::Checkbox("Draw Future Positions", &config.game_overlay_draw_future)) + OverlayConfig_MarkDirty(); + + if (ImGui::Checkbox("Draw Wind Debug Tail", &config.game_overlay_draw_wind_tail)) + OverlayConfig_MarkDirty(); + + if (ImGui::Checkbox("Show Target Correction", &config.game_overlay_show_target_correction)) + OverlayConfig_MarkDirty(); + + if (ImGui::Checkbox("Show FPS Counter", &config.game_overlay_show_fps_counter)) + OverlayConfig_MarkDirty(); + + if (ImGui::Checkbox("Show Latency", &config.game_overlay_show_latency)) + OverlayConfig_MarkDirty(); + + OverlayUI::EndSection(); + } + + if (OverlayUI::BeginSection("Box Color", "game_overlay_section_box_color")) + { + bool colorChanged = false; + + ImGui::SliderInt("A##go_box_a", &config.game_overlay_box_a, 0, 255); + colorChanged |= ImGui::IsItemEdited(); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderInt("R##go_box_r", &config.game_overlay_box_r, 0, 255); + colorChanged |= ImGui::IsItemEdited(); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderInt("G##go_box_g", &config.game_overlay_box_g, 0, 255); + colorChanged |= ImGui::IsItemEdited(); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderInt("B##go_box_b", &config.game_overlay_box_b, 0, 255); + colorChanged |= ImGui::IsItemEdited(); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderFloat("Box Thickness", &config.game_overlay_box_thickness, 0.5f, 10.0f, "%.1f"); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + if (colorChanged) + config.clampGameOverlayColor(); + + OverlayUI::EndSection(); + } + + if (OverlayUI::BeginSection("Capture Frame", "game_overlay_section_capture_frame")) + { + if (ImGui::Checkbox("Draw Capture Frame", &config.game_overlay_draw_frame)) + OverlayConfig_MarkDirty(); + + bool frameColorChanged = false; + + ImGui::SliderInt("A##go_frame_a", &config.game_overlay_frame_a, 0, 255); + frameColorChanged |= ImGui::IsItemEdited(); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderInt("R##go_frame_r", &config.game_overlay_frame_r, 0, 255); + frameColorChanged |= ImGui::IsItemEdited(); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderInt("G##go_frame_g", &config.game_overlay_frame_g, 0, 255); + frameColorChanged |= ImGui::IsItemEdited(); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderInt("B##go_frame_b", &config.game_overlay_frame_b, 0, 255); + frameColorChanged |= ImGui::IsItemEdited(); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderFloat("Frame Thickness", &config.game_overlay_frame_thickness, 0.5f, 10.0f, "%.1f"); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + if (frameColorChanged) + config.clampGameOverlayColor(); + + OverlayUI::EndSection(); + } + + if (OverlayUI::BeginSection("Future Point Style", "game_overlay_section_future_style")) + { + ImGui::SliderFloat("Point Radius", &config.game_overlay_future_point_radius, 1.0f, 20.0f, "%.1f"); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderFloat("Point Step Alpha Falloff", &config.game_overlay_future_alpha_falloff, 0.1f, 5.0f, "%.2f"); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + OverlayUI::EndSection(); + } + + if (OverlayUI::BeginSection("Icon Overlay", "game_overlay_section_icon")) + { + if (ImGui::Checkbox("Enable Icon Overlay", &config.game_overlay_icon_enabled)) + OverlayConfig_MarkDirty(); + + if (!config.game_overlay_icon_enabled) + { + ImGui::BeginDisabled(); + } + + static bool pathInit = false; + static char iconPathBuf[512]; + + if (!pathInit) + { + pathInit = true; + memset(iconPathBuf, 0, sizeof(iconPathBuf)); + std::string p = config.game_overlay_icon_path; + if (p.size() >= sizeof(iconPathBuf)) p = p.substr(0, sizeof(iconPathBuf) - 1); + memcpy(iconPathBuf, p.c_str(), p.size()); + } + + if (ImGui::InputText("Icon Path", iconPathBuf, IM_ARRAYSIZE(iconPathBuf))) + { + config.game_overlay_icon_path = iconPathBuf; + OverlayConfig_MarkDirty(); + } + + ImGui::SameLine(); + if (ImGui::Button("Browse##icon_path")) + { + char filePath[MAX_PATH] = {}; + OPENFILENAMEA ofn = {}; + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = nullptr; + ofn.lpstrFile = filePath; + ofn.nMaxFile = sizeof(filePath); + ofn.lpstrFilter = "Image Files\0*.png;*.jpg;*.jpeg;*.bmp;*.ico\0All Files\0*.*\0"; + ofn.nFilterIndex = 1; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR; + + if (GetOpenFileNameA(&ofn)) + { + strncpy_s(iconPathBuf, filePath, sizeof(iconPathBuf) - 1); + config.game_overlay_icon_path = iconPathBuf; + OverlayConfig_MarkDirty(); + } + } + + ImGui::SliderInt("Icon Width", &config.game_overlay_icon_width, 4, 512); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderInt("Icon Height", &config.game_overlay_icon_height, 4, 512); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderFloat("Icon Offset X", &config.game_overlay_icon_offset_x, -500.0f, 500.0f, "%.1f"); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderFloat("Icon Offset Y", &config.game_overlay_icon_offset_y, -500.0f, 500.0f, "%.1f"); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + if (ImGui::InputInt("Icon Class (-1 = all)", &config.game_overlay_icon_class)) + { + if (config.game_overlay_icon_class < -1) config.game_overlay_icon_class = -1; + OverlayConfig_MarkDirty(); + } + + const char* anchors[] = { "center", "top", "bottom", "head" }; + int currentAnchor = 0; + for (int i = 0; i < (int)(sizeof(anchors) / sizeof(anchors[0])); ++i) + { + if (config.game_overlay_icon_anchor == anchors[i]) + { + currentAnchor = i; + break; + } + } + + if (ImGui::Combo("Icon Anchor", ¤tAnchor, anchors, IM_ARRAYSIZE(anchors))) + { + config.game_overlay_icon_anchor = anchors[currentAnchor]; + OverlayConfig_MarkDirty(); + } + + if (!config.game_overlay_icon_enabled) + { + ImGui::EndDisabled(); + ImGui::TextDisabled("Enable Icon Overlay to edit settings."); + } + + OverlayUI::EndSection(); + } + + if (OverlayUI::BeginSection("Aim Simulation", "game_overlay_section_aim_sim")) + { + if (ImGui::Checkbox("Enable Aim Simulation Window", &config.aim_sim_enabled)) + OverlayConfig_MarkDirty(); + + if (!config.aim_sim_enabled) + { + ImGui::BeginDisabled(); + } + + ImGui::SliderInt("Sim X", &config.aim_sim_x, -3000, 3000); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderInt("Sim Y", &config.aim_sim_y, -3000, 3000); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderInt("Sim Width", &config.aim_sim_width, 220, 1600); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + ImGui::SliderInt("Sim Height", &config.aim_sim_height, 180, 1000); + if (ImGui::IsItemDeactivatedAfterEdit()) + OverlayConfig_MarkDirty(); + + if (ImGui::SliderInt("Sim FPS Min", &config.aim_sim_fps_min, 15, 360)) + { + if (config.aim_sim_fps_min > config.aim_sim_fps_max) + config.aim_sim_fps_max = config.aim_sim_fps_min; + OverlayConfig_MarkDirty(); + } + + if (ImGui::SliderInt("Sim FPS Max", &config.aim_sim_fps_max, 15, 360)) + { + if (config.aim_sim_fps_max < config.aim_sim_fps_min) + config.aim_sim_fps_min = config.aim_sim_fps_max; + OverlayConfig_MarkDirty(); + } + + if (ImGui::SliderFloat("FPS Jitter", &config.aim_sim_fps_jitter, 0.0f, 0.8f, "%.3f")) + OverlayConfig_MarkDirty(); + + if (ImGui::SliderFloat("Capture Delay (ms)", &config.aim_sim_capture_delay_ms, 0.0f, 80.0f, "%.1f")) + OverlayConfig_MarkDirty(); + + static bool delayedSnapshotPending = false; + static double delayedSnapshotApplyAt = 0.0; + const auto apply_snapshot_metrics = []() + { + float current_preprocess = 0.0f; + float current_inference = 0.0f; + float current_copy = 0.0f; + float current_post = 0.0f; + float current_nms = 0.0f; + bool hasTimingMetrics = false; + + if (config.backend == "DML" && dml_detector) + { + current_preprocess = static_cast(dml_detector->lastPreprocessTimeDML.count()); + current_inference = static_cast(dml_detector->lastInferenceTimeDML.count()); + current_copy = static_cast(dml_detector->lastCopyTimeDML.count()); + current_post = static_cast(dml_detector->lastPostprocessTimeDML.count()); + current_nms = static_cast(dml_detector->lastNmsTimeDML.count()); + hasTimingMetrics = true; + } +#ifdef USE_CUDA + else + { + current_preprocess = static_cast(trt_detector.lastPreprocessTime.count()); + current_inference = static_cast(trt_detector.lastInferenceTime.count()); + current_copy = static_cast(trt_detector.lastCopyTime.count()); + current_post = static_cast(trt_detector.lastPostprocessTime.count()); + current_nms = static_cast(trt_detector.lastNmsTime.count()); + hasTimingMetrics = true; + } +#endif + + const auto clampf = [](float v, float lo, float hi) -> float + { + if (v < lo) return lo; + if (v > hi) return hi; + return v; + }; + + const float fpsNow = static_cast(captureFps.load()); + if (fpsNow > 1.0f) + { + const float captureDelayMs = 1000.0f / fpsNow; + config.aim_sim_capture_delay_ms = clampf(captureDelayMs, 0.0f, 80.0f); + } + + if (hasTimingMetrics && current_inference > 0.0f) + config.aim_sim_inference_delay_ms = clampf(current_inference, 0.0f, 120.0f); + + if (hasTimingMetrics) + { + const float extraDelayMs = current_preprocess + current_copy + current_post + current_nms; + config.aim_sim_extra_delay_ms = clampf(extraDelayMs, 0.0f, 60.0f); + } + + OverlayConfig_MarkDirty(); + }; + + if (delayedSnapshotPending && ImGui::GetTime() >= delayedSnapshotApplyAt) + { + apply_snapshot_metrics(); + delayedSnapshotPending = false; + } + + if (ImGui::Checkbox("Use Live Inference Delay", &config.aim_sim_use_live_inference)) + OverlayConfig_MarkDirty(); + ImGui::SameLine(); + if (ImGui::Button("Snapshot Metrics")) + apply_snapshot_metrics(); + if (ImGui::IsItemHovered()) + { + ImGui::SetTooltip( + "Capture Delay <- 1000/FPS\n" + "Inference Delay <- current backend inference\n" + "Extra Delay <- preprocess + copy + postprocess + NMS" + ); + } + ImGui::SameLine(); + if (ImGui::Button("Snapshot in 4s")) + { + delayedSnapshotPending = true; + delayedSnapshotApplyAt = ImGui::GetTime() + 4.0; + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Start 4-second timer, then snapshot metrics automatically."); + + if (delayedSnapshotPending) + { + const double remaining = std::max(0.0, delayedSnapshotApplyAt - ImGui::GetTime()); + ImGui::SameLine(); + ImGui::TextDisabled("Auto in %.1fs", static_cast(remaining)); + } + + if (ImGui::SliderFloat("Inference Delay (ms)", &config.aim_sim_inference_delay_ms, 0.0f, 120.0f, "%.1f")) + OverlayConfig_MarkDirty(); + + if (ImGui::SliderFloat("Input Delay (ms)", &config.aim_sim_input_delay_ms, 0.0f, 60.0f, "%.1f")) + OverlayConfig_MarkDirty(); + + if (ImGui::SliderFloat("Extra Delay (ms)", &config.aim_sim_extra_delay_ms, 0.0f, 60.0f, "%.1f")) + OverlayConfig_MarkDirty(); + + if (ImGui::SliderFloat("Target Max Speed", &config.aim_sim_target_max_speed, 20.0f, 2500.0f, "%.0f")) + OverlayConfig_MarkDirty(); + + if (ImGui::SliderFloat("Target Accel", &config.aim_sim_target_accel, 20.0f, 10000.0f, "%.0f")) + OverlayConfig_MarkDirty(); + + if (ImGui::SliderFloat("Target Stop Chance", &config.aim_sim_target_stop_chance, 0.0f, 0.95f, "%.2f")) + OverlayConfig_MarkDirty(); + + if (ImGui::Checkbox("Show Delayed Observation", &config.aim_sim_show_observed)) + OverlayConfig_MarkDirty(); + + if (ImGui::Checkbox("Show Trajectory History", &config.aim_sim_show_history)) + OverlayConfig_MarkDirty(); + + if (!config.aim_sim_enabled) + { + ImGui::EndDisabled(); + ImGui::TextDisabled("Enable Aim Simulation Window to edit settings."); + } + + OverlayUI::EndSection(); + } + + if (!g_iconLastError.empty()) + { + if (OverlayUI::BeginSection("Errors", "game_overlay_section_errors")) + { + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 100, 100, 255)); + ImGui::TextWrapped("%s", g_iconLastError.c_str()); + ImGui::PopStyleColor(); + OverlayUI::EndSection(); + } + } + +} diff --git a/sunone_aimbot_cpp/overlay/draw_game_overlay.h b/RN_AI_cpp/overlay/draw_game_overlay.h similarity index 100% rename from sunone_aimbot_cpp/overlay/draw_game_overlay.h rename to RN_AI_cpp/overlay/draw_game_overlay.h diff --git a/sunone_aimbot_cpp/overlay/draw_mouse.cpp b/RN_AI_cpp/overlay/draw_mouse.cpp similarity index 63% rename from sunone_aimbot_cpp/overlay/draw_mouse.cpp rename to RN_AI_cpp/overlay/draw_mouse.cpp index c72ab1d6..ecf0d1a3 100644 --- a/sunone_aimbot_cpp/overlay/draw_mouse.cpp +++ b/RN_AI_cpp/overlay/draw_mouse.cpp @@ -1,4 +1,4 @@ -#define WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #define _WINSOCKAPI_ #include #include @@ -6,7 +6,7 @@ #include "imgui/imgui.h" #include -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "include/other_tools.h" #include "kmbox_net/picture.h" @@ -23,9 +23,21 @@ float prev_snapBoostFactor = config.snapBoostFactor; int prev_smoothness = config.smoothness; static bool prev_use_smoothing = config.use_smoothing; static bool prev_use_kalman = config.use_kalman; -// TODO: проверить static, focuse_target не обновляется, только после перезапуска. +static bool prev_tracking_smoothing = config.tracking_smoothing; float prev_kalman_process_noise = config.kalman_process_noise; float prev_kalman_measure_noise = config.kalman_measurement_noise; +float prev_reset_threshold = config.resetThreshold; +int prev_prediction_mode = config.prediction_mode; +float prev_prediction_lead_ms = config.prediction_kalman_lead_ms; +float prev_prediction_max_lead_ms = config.prediction_kalman_max_lead_ms; +float prev_prediction_velocity_smoothing = config.prediction_velocity_smoothing; +float prev_prediction_velocity_scale = config.prediction_velocity_scale; +float prev_prediction_kalman_q = config.prediction_kalman_process_noise; +float prev_prediction_kalman_r = config.prediction_kalman_measurement_noise; +bool prev_prediction_use_future_for_aim = config.prediction_use_future_for_aim; +bool prev_camera_compensation_enabled = config.camera_compensation_enabled; +float prev_camera_compensation_max_shift = config.camera_compensation_max_shift; +float prev_camera_compensation_strength = config.camera_compensation_strength; bool prev_wind_mouse_enabled = config.wind_mouse_enabled; float prev_wind_G = config.wind_G; @@ -35,74 +47,69 @@ float prev_wind_D = config.wind_D; bool prev_triggerbot = config.triggerbot; float prev_triggerbot_bScope_multiplier = config.triggerbot_bScope_multiplier; -float prev_triggerbot_interval = static_cast(config.triggerbot_interval); -float prev_triggerbot_predict_ms = static_cast(config.triggerbot_predict_ms); -float prev_triggerbot_predict_alpha = static_cast(config.triggerbot_predict_alpha); +int prev_triggerbot_reaction_ms = config.triggerbot_reaction_ms; bool prev_auto_shoot = config.auto_shoot; float prev_bScope_multiplier = config.bScope_multiplier; -static void draw_target_correction_demo() +static void draw_target_correction_demo_canvas() { - if (ImGui::CollapsingHeader("Visual demo")) - { - ImVec2 canvas_sz(220, 220); - ImGui::InvisibleButton("##tc_canvas", canvas_sz); - - ImVec2 p0 = ImGui::GetItemRectMin(); - ImVec2 p1 = ImGui::GetItemRectMax(); - ImVec2 center{ (p0.x + p1.x) * 0.5f, (p0.y + p1.y) * 0.5f }; - - ImDrawList* dl = ImGui::GetWindowDrawList(); - dl->AddRectFilled(p0, p1, IM_COL32(25, 25, 25, 255)); - - const float scale = 4.0f; - float near_px = config.nearRadius * scale; - float snap_px = config.snapRadius * scale; - near_px = ImClamp(near_px, 10.0f, canvas_sz.x * 0.45f); - snap_px = ImClamp(snap_px, 6.0f, near_px - 4.0f); - - dl->AddCircle(center, near_px, IM_COL32(80, 120, 255, 180), 64, 2.0f); - dl->AddCircle(center, snap_px, IM_COL32(255, 100, 100, 180), 64, 2.0f); - - static float dist_px = near_px; - static float vel_px = 0.0f; - static double last_t = ImGui::GetTime(); - double now = ImGui::GetTime(); - double dt = now - last_t; - last_t = now; - - double dist_units = dist_px / scale; - double speed_mult; - if (dist_units < config.snapRadius) - speed_mult = config.minSpeedMultiplier * config.snapBoostFactor; - else if (dist_units < config.nearRadius) - { - double t = dist_units / config.nearRadius; - double crv = 1.0 - pow(1.0 - t, config.speedCurveExponent); - speed_mult = config.minSpeedMultiplier + - (config.maxSpeedMultiplier - config.minSpeedMultiplier) * crv; - } - else - { - double norm = ImClamp(dist_units / config.nearRadius, 0.0, 1.0); - speed_mult = config.minSpeedMultiplier + - (config.maxSpeedMultiplier - config.minSpeedMultiplier) * norm; - } + ImVec2 canvas_sz(220, 220); + ImGui::InvisibleButton("##tc_canvas", canvas_sz); - double base_px_s = 60.0; - vel_px = static_cast(base_px_s * speed_mult); - dist_px -= vel_px * static_cast(dt); - if (dist_px <= 0.0f) dist_px = near_px; + ImVec2 p0 = ImGui::GetItemRectMin(); + ImVec2 p1 = ImGui::GetItemRectMax(); + ImVec2 center{ (p0.x + p1.x) * 0.5f, (p0.y + p1.y) * 0.5f }; - ImVec2 dot{ center.x - dist_px, center.y }; - dl->AddCircleFilled(dot, 4.0f, IM_COL32(255, 255, 80, 255)); + ImDrawList* dl = ImGui::GetWindowDrawList(); + dl->AddRectFilled(p0, p1, IM_COL32(25, 25, 25, 255)); - ImGui::Dummy(ImVec2(0, 4)); - ImGui::TextColored(ImVec4(0.31f, 0.48f, 1.0f, 1.0f), "Near radius"); - ImGui::SameLine(130); - ImGui::TextColored(ImVec4(1.0f, 0.39f, 0.39f, 1.0f), "Snap radius"); + const float scale = 4.0f; + float near_px = config.nearRadius * scale; + float snap_px = config.snapRadius * scale; + near_px = ImClamp(near_px, 10.0f, canvas_sz.x * 0.45f); + snap_px = ImClamp(snap_px, 6.0f, near_px - 4.0f); + + dl->AddCircle(center, near_px, IM_COL32(80, 120, 255, 180), 64, 2.0f); + dl->AddCircle(center, snap_px, IM_COL32(255, 100, 100, 180), 64, 2.0f); + + static float dist_px = near_px; + static float vel_px = 0.0f; + static double last_t = ImGui::GetTime(); + double now = ImGui::GetTime(); + double dt = now - last_t; + last_t = now; + + double dist_units = dist_px / scale; + double speed_mult; + if (dist_units < config.snapRadius) + speed_mult = config.minSpeedMultiplier * config.snapBoostFactor; + else if (dist_units < config.nearRadius) + { + double t = dist_units / config.nearRadius; + double crv = 1.0 - pow(1.0 - t, config.speedCurveExponent); + speed_mult = config.minSpeedMultiplier + + (config.maxSpeedMultiplier - config.minSpeedMultiplier) * crv; + } + else + { + double norm = ImClamp(dist_units / config.nearRadius, 0.0, 1.0); + speed_mult = config.minSpeedMultiplier + + (config.maxSpeedMultiplier - config.minSpeedMultiplier) * norm; } + + double base_px_s = 60.0; + vel_px = static_cast(base_px_s * speed_mult); + dist_px -= vel_px * static_cast(dt); + if (dist_px <= 0.0f) dist_px = near_px; + + ImVec2 dot{ center.x - dist_px, center.y }; + dl->AddCircleFilled(dot, 4.0f, IM_COL32(255, 255, 80, 255)); + + ImGui::Dummy(ImVec2(0, 4)); + ImGui::TextColored(ImVec4(0.31f, 0.48f, 1.0f, 1.0f), "Near radius"); + ImGui::SameLine(130); + ImGui::TextColored(ImVec4(1.0f, 0.39f, 0.39f, 1.0f), "Snap radius"); } struct DemoKalman1D { @@ -121,11 +128,8 @@ struct DemoKalman1D { } }; -static void draw_smoothing_kalman_demo() +static void draw_smoothing_kalman_demo_canvas() { - if (!ImGui::CollapsingHeader("Smooth + Kalman Demo")) - return; - ImVec2 canvas_sz(220, 220); ImGui::InvisibleButton("##sk_canvas", canvas_sz); ImVec2 p0 = ImGui::GetItemRectMin(); @@ -134,13 +138,13 @@ static void draw_smoothing_kalman_demo() ImDrawList* dl = ImGui::GetWindowDrawList(); dl->AddRectFilled(p0, p1, IM_COL32(30, 30, 30, 255)); - // Время и dt + // ????? ? dt static double last_t = ImGui::GetTime(); double now = ImGui::GetTime(); double dt = now - last_t; last_t = now; - // Raw-цель по окружности + // Raw-???? ?? ?????????? static double angle = 0.0; angle += dt * 1.0; if (angle > 2 * 3.14159265358979323846) angle -= 2 * 3.14159265358979323846; @@ -148,7 +152,7 @@ static void draw_smoothing_kalman_demo() double rawX = center.x + cos(angle) * rad; double rawY = center.y + sin(angle) * rad; - // Калман-фильтр + // ??????-?????? static DemoKalman1D kfX{ config.kalman_process_noise, config.kalman_measurement_noise }, kfY{ config.kalman_process_noise, config.kalman_measurement_noise }; static float lastQ = config.kalman_process_noise, @@ -162,11 +166,11 @@ static void draw_smoothing_kalman_demo() double kalX = kfX.update(rawX, dt); double kalY = kfY.update(rawY, dt); - // Экспоненциальное сглаживание + // ???????????????? ??????????? static double smX = center.x, smY = center.y; int N = config.smoothness > 0 ? config.smoothness : 1; double alpha = 1.0 / N; - // Сброс, если Kalman-координата «прыгает» слишком далеко + // ?????, ???? Kalman-?????????? ??????? ??????? ?????? const double resetThreshold = 5.0; if (hypot(kalX - smX, kalY - smY) > resetThreshold) { smX = kalX; @@ -177,12 +181,12 @@ static void draw_smoothing_kalman_demo() smY += (kalY - smY) * alpha; } - // Рисуем точки: белая = raw, красная = kalman, зелёная = smoothed + // ?????? ?????: ????? = raw, ??????? = kalman, ??????? = smoothed dl->AddCircleFilled({ (float)rawX, (float)rawY }, 4.0f, IM_COL32(255, 255, 255, 200)); dl->AddCircleFilled({ (float)kalX, (float)kalY }, 4.0f, IM_COL32(255, 100, 100, 200)); dl->AddCircleFilled({ (float)smX, (float)smY }, 4.0f, IM_COL32(100, 255, 100, 200)); - // Легенда + // ??????? dl->AddText({ p0.x + 5, p0.y + 5 }, IM_COL32(200, 200, 200, 255), "W=Raw R=Kalman G=Smoothed"); @@ -202,7 +206,9 @@ void draw_mouse() input_method_changed.store(true); globalMouseThread->setUseSmoothing(config.use_smoothing); } - + ImGui::SameLine(); + ImGui::Checkbox("Tracking Smoothing", &config.tracking_smoothing); + ImGui::SameLine(); if (ImGui::Checkbox("Enable Kalman Filter", &config.use_kalman)) { config.saveConfig(); @@ -218,6 +224,7 @@ void draw_mouse() changed |= ImGui::SliderFloat("Kalman Measurement Noise", &config.kalman_measurement_noise, 0.40f, 1.0f, "%.4f"); changed |= ImGui::SliderFloat("Kalman Speed Multiplier X", &config.kalman_speed_multiplier_x, 0.1f, 5.0f, "%.2f"); changed |= ImGui::SliderFloat("Kalman Speed Multiplier Y", &config.kalman_speed_multiplier_y, 0.1f, 5.0f, "%.2f"); + changed |= ImGui::SliderFloat("Reset Threshold", &config.resetThreshold, 1.0f, 20.0f, "%.1f"); if (changed) { @@ -235,41 +242,76 @@ void draw_mouse() } - draw_smoothing_kalman_demo(); + if (ImGui::CollapsingHeader("Demos")) + { + if (ImGui::BeginTable("mouse_demo_table", 2, ImGuiTableFlags_SizingFixedFit)) + { + ImGui::TableNextColumn(); + ImGui::Text("Smooth + Kalman"); + draw_smoothing_kalman_demo_canvas(); + ImGui::TableNextColumn(); + ImGui::Text("Visual"); + draw_target_correction_demo_canvas(); + ImGui::EndTable(); + } + } ImGui::SeparatorText("Speed Multiplier"); ImGui::SliderFloat("Min Speed Multiplier", &config.minSpeedMultiplier, 0.1f, 5.0f, "%.1f"); ImGui::SliderFloat("Max Speed Multiplier", &config.maxSpeedMultiplier, 0.1f, 5.0f, "%.1f"); - ImGui::SeparatorText("Prediction"); - ImGui::SliderFloat("Prediction Interval", &config.predictionInterval, 0.00f, 0.5f, "%.2f"); - if (config.predictionInterval == 0.00f) - { - ImGui::SameLine(); - ImGui::TextColored(ImVec4(255, 0, 0, 255), "-> Disabled"); - } - else + if (config.use_kalman) { - - if (ImGui::SliderInt("Future Positions", &config.prediction_futurePositions, 1, 40)) + ImGui::SeparatorText("Prediction"); + ImGui::SliderFloat("Prediction Interval", &config.predictionInterval, 0.00f, 0.5f, "%.2f"); + const char* mode_items[] = { "Standard", "Kalman Lead", "Kalman + Raw" }; + int mode_idx = config.prediction_mode; + if (ImGui::Combo("Prediction Mode", &mode_idx, mode_items, IM_ARRAYSIZE(mode_items))) { + config.prediction_mode = mode_idx; config.saveConfig(); - input_method_changed.store(true); } - - ImGui::SameLine(); - if (ImGui::Checkbox("Draw##draw_future_positions_button", &config.draw_futurePositions)) + ImGui::SliderFloat("Pred Kalman Lead (ms)", &config.prediction_kalman_lead_ms, 0.0f, 150.0f, "%.1f"); + ImGui::SliderFloat("Pred Kalman Max Lead (ms)", &config.prediction_kalman_max_lead_ms, 0.0f, 250.0f, "%.1f"); + ImGui::SliderFloat("Pred Velocity Smoothing", &config.prediction_velocity_smoothing, 0.0f, 1.0f, "%.2f"); + ImGui::SliderFloat("Pred Velocity Scale", &config.prediction_velocity_scale, 0.0f, 3.0f, "%.2f"); + ImGui::SliderFloat("Pred Kalman Q", &config.prediction_kalman_process_noise, 0.001f, 5.0f, "%.3f"); + ImGui::SliderFloat("Pred Kalman R", &config.prediction_kalman_measurement_noise, 0.001f, 5.0f, "%.3f"); + ImGui::Checkbox("Use Future For Aim", &config.prediction_use_future_for_aim); + if (config.predictionInterval == 0.00f) { - config.saveConfig(); + ImGui::SameLine(); + ImGui::TextColored(ImVec4(255, 0, 0, 255), "-> Disabled"); + } + else + { + if (ImGui::SliderInt("Future Positions", &config.prediction_futurePositions, 1, 40)) + { + config.saveConfig(); + input_method_changed.store(true); + } + + ImGui::SameLine(); + if (ImGui::Checkbox("Draw##draw_future_positions_button", &config.draw_futurePositions)) + { + config.saveConfig(); + } } } + ImGui::SeparatorText("Camera Compensation"); + ImGui::Checkbox("Enable Camera Compensation", &config.camera_compensation_enabled); + if (config.camera_compensation_enabled) + { + ImGui::SliderFloat("Camera Max Shift", &config.camera_compensation_max_shift, 0.0f, 200.0f, "%.1f"); + ImGui::SliderFloat("Camera Strength", &config.camera_compensation_strength, 0.0f, 3.0f, "%.2f"); + } + ImGui::SeparatorText("Target corrention"); ImGui::SliderFloat("Snap Radius", &config.snapRadius, 0.1f, 5.0f, "%.1f"); ImGui::SliderFloat("Near Radius", &config.nearRadius, 1.0f, 40.0f, "%.1f"); ImGui::SliderFloat("Speed Curve Exponent", &config.speedCurveExponent, 0.1f, 10.0f, "%.1f"); ImGui::SliderFloat("Snap Boost Factor", &config.snapBoostFactor, 0.01f, 4.00f, "%.2f"); - draw_target_correction_demo(); ImGui::SeparatorText("Game Profile"); std::vector profile_names; @@ -356,9 +398,12 @@ void draw_mouse() ImGui::SeparatorText("Manage Profiles"); static char new_profile_name[64] = ""; - ImGui::InputText("New profile name", new_profile_name, sizeof(new_profile_name)); + const float add_btn_w = 96.0f; + const float spacing = ImGui::GetStyle().ItemSpacing.x; + ImGui::SetNextItemWidth((std::max)(120.0f, ImGui::GetContentRegionAvail().x - add_btn_w - spacing)); + ImGui::InputTextWithHint("##new_profile_name", "New profile name", new_profile_name, sizeof(new_profile_name)); ImGui::SameLine(); - if (ImGui::Button("Add Profile")) + if (ImGui::Button("Add Profile", ImVec2(add_btn_w, 0.0f))) { std::string name = std::string(new_profile_name); if (!name.empty() && config.game_profiles.count(name) == 0) @@ -395,94 +440,71 @@ void draw_mouse() ImGui::PopStyleColor(); } - ImGui::SeparatorText("Easy No Recoil"); - ImGui::Checkbox("Easy No Recoil", &config.easynorecoil); - if (config.easynorecoil) - { - ImGui::SliderFloat("No Recoil Strength", &config.easynorecoilstrength, 0.1f, 500.0f, "%.1f"); - ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Left/Right Arrow keys: Adjust recoil strength by 10"); - - if (config.easynorecoilstrength >= 100.0f) - { - ImGui::TextColored(ImVec4(255, 255, 0, 255), "WARNING: High recoil strength may be detected."); - } - } - - ImGui::SeparatorText("Auto Shoot"); + // TODO: Easy No Recoil is currently non-functional; keep it hidden until fixed. - ImGui::Checkbox("Auto Shoot", &config.auto_shoot); - if (config.auto_shoot) + if (ImGui::CollapsingHeader("Advanced")) { - ImGui::SliderFloat("bScope Multiplier", &config.bScope_multiplier, 0.2f, 2.0f, "%.1f"); - } - - ImGui::SeparatorText("Triggerbot"); - ImGui::Checkbox("Triggerbot (only fire, no aim)", &config.triggerbot); - if (config.triggerbot) - { - float interval = static_cast(config.triggerbot_interval); - if (ImGui::SliderFloat("Triggerbot interval (s, 0=hold)", &interval, 0.0f, 2.0f, "%.2f")) - { - config.triggerbot_interval = interval; - config.saveConfig(); - } - float predict_ms = static_cast(config.triggerbot_predict_ms); - if (ImGui::SliderFloat("Triggerbot predict (ms)", &predict_ms, 0.0f, 150.0f, "%.0f")) + ImGui::SeparatorText("Auto Shoot"); + ImGui::Checkbox("Auto Shoot", &config.auto_shoot); + if (config.auto_shoot) { - config.triggerbot_predict_ms = predict_ms; - config.saveConfig(); - } - float predict_alpha = static_cast(config.triggerbot_predict_alpha); - if (ImGui::SliderFloat("Triggerbot velocity smoothing", &predict_alpha, 0.0f, 1.0f, "%.2f")) - { - config.triggerbot_predict_alpha = predict_alpha; - config.saveConfig(); + ImGui::SliderFloat("bScope Multiplier", &config.bScope_multiplier, 0.2f, 2.0f, "%.1f"); } - ImGui::SliderFloat("Triggerbot bScope", &config.triggerbot_bScope_multiplier, 0.5f, 2.0f, "%.1f"); - } - - ImGui::SeparatorText("Wind mouse"); - if (ImGui::Checkbox("Enable WindMouse", &config.wind_mouse_enabled)) - { - config.saveConfig(); - input_method_changed.store(true); - } - - if (config.wind_mouse_enabled) - { - if (ImGui::SliderFloat("Gravity force", &config.wind_G, 4.00f, 40.00f, "%.2f")) + ImGui::SeparatorText("Triggerbot"); + ImGui::Checkbox("Triggerbot (only fire, no aim)", &config.triggerbot); + if (config.triggerbot) { - config.saveConfig(); + int reaction_ms = config.triggerbot_reaction_ms; + if (ImGui::SliderInt("Reaction Time (ms)", &reaction_ms, 0, 500)) + { + config.triggerbot_reaction_ms = reaction_ms; + config.saveConfig(); + } + ImGui::SliderFloat("Triggerbot bScope", &config.triggerbot_bScope_multiplier, 0.5f, 2.0f, "%.1f"); } - if (ImGui::SliderFloat("Wind fluctuation", &config.wind_W, 1.00f, 40.00f, "%.2f")) + ImGui::SeparatorText("Wind mouse"); + if (ImGui::Checkbox("Enable WindMouse", &config.wind_mouse_enabled)) { config.saveConfig(); + input_method_changed.store(true); } - - if (ImGui::SliderFloat("Max step (velocity clip)", &config.wind_M, 1.00f, 40.00f, "%.2f")) + if (config.wind_mouse_enabled) { - config.saveConfig(); - } + if (ImGui::SliderFloat("Gravity force", &config.wind_G, 4.00f, 40.00f, "%.2f")) + { + config.saveConfig(); + } - if (ImGui::SliderFloat("Distance where behaviour changes", &config.wind_D, 1.00f, 40.00f, "%.2f")) - { - config.saveConfig(); - } + if (ImGui::SliderFloat("Wind fluctuation", &config.wind_W, 1.00f, 40.00f, "%.2f")) + { + config.saveConfig(); + } - if (ImGui::Button("Reset Wind Mouse to default settings")) - { - config.wind_G = 18.0f; - config.wind_W = 15.0f; - config.wind_M = 10.0f; - config.wind_D = 8.0f; - config.saveConfig(); + if (ImGui::SliderFloat("Max step (velocity clip)", &config.wind_M, 1.00f, 40.00f, "%.2f")) + { + config.saveConfig(); + } + + if (ImGui::SliderFloat("Distance where behaviour changes", &config.wind_D, 1.00f, 40.00f, "%.2f")) + { + config.saveConfig(); + } + + if (ImGui::Button("Reset Wind Mouse to default settings")) + { + config.wind_G = 18.0f; + config.wind_W = 15.0f; + config.wind_M = 10.0f; + config.wind_D = 8.0f; + config.saveConfig(); + } } } ImGui::SeparatorText("Input method"); - std::vector input_methods = { "MAKCU", "KMBOX_B", "ARDUINO" }; + std::vector input_methods = { "WIN32", "ARDUINO", "KMBOX_B", "KMBOX_NET", "MAKCU" }; std::vector method_items; method_items.reserve(input_methods.size()); @@ -514,30 +536,84 @@ void draw_mouse() } } - else if (config.input_method == "MAKCU") + + if (config.input_method == "MAKCU") { - ImGui::Text("Makcu Settings"); + if (makcu && makcu->isOpen()) + { + ImGui::TextColored(ImVec4(0, 255, 0, 255), "Makcu connected"); + } + else + { + ImGui::TextColored(ImVec4(255, 0, 0, 255), "Makcu not connected"); + } - ImGui::InputText("Makcu Port", config.makcu_port.data(), config.makcu_port.size()); - //TODO: Убери строчну на 362 - ImGui::InputInt("Makcu Baudrate", &config.makcu_baudrate); + std::vector port_list; + for (int i = 1; i <= 30; ++i) + { + port_list.push_back("COM" + std::to_string(i)); + } - if (!makcu) + bool has_current_port = false; + for (const auto& port : port_list) { - makcu = new MakcuConnection(config.makcu_port, config.makcu_baudrate); - if (!makcu->isOpen()) + if (port == config.makcu_port) { - ImGui::TextColored(ImVec4(255, 0, 0, 255), "Failed to connect to Makcu."); + has_current_port = true; + break; } - else + } + if (!config.makcu_port.empty() && !has_current_port) + { + port_list.insert(port_list.begin(), config.makcu_port); + } + + std::vector port_items; + port_items.reserve(port_list.size()); + for (auto& p : port_list) port_items.push_back(p.c_str()); + + int port_index = 0; + for (size_t i = 0; i < port_list.size(); ++i) + { + if (port_list[i] == config.makcu_port) { - ImGui::TextColored(ImVec4(0, 255, 0, 255), "Makcu connected."); + port_index = (int)i; + break; } } - } + if (ImGui::Combo("Makcu Port", &port_index, port_items.data(), (int)port_items.size())) + { + config.makcu_port = port_list[port_index]; + config.saveConfig(); + input_method_changed.store(true); + } - if (config.input_method == "ARDUINO") + std::vector baud_list = { 115200, 1000000, 2000000, 4000000 }; + std::vector baud_str_list; + for (int b : baud_list) baud_str_list.push_back(std::to_string(b)); + std::vector baud_items; + baud_items.reserve(baud_str_list.size()); + for (auto& bs : baud_str_list) baud_items.push_back(bs.c_str()); + + int baud_index = 0; + for (size_t i = 0; i < baud_list.size(); ++i) + { + if (baud_list[i] == config.makcu_baudrate) + { + baud_index = (int)i; + break; + } + } + + if (ImGui::Combo("Makcu Baudrate", &baud_index, baud_items.data(), (int)baud_items.size())) + { + config.makcu_baudrate = baud_list[baud_index]; + config.saveConfig(); + input_method_changed.store(true); + } + } + else if (config.input_method == "ARDUINO") { if (arduinoSerial) { @@ -749,12 +825,25 @@ void draw_mouse() prev_fovY != config.fovY || config.smoothness != prev_smoothness || prev_use_smoothing != config.use_smoothing || + prev_tracking_smoothing != config.tracking_smoothing || prev_use_kalman != config.use_kalman || prev_kalman_process_noise != config.kalman_process_noise || prev_kalman_measure_noise != config.kalman_measurement_noise || + prev_reset_threshold != config.resetThreshold || prev_minSpeedMultiplier != config.minSpeedMultiplier || prev_maxSpeedMultiplier != config.maxSpeedMultiplier || prev_predictionInterval != config.predictionInterval || + prev_prediction_mode != config.prediction_mode || + prev_prediction_lead_ms != config.prediction_kalman_lead_ms || + prev_prediction_max_lead_ms != config.prediction_kalman_max_lead_ms || + prev_prediction_velocity_smoothing != config.prediction_velocity_smoothing || + prev_prediction_velocity_scale != config.prediction_velocity_scale || + prev_prediction_kalman_q != config.prediction_kalman_process_noise || + prev_prediction_kalman_r != config.prediction_kalman_measurement_noise || + prev_prediction_use_future_for_aim != config.prediction_use_future_for_aim || + prev_camera_compensation_enabled != config.camera_compensation_enabled || + prev_camera_compensation_max_shift != config.camera_compensation_max_shift || + prev_camera_compensation_strength != config.camera_compensation_strength || prev_snapRadius != config.snapRadius || prev_nearRadius != config.nearRadius || prev_speedCurveExponent != config.speedCurveExponent || @@ -764,12 +853,25 @@ void draw_mouse() prev_fovY = config.fovY; prev_smoothness = config.smoothness; prev_use_smoothing = config.use_smoothing; + prev_tracking_smoothing = config.tracking_smoothing; prev_use_kalman = config.use_kalman; prev_kalman_process_noise = config.kalman_process_noise; prev_kalman_measure_noise = config.kalman_measurement_noise; + prev_reset_threshold = config.resetThreshold; prev_minSpeedMultiplier = config.minSpeedMultiplier; prev_maxSpeedMultiplier = config.maxSpeedMultiplier; prev_predictionInterval = config.predictionInterval; + prev_prediction_mode = config.prediction_mode; + prev_prediction_lead_ms = config.prediction_kalman_lead_ms; + prev_prediction_max_lead_ms = config.prediction_kalman_max_lead_ms; + prev_prediction_velocity_smoothing = config.prediction_velocity_smoothing; + prev_prediction_velocity_scale = config.prediction_velocity_scale; + prev_prediction_kalman_q = config.prediction_kalman_process_noise; + prev_prediction_kalman_r = config.prediction_kalman_measurement_noise; + prev_prediction_use_future_for_aim = config.prediction_use_future_for_aim; + prev_camera_compensation_enabled = config.camera_compensation_enabled; + prev_camera_compensation_max_shift = config.camera_compensation_max_shift; + prev_camera_compensation_strength = config.camera_compensation_strength; prev_snapRadius = config.snapRadius; prev_nearRadius = config.nearRadius; prev_speedCurveExponent = config.speedCurveExponent; @@ -826,17 +928,13 @@ void draw_mouse() prev_bScope_multiplier != config.bScope_multiplier || prev_triggerbot != config.triggerbot || prev_triggerbot_bScope_multiplier != config.triggerbot_bScope_multiplier || - prev_triggerbot_interval != static_cast(config.triggerbot_interval) || - prev_triggerbot_predict_ms != static_cast(config.triggerbot_predict_ms) || - prev_triggerbot_predict_alpha != static_cast(config.triggerbot_predict_alpha)) + prev_triggerbot_reaction_ms != config.triggerbot_reaction_ms) { prev_auto_shoot = config.auto_shoot; prev_bScope_multiplier = config.bScope_multiplier; prev_triggerbot = config.triggerbot; prev_triggerbot_bScope_multiplier = config.triggerbot_bScope_multiplier; - prev_triggerbot_interval = static_cast(config.triggerbot_interval); - prev_triggerbot_predict_ms = static_cast(config.triggerbot_predict_ms); - prev_triggerbot_predict_alpha = static_cast(config.triggerbot_predict_alpha); + prev_triggerbot_reaction_ms = config.triggerbot_reaction_ms; globalMouseThread->updateConfig( config.detection_resolution, @@ -852,3 +950,4 @@ void draw_mouse() config.saveConfig(); } } + diff --git a/RN_AI_cpp/overlay/draw_overlay.cpp b/RN_AI_cpp/overlay/draw_overlay.cpp new file mode 100644 index 00000000..4c6def17 --- /dev/null +++ b/RN_AI_cpp/overlay/draw_overlay.cpp @@ -0,0 +1,101 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include +#include + +#include "imgui/imgui.h" +#include "rn_ai_cpp.h" +#include "overlay.h" +#include "ui_controls.h" +#include "config_dirty.h" + +void draw_overlay() +{ + ImGui::PushID("Overlay Opacity"); + ImGui::TextUnformatted("Overlay Opacity"); + bool opacity_changed = false; + if (ImGui::Button("-", ImVec2(24.0f, 0.0f))) + { + config.overlay_opacity = std::clamp(config.overlay_opacity - 1, 40, 255); + opacity_changed = true; + } + ImGui::SameLine(); + ImGui::SetNextItemWidth(220.0f); + if (ImGui::SliderInt("##slider", &config.overlay_opacity, 40, 255, "%d")) + { + config.overlay_opacity = std::clamp(config.overlay_opacity, 40, 255); + opacity_changed = true; + } + ImGui::SameLine(); + if (ImGui::Button("+", ImVec2(24.0f, 0.0f))) + { + config.overlay_opacity = std::clamp(config.overlay_opacity + 1, 40, 255); + opacity_changed = true; + } + ImGui::PopID(); + + if (opacity_changed) + OverlayConfig_MarkDirty(); + + static float ui_scale = config.overlay_ui_scale; + static int window_w = overlayWidth; + static int window_h = overlayHeight; + bool ui_scale_changed = false; + + ImGui::SameLine(); + ImGui::PushID("UI Scale Inline"); + ImGui::TextUnformatted("UI Scale"); + ImGui::SameLine(); + if (ImGui::Button("-", ImVec2(24.0f, 0.0f))) + { + ui_scale = std::clamp(ui_scale - 0.05f, 0.5f, 3.0f); + ui_scale_changed = true; + } + ImGui::SameLine(); + if (ImGui::Button("+", ImVec2(24.0f, 0.0f))) + { + ui_scale = std::clamp(ui_scale + 0.05f, 0.5f, 3.0f); + ui_scale_changed = true; + } + ImGui::SameLine(); + ImGui::SetNextItemWidth(90.0f); + if (ImGui::InputFloat("##input", &ui_scale, 0.0f, 0.0f, "%.2f")) + { + ui_scale = std::clamp(ui_scale, 0.5f, 3.0f); + ui_scale_changed = true; + } + ImGui::PopID(); + + if (ui_scale_changed) + { + ImGui::GetIO().FontGlobalScale = ui_scale; + config.overlay_ui_scale = ui_scale; + OverlayConfig_MarkDirty(); + extern const int BASE_OVERLAY_WIDTH; + extern const int BASE_OVERLAY_HEIGHT; + overlayWidth = static_cast(BASE_OVERLAY_WIDTH * ui_scale); + overlayHeight = static_cast(BASE_OVERLAY_HEIGHT * ui_scale); + SetWindowPos(g_hwnd, NULL, 0, 0, overlayWidth, overlayHeight, SWP_NOMOVE | SWP_NOZORDER); + window_w = overlayWidth; + window_h = overlayHeight; + } + + if (window_w != overlayWidth || window_h != overlayHeight) + { + window_w = overlayWidth; + window_h = overlayHeight; + } + + if (OverlayUI::SliderIntWithButtons("Window Width", &window_w, 520, 2200, 10, "%d")) + { + overlayWidth = window_w; + SetWindowPos(g_hwnd, NULL, 0, 0, overlayWidth, overlayHeight, SWP_NOMOVE | SWP_NOZORDER); + } + + if (OverlayUI::SliderIntWithButtons("Window Height", &window_h, 360, 1400, 10, "%d")) + { + overlayHeight = window_h; + SetWindowPos(g_hwnd, NULL, 0, 0, overlayWidth, overlayHeight, SWP_NOMOVE | SWP_NOZORDER); + } +} diff --git a/sunone_aimbot_cpp/overlay/draw_settings.h b/RN_AI_cpp/overlay/draw_settings.h similarity index 71% rename from sunone_aimbot_cpp/overlay/draw_settings.h rename to RN_AI_cpp/overlay/draw_settings.h index a0729deb..35f91c25 100644 --- a/sunone_aimbot_cpp/overlay/draw_settings.h +++ b/RN_AI_cpp/overlay/draw_settings.h @@ -3,13 +3,16 @@ void draw_capture_settings(); void draw_target(); +void draw_classes(); void draw_mouse(); void draw_ai(); void draw_buttons(); void draw_overlay(); +void draw_game_overlay_settings(); void draw_stats(); void draw_debug(); +void draw_components(); void load_body_texture(); void release_body_texture(); -#endif // DRAW_SETTINGS_H \ No newline at end of file +#endif // DRAW_SETTINGS_H diff --git a/RN_AI_cpp/overlay/draw_stats.cpp b/RN_AI_cpp/overlay/draw_stats.cpp new file mode 100644 index 00000000..728a16b4 --- /dev/null +++ b/RN_AI_cpp/overlay/draw_stats.cpp @@ -0,0 +1,259 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#include +#include +#include + +#include "imgui/imgui.h" +#include "rn_ai_cpp.h" +#include "overlay.h" +#include "capture.h" +#include "ui_sections.h" + +void draw_stats() +{ + static float preprocess_times[120] = {}; + static float inference_times[120] = {}; + static float copy_times[120] = {}; + static float postprocess_times[120] = {}; + static float nms_times[120] = {}; + static int index_inf = 0; + + float current_preprocess = 0.0f; + float current_inference = 0.0f; + float current_copy = 0.0f; + float current_post = 0.0f; + float current_nms = 0.0f; + + if (config.backend == "DML" && dml_detector) {} +#ifdef USE_CUDA + else + { + current_preprocess = static_cast(trt_detector.lastPreprocessTime.count()); + current_inference = static_cast(trt_detector.lastInferenceTime.count()); + current_copy = static_cast(trt_detector.lastCopyTime.count()); + current_post = static_cast(trt_detector.lastPostprocessTime.count()); + current_nms = static_cast(trt_detector.lastNmsTime.count()); + } +#endif + preprocess_times[index_inf] = current_preprocess; + inference_times[index_inf] = current_inference; + copy_times[index_inf] = current_copy; + postprocess_times[index_inf] = current_post; + nms_times[index_inf] = current_nms; + index_inf = (index_inf + 1) % IM_ARRAYSIZE(inference_times); + + auto avg = [](const float* arr, int n) -> float { + float sum = 0.0f; int cnt = 0; + for (int i = 0; i < n; ++i) if (arr[i] > 0.0f) { sum += arr[i]; ++cnt; } + return cnt ? sum / cnt : 0.0f; + }; + + float avg_preprocess = avg(preprocess_times, IM_ARRAYSIZE(preprocess_times)); + float avg_inference = avg(inference_times, IM_ARRAYSIZE(inference_times)); + float avg_copy = avg(copy_times, IM_ARRAYSIZE(copy_times)); + float avg_post = avg(postprocess_times, IM_ARRAYSIZE(postprocess_times)); + float avg_nms = avg(nms_times, IM_ARRAYSIZE(nms_times)); + (void)avg_preprocess; + (void)avg_inference; + (void)avg_copy; + (void)avg_post; + (void)avg_nms; + + static float capture_fps_vals[120] = {}; + static int index_fps = 0; + + float current_fps = static_cast(captureFps.load()); + capture_fps_vals[index_fps] = current_fps; + index_fps = (index_fps + 1) % IM_ARRAYSIZE(capture_fps_vals); + + int latestWidth = 0; + int latestHeight = 0; + size_t queueDepth = 0; + { + std::lock_guard lk(frameMutex); + if (!latestFrame.empty()) + { + latestWidth = latestFrame.cols; + latestHeight = latestFrame.rows; + } + queueDepth = frameQueue.size(); + } + + if (OverlayUI::BeginCard("PERFORMANCE METRICS", "stats_metrics")) + { + auto metricBox = [](const char* id, const char* title, float nowVal, const char* unit, const float* vals, int count, int idx, float maxY, ImU32 valueColor, ImVec4 lineColor) + { + ImGui::BeginChild(id, ImVec2(0, 146), true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + + ImGui::TextUnformatted(title); + + char value_buf[64] = {}; + if (unit && unit[0] != '\0') + snprintf(value_buf, sizeof(value_buf), "%.1f %s", nowVal, unit); + else + snprintf(value_buf, sizeof(value_buf), "%.0f", nowVal); + + const float value_w = ImGui::CalcTextSize(value_buf).x; + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetWindowContentRegionMax().x - value_w); + ImGui::SetWindowFontScale(1.12f); + ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(valueColor), "%s", value_buf); + ImGui::SetWindowFontScale(1.00f); + + ImGui::Dummy(ImVec2(0.0f, 6.0f)); + ImGui::PushStyleColor(ImGuiCol_PlotLines, lineColor); + ImGui::PushStyleColor(ImGuiCol_PlotLinesHovered, lineColor); + ImGui::PlotLines("##plot", vals, count, idx, nullptr, 0.0f, maxY, ImVec2(-1, 80)); + ImGui::PopStyleColor(2); + ImGui::EndChild(); + }; + + if (ImGui::BeginTable("metrics_tbl", 2, ImGuiTableFlags_SizingStretchSame)) + { + ImGui::TableNextColumn(); + metricBox("m_fps", "CAPTURE FPS", current_fps, "", capture_fps_vals, IM_ARRAYSIZE(capture_fps_vals), index_fps, 240.0f, IM_COL32(88, 220, 95, 255), ImVec4(0.28f, 0.82f, 0.36f, 1.0f)); + ImGui::TableNextColumn(); + metricBox("m_pre", "PREPROCESS", current_preprocess, "ms", preprocess_times, IM_ARRAYSIZE(preprocess_times), index_inf, 20.0f, IM_COL32(120, 212, 255, 255), ImVec4(0.36f, 0.78f, 0.98f, 1.0f)); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + metricBox("m_inf", "INFERENCE", current_inference, "ms", inference_times, IM_ARRAYSIZE(inference_times), index_inf, 20.0f, IM_COL32(232, 200, 64, 255), ImVec4(0.88f, 0.73f, 0.18f, 1.0f)); + ImGui::TableNextColumn(); + static float queue_vals[120] = {}; + static int queue_idx = 0; + queue_vals[queue_idx] = static_cast(queueDepth); + queue_idx = (queue_idx + 1) % IM_ARRAYSIZE(queue_vals); + metricBox("m_qd", "QUEUE DEPTH", static_cast(queueDepth), "", queue_vals, IM_ARRAYSIZE(queue_vals), queue_idx, 16.0f, IM_COL32(224, 224, 224, 255), ImVec4(0.85f, 0.85f, 0.85f, 1.0f)); + ImGui::EndTable(); + } + } + OverlayUI::EndCard(); + + std::string captureSource = "Unknown"; + if (config.capture_method == "duplication_api" || config.capture_method == "obs") + { + captureSource = "Monitor " + std::to_string(std::max(0, config.monitor_idx) + 1); + } + else if (config.capture_method == "winrt") + { + captureSource = "WinRT"; + } + else if (config.capture_method == "virtual_camera") + { + captureSource = "Camera: " + config.virtual_camera_name; + } + + if (OverlayUI::BeginCard("CAPTURE DETAILS", "stats_capture")) + { + if (ImGui::BeginTable("stats_capture_tbl", 2, ImGuiTableFlags_SizingStretchProp)) + { + auto row_text = [](const char* key, const char* val) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(key); + ImGui::TableNextColumn(); + ImGui::TextWrapped("%s", val); + }; + + row_text("Capture Method:", config.capture_method.c_str()); + row_text("Backend:", config.backend.c_str()); + row_text("Source:", captureSource.c_str()); + + char frame_size_buf[32] = {}; + if (latestWidth > 0 && latestHeight > 0) + snprintf(frame_size_buf, sizeof(frame_size_buf), "%dx%d", latestWidth, latestHeight); + else + snprintf(frame_size_buf, sizeof(frame_size_buf), "n/a"); + row_text("Frame Size:", frame_size_buf); + + char det_res_buf[32] = {}; + snprintf(det_res_buf, sizeof(det_res_buf), "%d", config.detection_resolution); + row_text("Detection Resolution:", det_res_buf); + + char qd_buf[32] = {}; + snprintf(qd_buf, sizeof(qd_buf), "%d", static_cast(queueDepth)); + row_text("Frame Queue Depth:", qd_buf); + + row_text("Circle Mask:", config.circle_mask ? "on" : "off"); + ImGui::EndTable(); + } + +#ifdef USE_CUDA + if (config.backend == "TRT") + { + const bool canUseCudaCapture = (config.capture_method == "duplication_api"); + const bool directCaptureActive = canUseCudaCapture && config.capture_use_cuda && !config.circle_mask; + + std::string directCaptureStatus; + if (!canUseCudaCapture) + directCaptureStatus = "N/A (requires duplication_api)"; + else if (!config.capture_use_cuda) + directCaptureStatus = "Disabled by user"; + else if (config.circle_mask) + directCaptureStatus = "CPU fallback (circle mask is enabled)"; + else + directCaptureStatus = "Active"; + + ImGui::Separator(); + ImGui::Text("CUDA Direct Capture: %s", config.capture_use_cuda ? "enabled" : "disabled"); + ImGui::Text("Capture pipeline: %s", directCaptureActive ? "GPU direct path" : "CPU readback"); + ImGui::TextWrapped("Direct capture status: %s", directCaptureStatus.c_str()); + } +#endif + } + OverlayUI::EndCard(); + + if (OverlayUI::BeginCard("SYSTEM INFO", "stats_system")) + { + if (ImGui::BeginTable("stats_system_tbl", 2, ImGuiTableFlags_SizingStretchProp)) + { + auto row_text = [](const char* key, const char* val) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(key); + ImGui::TableNextColumn(); + ImGui::TextWrapped("%s", val); + }; + row_text("GPU:", "NVIDIA GPU"); + row_text("CUDA Version:", "12.x"); + row_text("Driver:", "n/a"); + ImGui::EndTable(); + } + } + OverlayUI::EndCard(); + + if (ImGui::CollapsingHeader("DETECTION STATISTICS", ImGuiTreeNodeFlags_DefaultOpen)) + { + size_t detCount = 0; + { + std::lock_guard lock(detectionBuffer.mutex); + detCount = detectionBuffer.boxes.size(); + } + if (ImGui::BeginTable("stats_det_tbl", 2, ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Total Detections:"); + ImGui::TableNextColumn(); + ImGui::Text("%d", static_cast(detCount)); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Avg Confidence:"); + ImGui::TableNextColumn(); + ImGui::Text("%.2f", config.confidence_threshold); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Target Locks:"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(config.smart_target_lock ? "enabled" : "disabled"); + ImGui::EndTable(); + } + } +} diff --git a/RN_AI_cpp/overlay/draw_target.cpp b/RN_AI_cpp/overlay/draw_target.cpp new file mode 100644 index 00000000..bce7df09 --- /dev/null +++ b/RN_AI_cpp/overlay/draw_target.cpp @@ -0,0 +1,725 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "d3d11.h" +#include "imgui/imgui.h" + +#include "overlay.h" +#include "draw_settings.h" +#include "ui_sections.h" +#include "ui_controls.h" +#include "ui_runtime.h" +#include "rn_ai_cpp.h" +#include "other_tools.h" +#include "memory_images.h" + +ID3D11ShaderResourceView* bodyTexture = nullptr; +ImVec2 bodyImageSize; +static char class_priority_buf[128] = ""; +static bool text_buffers_inited = false; +static const char* kDeletedClassMarker = "__deleted__"; + +static std::string trim_ascii(const std::string& s) +{ + size_t start = 0; + while (start < s.size() && (s[start] == ' ' || s[start] == '\t' || s[start] == '\r' || s[start] == '\n')) + ++start; + + size_t end = s.size(); + while (end > start && (s[end - 1] == ' ' || s[end - 1] == '\t' || s[end - 1] == '\r' || s[end - 1] == '\n')) + --end; + + return s.substr(start, end - start); +} + +static bool load_names_file(const std::string& path, std::vector& out) +{ + std::ifstream file(path); + if (!file.is_open()) + return false; + + out.clear(); + std::string line; + while (std::getline(file, line)) + { + std::string trimmed = trim_ascii(line); + if (trimmed.empty()) + continue; + if (!trimmed.empty() && trimmed[0] == '#') + continue; + out.push_back(trimmed); + } + + return !out.empty(); +} + +static bool load_class_names_for_model( + const std::string& model_name, + std::vector& out_names, + std::string& out_source) +{ + out_names.clear(); + out_source.clear(); + + std::vector candidates; + if (!model_name.empty()) + { + std::filesystem::path model_path = std::filesystem::path("models") / model_name; + std::string stem = model_path.stem().string(); + candidates.push_back(model_path.parent_path() / (stem + ".names")); + candidates.push_back(model_path.parent_path() / (stem + ".txt")); + candidates.push_back(model_path.parent_path() / "classes.txt"); + candidates.push_back(model_path.parent_path() / "labels.txt"); + } + + candidates.push_back(std::filesystem::path("class_names.txt")); + candidates.push_back(std::filesystem::path("classes.txt")); + candidates.push_back(std::filesystem::path("config") / "class_names.txt"); + candidates.push_back(std::filesystem::path("config") / "classes.txt"); + candidates.push_back(std::filesystem::path("configs") / "class_names.txt"); + candidates.push_back(std::filesystem::path("configs") / "classes.txt"); + + for (const auto& candidate : candidates) + { + if (!std::filesystem::exists(candidate)) + continue; + + std::vector names; + if (load_names_file(candidate.string(), names)) + { + out_names = std::move(names); + out_source = candidate.string(); + return true; + } + } + + return false; +} + +static std::vector parse_int_list(const std::string& text) +{ + std::vector values; + std::string cleaned; + cleaned.reserve(text.size()); + for (char c : text) + { + if (std::isdigit(static_cast(c))) + cleaned.push_back(c); + else + cleaned.push_back(' '); + } + + std::stringstream ss(cleaned); + int val = 0; + while (ss >> val) + values.push_back(val); + return values; +} + +static std::string build_int_list(const std::vector& values) +{ + if (values.empty()) + return ""; + + std::ostringstream oss; + for (size_t i = 0; i < values.size(); ++i) + { + if (i != 0) + oss << "-"; + oss << values[i]; + } + return oss.str(); +} + +static std::string fallback_legacy_name(int id) +{ + if (id == config.class_player) return "class_player"; + if (id == config.class_bot) return "class_bot"; + if (id == config.class_weapon) return "class_weapon"; + if (id == config.class_outline) return "class_outline"; + if (id == config.class_dead_body) return "class_dead_body"; + if (id == config.class_hideout_target_human) return "class_hideout_target_human"; + if (id == config.class_hideout_target_balls) return "class_hideout_target_balls"; + if (id == config.class_head) return "class_head"; + if (id == config.class_smoke) return "class_smoke"; + if (id == config.class_fire) return "class_fire"; + if (id == config.class_third_person) return "class_third_person"; + return ""; +} + +static std::string class_label( + int id, + const std::unordered_map& names) +{ + auto it = names.find(id); + if (it != names.end() && !it->second.empty()) + return std::to_string(id) + ": " + it->second; + return "Class " + std::to_string(id); +} + +static bool is_deleted_class_name(const std::string& value) +{ + return value == kDeletedClassMarker; +} + +void draw_target() +{ + bool changed = false; + if (config.target_lock_enabled != config.smart_target_lock) + { + config.target_lock_enabled = config.smart_target_lock; + changed = true; + } + if (config.focusTarget) + { + config.focusTarget = false; + changed = true; + } + + if (OverlayUI::BeginCard("GENERAL TARGETING", "target_general_card")) + { + if (ImGui::Checkbox("Disable Headshot Mode", &config.disable_headshot)) + changed = true; + if (OverlayUI::g_show_descriptions) + ImGui::TextDisabled("Aim for body center instead of head"); + + if (ImGui::Checkbox("Ignore Third Person", &config.ignore_third_person)) + changed = true; + if (OverlayUI::g_show_descriptions) + ImGui::TextDisabled("Don't aim at your own character in 3rd person view"); + + if (ImGui::Checkbox("Auto Aim Active", &config.auto_aim)) + changed = true; + + int head_id = config.class_head; + ImGui::TextUnformatted("Head Class Id"); + ImGui::SetNextItemWidth((std::min)(220.0f, ImGui::GetContentRegionAvail().x)); + if (ImGui::InputInt("##head_class_id", &head_id, 0, 0)) + { + config.class_head = std::max(0, head_id); + changed = true; + } + + float max_scope_px = static_cast(std::hypot( + static_cast(config.detection_resolution), + static_cast(config.detection_resolution))) / 2.0f; + float scope_percent = 0.0f; + if (config.aim_bot_scope > 0.0f && max_scope_px > 0.0f) + scope_percent = (config.aim_bot_scope / max_scope_px) * 100.0f; + scope_percent = std::clamp(scope_percent, 0.0f, 100.0f); + float scope_percent_edit = scope_percent; + if (OverlayUI::FloatControlRow( + "Aim Scope Radius", + &scope_percent_edit, + 0.0f, + 100.0f, + 1.0f, + "%.0f", + "%.1f", + "%", + "% of screen radius to search for targets")) + { + if (scope_percent_edit <= 0.0f || max_scope_px <= 0.0f) + config.aim_bot_scope = 0.0f; + else + config.aim_bot_scope = (scope_percent_edit / 100.0f) * max_scope_px; + changed = true; + } + } + OverlayUI::EndCard(); + + if (OverlayUI::BeginCard("SMART TARGET LOCK", "target_lock_card")) + { + if (ImGui::Checkbox("Enable Smart Target Lock", &config.smart_target_lock)) + { + config.target_lock_enabled = config.smart_target_lock; + changed = true; + } + if (config.smart_target_lock) + { + if (OverlayUI::FloatControlRow( + "Lock Distance", + &config.target_lock_distance, + 20.0f, + 400.0f, + 1.0f, + "%.0f", + "%.1f", + "px", + "Max pixel distance to maintain lock on current target")) + changed = true; + + float reacquire_ms = config.target_lock_reacquire_time * 1000.0f; + if (OverlayUI::FloatControlRow( + "Reacquire Time", + &reacquire_ms, + 50.0f, + 2000.0f, + 10.0f, + "%.0f", + "%.0f", + "ms", + "Time before searching for new target after losing current")) + { + config.target_lock_reacquire_time = reacquire_ms / 1000.0f; + changed = true; + } + + float switch_delay_ms = static_cast(std::max(0, config.target_switch_delay)); + if (OverlayUI::FloatControlRow( + "Target Switch Delay", + &switch_delay_ms, + 0.0f, + 2000.0f, + 10.0f, + "%.0f", + "%.0f", + "ms", + "Debounce time before switching to different target")) + { + config.target_switch_delay = static_cast(switch_delay_ms + 0.5f); + changed = true; + } + } + } + OverlayUI::EndCard(); + + if (ImGui::CollapsingHeader("ADVANCED CLASS CONTROLS")) + { + ImGui::SetNextItemWidth((std::min)(120.0f, ImGui::GetContentRegionAvail().x)); + if (ImGui::InputInt("Target Reference Class", &config.target_reference_class, 0, 0)) + changed = true; + ImGui::SetNextItemWidth((std::min)(120.0f, ImGui::GetContentRegionAvail().x)); + if (ImGui::InputInt("Target Lock Fallback Class (-1 = off)", &config.target_lock_fallback_class, 0, 0)) + changed = true; + } + + if (ImGui::CollapsingHeader("SMART TARGET WEIGHTS")) + { + if (OverlayUI::FloatControlRow("Distance Weight", &config.distance_scoring_weight, 0.0f, 2.0f, 0.01f, "%.2f", "%.3f")) + changed = true; + if (OverlayUI::FloatControlRow("Center Weight", &config.center_scoring_weight, 0.0f, 2.0f, 0.01f, "%.2f", "%.3f")) + changed = true; + if (OverlayUI::FloatControlRow("Size Weight", &config.size_scoring_weight, 0.0f, 2.0f, 0.01f, "%.2f", "%.3f")) + changed = true; + if (OverlayUI::FloatControlRow("Tiebreak Ratio", &config.aim_weight_tiebreak_ratio, 0.0f, 1.0f, 0.01f, "%.2f", "%.3f")) + changed = true; + } + + if (changed) + config.saveConfig(); +} + +void draw_classes() +{ + bool changed = false; + + static std::string cached_model; + static std::vector cached_model_names; + static std::string cached_name_source; + static bool cached_names_loaded = false; + + bool reload_names = ImGui::Button("Reload Class Names"); + if (reload_names || cached_model != config.ai_model) + { + cached_model = config.ai_model; + cached_names_loaded = load_class_names_for_model( + cached_model, + cached_model_names, + cached_name_source); + + if (cached_names_loaded) + { + for (int i = 0; i < static_cast(cached_model_names.size()); ++i) + { + auto it_existing = config.custom_class_names.find(i); + if (it_existing != config.custom_class_names.end() && + is_deleted_class_name(it_existing->second)) + continue; + + if (!config.custom_class_names.count(i)) + { + config.custom_class_names[i] = cached_model_names[i]; + changed = true; + } + } + } + } + + std::unordered_map names_by_id; + for (const auto& kv : config.custom_class_names) + { + if (is_deleted_class_name(kv.second)) + continue; + if (!kv.second.empty()) + names_by_id[kv.first] = kv.second; + } + + std::vector allowed_list = parse_int_list(config.allowed_classes); + std::vector priority_list = parse_int_list(config.class_priority_order); + std::unordered_set allowed_set(allowed_list.begin(), allowed_list.end()); + std::unordered_set id_set; + std::vector class_ids; + class_ids.reserve(64); + + auto add_class_id = [&](int id) + { + if (id < 0) + return; + if (id_set.insert(id).second) + class_ids.push_back(id); + }; + auto is_class_deleted = [&](int id) -> bool + { + auto it = config.custom_class_names.find(id); + return it != config.custom_class_names.end() && + is_deleted_class_name(it->second); + }; + + for (const auto& kv : config.custom_class_names) + { + if (is_deleted_class_name(kv.second)) + continue; + add_class_id(kv.first); + } + + for (const auto& kv : config.class_aim_positions) + { + if (is_class_deleted(kv.first)) + continue; + add_class_id(kv.first); + } + + for (int id : allowed_list) + { + if (is_class_deleted(id)) + continue; + add_class_id(id); + } + + for (int id : priority_list) + { + if (is_class_deleted(id)) + continue; + add_class_id(id); + } + + { + std::lock_guard lock(detectionBuffer.mutex); + for (int id : detectionBuffer.classes) + { + auto it_existing = config.custom_class_names.find(id); + if (it_existing != config.custom_class_names.end() && + is_deleted_class_name(it_existing->second)) + continue; + + add_class_id(id); + if (!config.custom_class_names.count(id)) + { + std::string fallback = fallback_legacy_name(id); + if (fallback.empty()) + fallback = "class_" + std::to_string(id); + config.custom_class_names[id] = fallback; + names_by_id[id] = fallback; + changed = true; + } + } + } + + std::sort(class_ids.begin(), class_ids.end()); + for (int id : class_ids) + { + if (!names_by_id.count(id) || names_by_id[id].empty()) + { + std::string fallback = fallback_legacy_name(id); + if (fallback.empty()) + fallback = "class_" + std::to_string(id); + names_by_id[id] = fallback; + } + + auto it_custom = config.custom_class_names.find(id); + if (it_custom == config.custom_class_names.end()) + { + config.custom_class_names[id] = names_by_id[id]; + changed = true; + } + else if (it_custom->second.empty()) + { + it_custom->second = names_by_id[id]; + changed = true; + } + } + + ImGui::SeparatorText("Class Names"); + if (cached_names_loaded) + { + ImGui::Text("Source: %s", cached_name_source.c_str()); + ImGui::Text("Classes detected from file: %d", static_cast(cached_model_names.size())); + } + else + { + ImGui::TextDisabled("No class names file found. Using config/detection based IDs."); + } + + ImGui::SeparatorText("Class Priority"); + if (!text_buffers_inited) + { + strncpy_s(class_priority_buf, sizeof(class_priority_buf), config.class_priority_order.c_str(), _TRUNCATE); + text_buffers_inited = true; + } + if (ImGui::InputText("Class Priority Order", class_priority_buf, IM_ARRAYSIZE(class_priority_buf))) + { + config.class_priority_order = class_priority_buf; + changed = true; + } + ImGui::TextDisabled("Format: 7-0-4"); + + ImGui::SeparatorText("Inference Classes"); + ImGui::Text("Enabled classes: %d", static_cast(allowed_set.size())); + if (allowed_set.empty()) + ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.2f, 1.0f), "No classes enabled."); + + if (ImGui::Button("Select All")) + { + std::unordered_set working(class_ids.begin(), class_ids.end()); + std::vector new_list(working.begin(), working.end()); + std::sort(new_list.begin(), new_list.end()); + config.allowed_classes = build_int_list(new_list); + allowed_set = std::move(working); + changed = true; + } + ImGui::SameLine(); + if (ImGui::Button("Clear All")) + { + allowed_set.clear(); + config.allowed_classes.clear(); + changed = true; + } + + static int add_class_input_id = 0; + static char add_class_name[64] = ""; + ImGui::PushItemWidth(120.0f); + ImGui::InputInt("Class ID##add_class", &add_class_input_id); + ImGui::PopItemWidth(); + ImGui::SameLine(); + ImGui::PushItemWidth(180.0f); + ImGui::InputText("Class Name##add_class", add_class_name, IM_ARRAYSIZE(add_class_name)); + ImGui::PopItemWidth(); + ImGui::SameLine(); + if (ImGui::Button("Add Class")) + { + if (add_class_input_id >= 0) + { + std::string new_name = trim_ascii(add_class_name); + if (new_name.empty()) + new_name = "class_" + std::to_string(add_class_input_id); + + config.custom_class_names[add_class_input_id] = new_name; + names_by_id[add_class_input_id] = new_name; + add_class_id(add_class_input_id); + std::sort(class_ids.begin(), class_ids.end()); + allowed_set.insert(add_class_input_id); + + std::vector new_allowed(allowed_set.begin(), allowed_set.end()); + std::sort(new_allowed.begin(), new_allowed.end()); + config.allowed_classes = build_int_list(new_allowed); + + add_class_name[0] = '\0'; + changed = true; + } + } + + if (ImGui::BeginTable( + "class_filter_table", + 4, + ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable)) + { + ImGui::TableSetupColumn("Enabled", ImGuiTableColumnFlags_WidthFixed, 90.0f); + ImGui::TableSetupColumn("Class"); + ImGui::TableSetupColumn("Class ID", ImGuiTableColumnFlags_WidthFixed, 90.0f); + ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, 90.0f); + ImGui::TableHeadersRow(); + + auto apply_toggle = [&](int class_id, bool enabled) + { + std::unordered_set working = allowed_set; + if (enabled) + working.insert(class_id); + else + working.erase(class_id); + + std::vector new_list(working.begin(), working.end()); + std::sort(new_list.begin(), new_list.end()); + config.allowed_classes = build_int_list(new_list); + allowed_set = std::move(working); + changed = true; + }; + + for (int id : class_ids) + { + ImGui::TableNextRow(); + + ImGui::TableSetColumnIndex(0); + bool enabled = (allowed_set.count(id) > 0); + ImGui::PushID(id); + if (ImGui::Checkbox("##class_enabled", &enabled)) + apply_toggle(id, enabled); + ImGui::PopID(); + + ImGui::TableSetColumnIndex(1); + std::string label = class_label(id, names_by_id); + ImGui::TextUnformatted(label.c_str()); + + ImGui::TableSetColumnIndex(2); + ImGui::Text("%d", id); + + ImGui::TableSetColumnIndex(3); + ImGui::PushID(id + 100000); + if (ImGui::SmallButton("Delete")) + { + config.custom_class_names[id] = kDeletedClassMarker; + config.class_aim_positions.erase(id); + allowed_set.erase(id); + priority_list.erase( + std::remove(priority_list.begin(), priority_list.end(), id), + priority_list.end()); + std::vector new_allowed(allowed_set.begin(), allowed_set.end()); + std::sort(new_allowed.begin(), new_allowed.end()); + config.allowed_classes = build_int_list(new_allowed); + config.class_priority_order = build_int_list(priority_list); + strncpy_s(class_priority_buf, sizeof(class_priority_buf), config.class_priority_order.c_str(), _TRUNCATE); + changed = true; + } + ImGui::PopID(); + } + + ImGui::EndTable(); + } + + ImGui::SeparatorText("Class Aim Positions"); + static int selected_class_id = -1; + if (!class_ids.empty()) + { + if (!id_set.count(selected_class_id)) + selected_class_id = class_ids.front(); + + std::string preview = class_label(selected_class_id, names_by_id); + if (ImGui::BeginCombo("Select Class", preview.c_str())) + { + for (int id : class_ids) + { + std::string label = class_label(id, names_by_id); + bool is_selected = (id == selected_class_id); + if (ImGui::Selectable(label.c_str(), is_selected)) + selected_class_id = id; + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + float pos1 = config.aim_bot_position; + float pos2 = config.aim_bot_position2; + auto it = config.class_aim_positions.find(selected_class_id); + if (it != config.class_aim_positions.end()) + { + pos1 = it->second.first; + pos2 = it->second.second; + } + + bool aim_changed = false; + if (ImGui::InputFloat("Aim Position", &pos1, 0.01f, 0.05f, "%.3f")) + { + pos1 = std::clamp(pos1, 0.0f, 1.0f); + aim_changed = true; + } + if (ImGui::InputFloat("Aim Position2", &pos2, 0.01f, 0.05f, "%.3f")) + { + pos2 = std::clamp(pos2, 0.0f, 1.0f); + aim_changed = true; + } + if (aim_changed) + { + config.class_aim_positions[selected_class_id] = { pos1, pos2 }; + changed = true; + } + + if (ImGui::Button("Reset Current Class Aim")) + { + config.class_aim_positions.erase(selected_class_id); + changed = true; + } + ImGui::TextDisabled("If class has no override, global Aim Position values are used."); + + if (bodyTexture) + { + ImGui::Image((void*)bodyTexture, bodyImageSize); + ImVec2 image_pos = ImGui::GetItemRectMin(); + ImVec2 image_size = ImGui::GetItemRectSize(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + float line1_y = image_pos.y + pos1 * image_size.y; + float line2_y = image_pos.y + pos2 * image_size.y; + ImVec2 line1_start = ImVec2(image_pos.x, line1_y); + ImVec2 line1_end = ImVec2(image_pos.x + image_size.x, line1_y); + ImVec2 line2_start = ImVec2(image_pos.x, line2_y); + ImVec2 line2_end = ImVec2(image_pos.x + image_size.x, line2_y); + draw_list->AddLine(line1_start, line1_end, IM_COL32(255, 0, 0, 255), 2.0f); + draw_list->AddLine(line2_start, line2_end, IM_COL32(0, 255, 0, 255), 2.0f); + draw_list->AddText(ImVec2(line1_end.x + 5, line1_y - 7), IM_COL32(255, 0, 0, 255), "Aim1"); + draw_list->AddText(ImVec2(line2_end.x + 5, line2_y - 7), IM_COL32(0, 255, 0, 255), "Aim2"); + } + else + { + ImGui::TextDisabled("Image not found."); + } + } + else + { + ImGui::TextDisabled("No class ids available."); + } + + if (changed) + config.saveConfig(); +} + +void load_body_texture() +{ + int image_width = 0; + int image_height = 0; + + std::string body_image = std::string(bodyImageBase64_1) + std::string(bodyImageBase64_2) + std::string(bodyImageBase64_3); + + bool ret = LoadTextureFromMemory(body_image, g_pd3dDevice, &bodyTexture, &image_width, &image_height); + if (!ret) + { + std::cerr << "[Overlay] Can't load image!" << std::endl; + } + else + { + bodyImageSize = ImVec2((float)image_width, (float)image_height); + } +} + +void release_body_texture() +{ + if (bodyTexture) + { + bodyTexture->Release(); + bodyTexture = nullptr; + } +} diff --git a/RN_AI_cpp/overlay/overlay.cpp b/RN_AI_cpp/overlay/overlay.cpp new file mode 100644 index 00000000..6914794e --- /dev/null +++ b/RN_AI_cpp/overlay/overlay.cpp @@ -0,0 +1,692 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "overlay.h" +#include "overlay/draw_settings.h" +#include "config.h" +#include "keycodes.h" +#include "rn_ai_cpp.h" +#include "capture.h" +#include "keyboard_listener.h" +#include "other_tools.h" +#include "virtual_camera.h" +#include "config_dirty.h" +#include "ui_theme.h" +#include "ui_runtime.h" +#ifdef USE_CUDA +#include "trt_detector.h" +#endif + +ID3D11Device* g_pd3dDevice = NULL; +ID3D11DeviceContext* g_pd3dDeviceContext = NULL; +IDXGISwapChain* g_pSwapChain = NULL; +ID3D11RenderTargetView* g_mainRenderTargetView = NULL; +HWND g_hwnd = NULL; + +extern Config config; +extern std::mutex configMutex; +extern std::atomic shouldExit; + +bool CreateDeviceD3D(HWND hWnd); +void CleanupDeviceD3D(); +void CreateRenderTarget(); +void CleanupRenderTarget(); + +ID3D11BlendState* g_pBlendState = nullptr; +LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +const int BASE_OVERLAY_WIDTH = 680; +const int BASE_OVERLAY_HEIGHT = 480; +int overlayWidth = 0; +int overlayHeight = 0; + +std::vector availableModels; +std::vector key_names; +std::vector key_names_cstrs; + +ID3D11ShaderResourceView* body_texture = nullptr; +ID3D11ShaderResourceView* g_menu_bg_texture = nullptr; +int g_menu_bg_w = 0; +int g_menu_bg_h = 0; +std::string g_menu_bg_loaded_path; +bool g_menu_bg_loaded_ok = false; + +bool InitializeBlendState() +{ + D3D11_BLEND_DESC blendDesc; + ZeroMemory(&blendDesc, sizeof(blendDesc)); + + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.RenderTarget[0].BlendEnable = TRUE; + blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + + HRESULT hr = g_pd3dDevice->CreateBlendState(&blendDesc, &g_pBlendState); + if (FAILED(hr)) + { + return false; + } + + float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f }; + g_pd3dDeviceContext->OMSetBlendState(g_pBlendState, blendFactor, 0xffffffff); + + return true; +} + +bool CreateDeviceD3D(HWND hWnd) +{ + DXGI_SWAP_CHAIN_DESC sd; + ZeroMemory(&sd, sizeof(sd)); + sd.BufferCount = 2; + sd.BufferDesc.Width = overlayWidth; + sd.BufferDesc.Height = overlayHeight; + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.BufferDesc.RefreshRate.Numerator = 0; + sd.BufferDesc.RefreshRate.Denominator = 0; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.OutputWindow = hWnd; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = 0; + sd.Windowed = TRUE; + sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + + UINT createDeviceFlags = 0; + + D3D_FEATURE_LEVEL featureLevel; + const D3D_FEATURE_LEVEL featureLevelArray[2] = + { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_0, + }; + + HRESULT res = D3D11CreateDeviceAndSwapChain(NULL, + D3D_DRIVER_TYPE_HARDWARE, + NULL, + createDeviceFlags, + featureLevelArray, + 2, + D3D11_SDK_VERSION, + &sd, + &g_pSwapChain, + &g_pd3dDevice, + &featureLevel, + &g_pd3dDeviceContext); + if (res != S_OK) + return false; + + if (!InitializeBlendState()) + return false; + + CreateRenderTarget(); + return true; +} + +void CreateRenderTarget() +{ + ID3D11Texture2D* pBackBuffer = NULL; + g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); + g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_mainRenderTargetView); + pBackBuffer->Release(); +} + +void CleanupRenderTarget() +{ + if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = NULL; } +} + +void CleanupDeviceD3D() +{ + CleanupRenderTarget(); + if (g_menu_bg_texture) { g_menu_bg_texture->Release(); g_menu_bg_texture = nullptr; } + g_menu_bg_w = 0; + g_menu_bg_h = 0; + g_menu_bg_loaded_path.clear(); + g_menu_bg_loaded_ok = false; + if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = NULL; } + if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; } + if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; } + if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = nullptr; } +} + +LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) + return true; + + switch (msg) + { + case WM_SIZE: + if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED) + { + RECT rect; + GetWindowRect(hWnd, &rect); + UINT width = rect.right - rect.left; + UINT height = rect.bottom - rect.top; + + CleanupRenderTarget(); + g_pSwapChain->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0); + CreateRenderTarget(); + } + return 0; + case WM_DESTROY: + shouldExit = true; + ::PostQuitMessage(0); + return 0; + default: + return ::DefWindowProc(hWnd, msg, wParam, lParam); + } +} + +void SetupImGui() +{ + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + + ImGuiIO& io = ImGui::GetIO(); + io.FontGlobalScale = config.overlay_ui_scale; + + // Merge Windows icon font into the default ImGui font for sidebar icons. + io.Fonts->Clear(); + io.Fonts->AddFontDefault(); + ImFontConfig icon_cfg{}; + icon_cfg.MergeMode = true; + icon_cfg.PixelSnapH = true; + static const ImWchar icon_ranges[] = { 0xE700, 0xF8FF, 0 }; + ImFont* icon_font = io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\segmdl2.ttf", 17.0f, &icon_cfg, icon_ranges); + if (!icon_font) + { + io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\Segoe Fluent Icons.ttf", 17.0f, &icon_cfg, icon_ranges); + } + + ImGui_ImplWin32_Init(g_hwnd); + ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); + + ImGui::StyleColorsDark(); + OverlayTheme_LoadAndApply("ui_theme.ini"); + + load_body_texture(); +} + +bool CreateOverlayWindow() +{ + overlayWidth = static_cast(BASE_OVERLAY_WIDTH * config.overlay_ui_scale); + overlayHeight = static_cast(BASE_OVERLAY_HEIGHT * config.overlay_ui_scale); + + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, + GetModuleHandle(NULL), NULL, NULL, NULL, NULL, + _T("Edge"), NULL }; + ::RegisterClassEx(&wc); + + g_hwnd = ::CreateWindowEx( + WS_EX_TOPMOST | WS_EX_LAYERED, + wc.lpszClassName, _T("Chrome"), + WS_POPUP, 0, 0, overlayWidth, overlayHeight, + NULL, NULL, wc.hInstance, NULL); + + if (g_hwnd == NULL) + return false; + +#ifndef WDA_EXCLUDEFROMCAPTURE +#define WDA_EXCLUDEFROMCAPTURE 0x00000011 +#endif + // Prevent recursive self-capture in debug view. + SetWindowDisplayAffinity(g_hwnd, WDA_EXCLUDEFROMCAPTURE); + + if (config.overlay_opacity <= 20) + { + config.overlay_opacity = 20; + config.saveConfig("config.ini"); + } + + if (config.overlay_opacity >= 256) + { + config.overlay_opacity = 255; + config.saveConfig("config.ini"); + } + + BYTE opacity = config.overlay_opacity; + + SetLayeredWindowAttributes(g_hwnd, 0, opacity, LWA_ALPHA); + + if (!CreateDeviceD3D(g_hwnd)) + { + CleanupDeviceD3D(); + ::UnregisterClass(wc.lpszClassName, wc.hInstance); + return false; + } + + return true; +} + +void OverlayThread() +{ + if (!CreateOverlayWindow()) + { + std::cout << "[Overlay] Can't create overlay window!" << std::endl; + return; + } + + SetupImGui(); + + bool show_overlay = false; + int prev_opacity = config.overlay_opacity; + + for (const auto& pair : KeyCodes::key_code_map) + { + key_names.push_back(pair.first); + } + std::sort(key_names.begin(), key_names.end()); + + key_names_cstrs.reserve(key_names.size()); + for (const auto& name : key_names) + { + key_names_cstrs.push_back(name.c_str()); + } + + std::vector availableModels = getAvailableModels(); + + MSG msg; + ZeroMemory(&msg, sizeof(msg)); + while (!shouldExit) + { + while (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) + { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + if (msg.message == WM_QUIT) + { + shouldExit = true; + return; + } + } + + if (isAnyKeyPressed(config.button_open_overlay) & 0x1) + { + show_overlay = !show_overlay; + + if (show_overlay) + { + ShowWindow(g_hwnd, SW_SHOW); + SetForegroundWindow(g_hwnd); + } + else + { + ShowWindow(g_hwnd, SW_HIDE); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + + if (show_overlay) + { + ImGui_ImplDX11_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowSize(ImVec2((float)overlayWidth, (float)overlayHeight)); + + ImGui::Begin( + "Options", + &show_overlay, + ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + { + std::lock_guard lock(configMutex); + const bool want_bg = OverlayUI::g_menu_bg_enabled && !OverlayUI::g_menu_bg_path.empty(); + if (!want_bg) + { + if (g_menu_bg_texture) + { + g_menu_bg_texture->Release(); + g_menu_bg_texture = nullptr; + } + g_menu_bg_loaded_path.clear(); + g_menu_bg_loaded_ok = false; + g_menu_bg_w = 0; + g_menu_bg_h = 0; + } + else if (g_menu_bg_loaded_path != OverlayUI::g_menu_bg_path || !g_menu_bg_loaded_ok) + { + if (g_menu_bg_texture) + { + g_menu_bg_texture->Release(); + g_menu_bg_texture = nullptr; + } + g_menu_bg_w = 0; + g_menu_bg_h = 0; + g_menu_bg_loaded_ok = LoadTextureFromFile( + OverlayUI::g_menu_bg_path.c_str(), + g_pd3dDevice, + &g_menu_bg_texture, + &g_menu_bg_w, + &g_menu_bg_h); + g_menu_bg_loaded_path = OverlayUI::g_menu_bg_path; + } + + if (g_menu_bg_texture && g_menu_bg_loaded_ok) + { + ImDrawList* bg = ImGui::GetWindowDrawList(); + ImVec2 wp = ImGui::GetWindowPos(); + ImVec2 ws = ImGui::GetWindowSize(); + const float a = (std::clamp)(OverlayUI::g_menu_bg_opacity, 0.02f, 1.0f); + bg->AddImage( + (ImTextureID)g_menu_bg_texture, + wp, + ImVec2(wp.x + ws.x, wp.y + ws.y), + ImVec2(0, 0), + ImVec2(1, 1), + IM_COL32(255, 255, 255, (int)(a * 255.0f))); + } + + static int selected_tab = 0; + if (OverlayUI::g_nav_width < 120.0f) + OverlayUI::g_nav_width = 172.0f; + const float nav_width = OverlayUI::g_nav_width * config.overlay_ui_scale; + + ImGui::BeginChild("left_nav", ImVec2(nav_width, 0), true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + ImGui::Text("NAVIGATION"); + ImGui::Separator(); + + enum class NavIcon + { + Camera, Target, Layers, Mouse, Brain, Gamepad, Eye, Chart, Bug, Cube + }; + struct NavItem { NavIcon icon; const char* label; }; + static const NavItem kItems[] = { + { NavIcon::Camera, "Capture" }, + { NavIcon::Target, "Target" }, + { NavIcon::Layers, "Classes" }, + { NavIcon::Mouse, "Mouse" }, + { NavIcon::Brain, "AI" }, + { NavIcon::Gamepad, "Buttons" }, + { NavIcon::Eye, "Overlay" }, + { NavIcon::Eye, "Game Overlay" }, + { NavIcon::Chart, "Stats" }, + { NavIcon::Bug, "Debug" }, + { NavIcon::Cube, "Components" }, + }; + + auto draw_nav_icon = [](ImDrawList* dl, NavIcon icon, const ImVec2& p, float s, ImU32 col) + { + const float t = 1.7f; + const float r = s * 0.5f; + const float cx = p.x + r; + const float cy = p.y + r; + switch (icon) + { + case NavIcon::Camera: + dl->AddRect(ImVec2(p.x + s * 0.12f, p.y + s * 0.28f), ImVec2(p.x + s * 0.88f, p.y + s * 0.80f), col, 3.0f, 0, t); + dl->AddCircle(ImVec2(cx, p.y + s * 0.54f), s * 0.14f, col, 0, t); + dl->AddRect(ImVec2(p.x + s * 0.26f, p.y + s * 0.16f), ImVec2(p.x + s * 0.44f, p.y + s * 0.30f), col, 2.0f, 0, t); + break; + case NavIcon::Target: + dl->AddCircle(ImVec2(cx, cy), s * 0.36f, col, 0, t); + dl->AddCircle(ImVec2(cx, cy), s * 0.16f, col, 0, t); + dl->AddCircleFilled(ImVec2(cx, cy), s * 0.04f, col); + break; + case NavIcon::Layers: + for (int i = 0; i < 3; ++i) + { + float y = p.y + s * (0.22f + i * 0.22f); + ImVec2 pts[4] = { + ImVec2(cx, y), + ImVec2(p.x + s * 0.86f, y + s * 0.10f), + ImVec2(cx, y + s * 0.20f), + ImVec2(p.x + s * 0.14f, y + s * 0.10f) + }; + dl->AddPolyline(pts, 4, col, true, t); + } + break; + case NavIcon::Mouse: + dl->AddRect(ImVec2(p.x + s * 0.30f, p.y + s * 0.14f), ImVec2(p.x + s * 0.70f, p.y + s * 0.86f), col, 6.0f, 0, t); + dl->AddLine(ImVec2(cx, p.y + s * 0.20f), ImVec2(cx, p.y + s * 0.44f), col, t); + dl->AddCircleFilled(ImVec2(cx, p.y + s * 0.30f), s * 0.03f, col); + break; + case NavIcon::Brain: + dl->AddCircle(ImVec2(p.x + s * 0.38f, p.y + s * 0.40f), s * 0.16f, col, 0, t); + dl->AddCircle(ImVec2(p.x + s * 0.62f, p.y + s * 0.40f), s * 0.16f, col, 0, t); + dl->AddCircle(ImVec2(p.x + s * 0.38f, p.y + s * 0.64f), s * 0.16f, col, 0, t); + dl->AddCircle(ImVec2(p.x + s * 0.62f, p.y + s * 0.64f), s * 0.16f, col, 0, t); + dl->AddLine(ImVec2(cx, p.y + s * 0.22f), ImVec2(cx, p.y + s * 0.82f), col, t); + break; + case NavIcon::Gamepad: + dl->AddRect(ImVec2(p.x + s * 0.16f, p.y + s * 0.36f), ImVec2(p.x + s * 0.84f, p.y + s * 0.78f), col, 5.0f, 0, t); + dl->AddLine(ImVec2(p.x + s * 0.30f, p.y + s * 0.56f), ImVec2(p.x + s * 0.42f, p.y + s * 0.56f), col, t); + dl->AddLine(ImVec2(p.x + s * 0.36f, p.y + s * 0.50f), ImVec2(p.x + s * 0.36f, p.y + s * 0.62f), col, t); + dl->AddCircle(ImVec2(p.x + s * 0.64f, p.y + s * 0.56f), s * 0.04f, col, 0, t); + dl->AddCircle(ImVec2(p.x + s * 0.74f, p.y + s * 0.56f), s * 0.04f, col, 0, t); + break; + case NavIcon::Eye: + dl->AddBezierCubic(ImVec2(p.x + s * 0.14f, cy), ImVec2(p.x + s * 0.30f, p.y + s * 0.20f), ImVec2(p.x + s * 0.70f, p.y + s * 0.20f), ImVec2(p.x + s * 0.86f, cy), col, t); + dl->AddBezierCubic(ImVec2(p.x + s * 0.14f, cy), ImVec2(p.x + s * 0.30f, p.y + s * 0.80f), ImVec2(p.x + s * 0.70f, p.y + s * 0.80f), ImVec2(p.x + s * 0.86f, cy), col, t); + dl->AddCircle(ImVec2(cx, cy), s * 0.10f, col, 0, t); + break; + case NavIcon::Chart: + dl->AddLine(ImVec2(p.x + s * 0.16f, p.y + s * 0.80f), ImVec2(p.x + s * 0.86f, p.y + s * 0.80f), col, t); + dl->AddLine(ImVec2(p.x + s * 0.16f, p.y + s * 0.24f), ImVec2(p.x + s * 0.16f, p.y + s * 0.80f), col, t); + dl->AddLine(ImVec2(p.x + s * 0.32f, p.y + s * 0.80f), ImVec2(p.x + s * 0.32f, p.y + s * 0.52f), col, t); + dl->AddLine(ImVec2(p.x + s * 0.50f, p.y + s * 0.80f), ImVec2(p.x + s * 0.50f, p.y + s * 0.36f), col, t); + dl->AddLine(ImVec2(p.x + s * 0.68f, p.y + s * 0.80f), ImVec2(p.x + s * 0.68f, p.y + s * 0.60f), col, t); + break; + case NavIcon::Bug: + dl->AddCircle(ImVec2(cx, p.y + s * 0.54f), s * 0.20f, col, 0, t); + dl->AddCircle(ImVec2(cx, p.y + s * 0.30f), s * 0.10f, col, 0, t); + dl->AddLine(ImVec2(p.x + s * 0.26f, p.y + s * 0.50f), ImVec2(p.x + s * 0.12f, p.y + s * 0.44f), col, t); + dl->AddLine(ImVec2(p.x + s * 0.26f, p.y + s * 0.62f), ImVec2(p.x + s * 0.12f, p.y + s * 0.68f), col, t); + dl->AddLine(ImVec2(p.x + s * 0.74f, p.y + s * 0.50f), ImVec2(p.x + s * 0.88f, p.y + s * 0.44f), col, t); + dl->AddLine(ImVec2(p.x + s * 0.74f, p.y + s * 0.62f), ImVec2(p.x + s * 0.88f, p.y + s * 0.68f), col, t); + break; + case NavIcon::Cube: + { + ImVec2 pts[6] = { + ImVec2(cx, p.y + s * 0.16f), + ImVec2(p.x + s * 0.80f, p.y + s * 0.30f), + ImVec2(p.x + s * 0.80f, p.y + s * 0.68f), + ImVec2(cx, p.y + s * 0.84f), + ImVec2(p.x + s * 0.20f, p.y + s * 0.68f), + ImVec2(p.x + s * 0.20f, p.y + s * 0.30f) + }; + dl->AddPolyline(pts, 6, col, true, t); + dl->AddLine(ImVec2(cx, p.y + s * 0.16f), ImVec2(cx, p.y + s * 0.52f), col, t); + dl->AddLine(ImVec2(p.x + s * 0.20f, p.y + s * 0.30f), ImVec2(cx, p.y + s * 0.52f), col, t); + dl->AddLine(ImVec2(p.x + s * 0.80f, p.y + s * 0.30f), ImVec2(cx, p.y + s * 0.52f), col, t); + break; + } + } + }; + + for (int i = 0; i < IM_ARRAYSIZE(kItems); ++i) + { + const bool active = (selected_tab == i); + if (active) + { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.22f, 0.29f, 0.38f, 0.55f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.25f, 0.33f, 0.43f, 0.70f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.28f, 0.36f, 0.47f, 0.80f)); + } + else + { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.00f, 0.00f, 0.00f, 0.00f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.20f, 0.24f, 0.30f, 0.35f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.22f, 0.28f, 0.36f, 0.50f)); + } + + std::string title = std::string(" ") + kItems[i].label; + if (ImGui::Button(title.c_str(), ImVec2(-1.0f, 34.0f * config.overlay_ui_scale))) + selected_tab = i; + ImVec2 rmin = ImGui::GetItemRectMin(); + float ih = ImGui::GetItemRectSize().y; + ImU32 icol = active ? IM_COL32(248, 248, 248, 255) : IM_COL32(220, 220, 220, 245); + ImVec2 ipos(rmin.x + 8.0f * config.overlay_ui_scale, rmin.y + (ih - 16.0f * config.overlay_ui_scale) * 0.5f); + draw_nav_icon(ImGui::GetWindowDrawList(), kItems[i].icon, ipos, 16.0f * config.overlay_ui_scale, icol); + ImGui::PopStyleColor(3); + } + ImGui::EndChild(); + + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.16f, 0.19f, 0.24f, 0.90f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.25f, 0.31f, 0.40f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.25f, 0.31f, 0.40f, 1.00f)); + ImGui::Button("##nav_splitter", ImVec2(6.0f, -1.0f)); + ImGui::PopStyleColor(3); + if (ImGui::IsItemActive()) + { + OverlayUI::g_nav_width += ImGui::GetIO().MouseDelta.x / (std::max)(0.25f, config.overlay_ui_scale); + OverlayUI::g_nav_width = (std::clamp)(OverlayUI::g_nav_width, 120.0f, 360.0f); + OverlayTheme_Save("ui_theme.ini"); + } + + ImGui::SameLine(); + ImGui::BeginChild( + "right_panel", + ImVec2(0, 0), + false, + ImGuiWindowFlags_None); + switch (selected_tab) + { + case 0: draw_capture_settings(); break; + case 1: draw_target(); break; + case 2: draw_classes(); break; + case 3: draw_mouse(); break; + case 4: draw_ai(); break; + case 5: draw_buttons(); break; + case 6: draw_overlay(); break; + case 7: draw_game_overlay_settings(); break; + case 8: draw_stats(); break; + case 9: draw_debug(); break; + case 10: draw_components(); break; + default: draw_capture_settings(); break; + } + ImGui::EndChild(); + + if (prev_opacity != config.overlay_opacity) + { + BYTE opacity = config.overlay_opacity; + SetLayeredWindowAttributes(g_hwnd, 0, opacity, LWA_ALPHA); + OverlayConfig_MarkDirty(); + prev_opacity = config.overlay_opacity; + } + + // Visible resize handles (right edge, bottom edge, and corner). + const float edge_thickness = 8.0f; + const float grip_size = 24.0f; + const ImVec2 wpos = ImGui::GetWindowPos(); + const ImVec2 wsize = ImGui::GetWindowSize(); + ImDrawList* wnd_dl = ImGui::GetWindowDrawList(); + + // Right edge handle. + ImGui::SetCursorScreenPos(ImVec2(wpos.x + wsize.x - edge_thickness, wpos.y)); + ImGui::InvisibleButton("##overlay_resize_right", ImVec2(edge_thickness, wsize.y - grip_size)); + if (ImGui::IsItemHovered() || ImGui::IsItemActive()) + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + if (ImGui::IsItemActive()) + { + overlayWidth = (std::max)(520, overlayWidth + static_cast(ImGui::GetIO().MouseDelta.x)); + SetWindowPos(g_hwnd, NULL, 0, 0, overlayWidth, overlayHeight, SWP_NOMOVE | SWP_NOZORDER); + } + + // Bottom edge handle. + ImGui::SetCursorScreenPos(ImVec2(wpos.x, wpos.y + wsize.y - edge_thickness)); + ImGui::InvisibleButton("##overlay_resize_bottom", ImVec2(wsize.x - grip_size, edge_thickness)); + if (ImGui::IsItemHovered() || ImGui::IsItemActive()) + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); + if (ImGui::IsItemActive()) + { + overlayHeight = (std::max)(360, overlayHeight + static_cast(ImGui::GetIO().MouseDelta.y)); + SetWindowPos(g_hwnd, NULL, 0, 0, overlayWidth, overlayHeight, SWP_NOMOVE | SWP_NOZORDER); + } + + // Bottom-right corner grip. + ImVec2 grip_pos(wpos.x + wsize.x - grip_size, wpos.y + wsize.y - grip_size); + ImGui::SetCursorScreenPos(grip_pos); + ImGui::InvisibleButton("##overlay_resize_grip", ImVec2(grip_size, grip_size)); + const bool grip_hot = ImGui::IsItemHovered() || ImGui::IsItemActive(); + if (grip_hot) + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNWSE); + const ImU32 grip_col = grip_hot ? IM_COL32(190, 220, 255, 240) : IM_COL32(145, 170, 205, 190); + wnd_dl->AddLine( + ImVec2(grip_pos.x + 6.0f, grip_pos.y + grip_size - 4.0f), + ImVec2(grip_pos.x + grip_size - 4.0f, grip_pos.y + 6.0f), + grip_col, 1.8f); + wnd_dl->AddLine( + ImVec2(grip_pos.x + 11.0f, grip_pos.y + grip_size - 4.0f), + ImVec2(grip_pos.x + grip_size - 4.0f, grip_pos.y + 11.0f), + grip_col, 1.8f); + if (ImGui::IsItemActive()) + { + overlayWidth = (std::max)(520, overlayWidth + static_cast(ImGui::GetIO().MouseDelta.x)); + overlayHeight = (std::max)(360, overlayHeight + static_cast(ImGui::GetIO().MouseDelta.y)); + SetWindowPos(g_hwnd, NULL, 0, 0, overlayWidth, overlayHeight, SWP_NOMOVE | SWP_NOZORDER); + } + } + + ImGui::End(); + ImGui::Render(); + + const float clear_color_with_alpha[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL); + g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); + ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); + + HRESULT result = g_pSwapChain->Present(0, 0); + + if (result == DXGI_STATUS_OCCLUDED || result == DXGI_ERROR_ACCESS_LOST) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + OverlayConfig_FlushIfDue(220); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + else + { + OverlayConfig_FlushIfDue(220); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + } + + OverlayConfig_FlushNow(); + + release_body_texture(); + + ImGui_ImplDX11_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); + + CleanupDeviceD3D(); + ::DestroyWindow(g_hwnd); + ::UnregisterClass(_T("Edge"), GetModuleHandle(NULL)); +} + +int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPTSTR lpCmdLine, + _In_ int nCmdShow) +{ + std::thread overlay(OverlayThread); + overlay.join(); + return 0; +} + diff --git a/sunone_aimbot_cpp/overlay/overlay.h b/RN_AI_cpp/overlay/overlay.h similarity index 96% rename from sunone_aimbot_cpp/overlay/overlay.h rename to RN_AI_cpp/overlay/overlay.h index 91ce3486..935583ec 100644 --- a/sunone_aimbot_cpp/overlay/overlay.h +++ b/RN_AI_cpp/overlay/overlay.h @@ -6,7 +6,7 @@ #include #include -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" extern ID3D11Device* g_pd3dDevice; extern ID3D11DeviceContext* g_pd3dDeviceContext; diff --git a/RN_AI_cpp/overlay/ui_controls.cpp b/RN_AI_cpp/overlay/ui_controls.cpp new file mode 100644 index 00000000..1042c9c6 --- /dev/null +++ b/RN_AI_cpp/overlay/ui_controls.cpp @@ -0,0 +1,183 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#include + +#include "imgui/imgui.h" +#include "ui_controls.h" +#include "ui_runtime.h" + +namespace OverlayUI +{ +bool SliderIntWithButtons(const char* label, int* value, int minValue, int maxValue, int step, const char* sliderFormat) +{ + bool changed = false; + ImGui::PushID(label); + ImGui::TextUnformatted(label); + + if (ImGui::Button("-", ImVec2(24.0f, 0.0f))) + { + *value = std::clamp(*value - step, minValue, maxValue); + changed = true; + } + + ImGui::SameLine(); + ImGui::SetNextItemWidth(220.0f); + changed |= ImGui::SliderInt("##slider", value, minValue, maxValue, sliderFormat); + + ImGui::SameLine(); + if (ImGui::Button("+", ImVec2(24.0f, 0.0f))) + { + *value = std::clamp(*value + step, minValue, maxValue); + changed = true; + } + + ImGui::SameLine(); + ImGui::SetNextItemWidth(90.0f); + if (ImGui::InputInt("##input", value, 0, 0)) + { + *value = std::clamp(*value, minValue, maxValue); + changed = true; + } + + ImGui::PopID(); + return changed; +} + +bool SliderFloatWithButtons(const char* label, float* value, float minValue, float maxValue, float step, const char* sliderFormat, const char* inputFormat) +{ + bool changed = false; + ImGui::PushID(label); + ImGui::TextUnformatted(label); + + if (ImGui::Button("-", ImVec2(24.0f, 0.0f))) + { + *value = std::clamp(*value - step, minValue, maxValue); + changed = true; + } + + ImGui::SameLine(); + ImGui::SetNextItemWidth(220.0f); + changed |= ImGui::SliderFloat("##slider", value, minValue, maxValue, sliderFormat); + + ImGui::SameLine(); + if (ImGui::Button("+", ImVec2(24.0f, 0.0f))) + { + *value = std::clamp(*value + step, minValue, maxValue); + changed = true; + } + + ImGui::SameLine(); + ImGui::SetNextItemWidth(90.0f); + if (ImGui::InputFloat("##input", value, 0.0f, 0.0f, inputFormat)) + { + *value = std::clamp(*value, minValue, maxValue); + changed = true; + } + + ImGui::PopID(); + return changed; +} + +bool IntControlRow(const char* label, int* value, int minValue, int maxValue, int step, const char* unit, const char* hint) +{ + bool changed = false; + ImGui::PushID(label); + + const float rowAvail = ImGui::GetContentRegionAvail().x; + const float btnW = g_row_button_width; + const float inputW = g_row_input_width; + const float unitW = (unit && unit[0] != '\0') ? (ImGui::CalcTextSize(unit).x + 8.0f) : 0.0f; + float sliderW = rowAvail - btnW - btnW - inputW - unitW - 16.0f; + sliderW = (std::max)(80.0f, sliderW); + + ImGui::TextUnformatted(label); + ImGui::SetNextItemWidth(sliderW); + + if (ImGui::Button("-", ImVec2(btnW, 0.0f))) + { + *value = std::clamp(*value - step, minValue, maxValue); + changed = true; + } + ImGui::SameLine(); + changed |= ImGui::SliderInt("##slider", value, minValue, maxValue, ""); + ImGui::SameLine(); + if (ImGui::Button("+", ImVec2(btnW, 0.0f))) + { + *value = std::clamp(*value + step, minValue, maxValue); + changed = true; + } + ImGui::SameLine(); + ImGui::SetNextItemWidth(inputW); + if (ImGui::InputInt("##input", value, 0, 0)) + { + *value = std::clamp(*value, minValue, maxValue); + changed = true; + } + if (unit && unit[0] != '\0') + { + ImGui::SameLine(); + ImGui::TextUnformatted(unit); + } + + if (g_show_descriptions && hint && hint[0] != '\0') + { + ImGui::TextDisabled("%s", hint); + } + + ImGui::PopID(); + return changed; +} + +bool FloatControlRow(const char* label, float* value, float minValue, float maxValue, float step, const char* sliderFormat, const char* inputFormat, const char* unit, const char* hint) +{ + bool changed = false; + ImGui::PushID(label); + + const float rowAvail = ImGui::GetContentRegionAvail().x; + const float btnW = g_row_button_width; + const float inputW = g_row_input_width; + const float unitW = (unit && unit[0] != '\0') ? (ImGui::CalcTextSize(unit).x + 8.0f) : 0.0f; + float sliderW = rowAvail - btnW - btnW - inputW - unitW - 16.0f; + sliderW = (std::max)(80.0f, sliderW); + + ImGui::TextUnformatted(label); + + if (ImGui::Button("-", ImVec2(btnW, 0.0f))) + { + *value = std::clamp(*value - step, minValue, maxValue); + changed = true; + } + ImGui::SameLine(); + ImGui::SetNextItemWidth(sliderW); + changed |= ImGui::SliderFloat("##slider", value, minValue, maxValue, sliderFormat); + ImGui::SameLine(); + if (ImGui::Button("+", ImVec2(btnW, 0.0f))) + { + *value = std::clamp(*value + step, minValue, maxValue); + changed = true; + } + ImGui::SameLine(); + ImGui::SetNextItemWidth(inputW); + if (ImGui::InputFloat("##input", value, 0.0f, 0.0f, inputFormat)) + { + *value = std::clamp(*value, minValue, maxValue); + changed = true; + } + if (unit && unit[0] != '\0') + { + ImGui::SameLine(); + ImGui::TextUnformatted(unit); + } + + if (g_show_descriptions && hint && hint[0] != '\0') + { + ImGui::TextDisabled("%s", hint); + } + + ImGui::PopID(); + return changed; +} +} diff --git a/RN_AI_cpp/overlay/ui_controls.h b/RN_AI_cpp/overlay/ui_controls.h new file mode 100644 index 00000000..deb97dd8 --- /dev/null +++ b/RN_AI_cpp/overlay/ui_controls.h @@ -0,0 +1,12 @@ +#ifndef OVERLAY_UI_CONTROLS_H +#define OVERLAY_UI_CONTROLS_H + +namespace OverlayUI +{ +bool SliderIntWithButtons(const char* label, int* value, int minValue, int maxValue, int step = 1, const char* sliderFormat = "%d"); +bool SliderFloatWithButtons(const char* label, float* value, float minValue, float maxValue, float step = 0.01f, const char* sliderFormat = "%.2f", const char* inputFormat = "%.3f"); +bool IntControlRow(const char* label, int* value, int minValue, int maxValue, int step, const char* unit = nullptr, const char* hint = nullptr); +bool FloatControlRow(const char* label, float* value, float minValue, float maxValue, float step, const char* sliderFormat = "%.2f", const char* inputFormat = "%.3f", const char* unit = nullptr, const char* hint = nullptr); +} + +#endif // OVERLAY_UI_CONTROLS_H diff --git a/RN_AI_cpp/overlay/ui_runtime.cpp b/RN_AI_cpp/overlay/ui_runtime.cpp new file mode 100644 index 00000000..2842f6be --- /dev/null +++ b/RN_AI_cpp/overlay/ui_runtime.cpp @@ -0,0 +1,19 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#include "ui_runtime.h" + +namespace OverlayUI +{ +bool g_show_descriptions = true; +float g_row_button_width = 22.0f; +float g_row_input_width = 54.0f; +float g_nav_width = 172.0f; +bool g_menu_bg_enabled = false; +float g_menu_bg_opacity = 0.22f; +std::string g_menu_bg_path = "ui_bg.png"; +float g_overlay_fps_text_size = 19.0f; +float g_overlay_latency_text_size = 18.0f; +} diff --git a/RN_AI_cpp/overlay/ui_runtime.h b/RN_AI_cpp/overlay/ui_runtime.h new file mode 100644 index 00000000..1229e826 --- /dev/null +++ b/RN_AI_cpp/overlay/ui_runtime.h @@ -0,0 +1,19 @@ +#ifndef OVERLAY_UI_RUNTIME_H +#define OVERLAY_UI_RUNTIME_H + +#include + +namespace OverlayUI +{ +extern bool g_show_descriptions; +extern float g_row_button_width; +extern float g_row_input_width; +extern float g_nav_width; +extern bool g_menu_bg_enabled; +extern float g_menu_bg_opacity; +extern std::string g_menu_bg_path; +extern float g_overlay_fps_text_size; +extern float g_overlay_latency_text_size; +} + +#endif // OVERLAY_UI_RUNTIME_H diff --git a/RN_AI_cpp/overlay/ui_sections.cpp b/RN_AI_cpp/overlay/ui_sections.cpp new file mode 100644 index 00000000..4e4d4c16 --- /dev/null +++ b/RN_AI_cpp/overlay/ui_sections.cpp @@ -0,0 +1,97 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#include +#include + +#include "imgui/imgui.h" +#include "ui_sections.h" + +namespace OverlayUI +{ +namespace +{ +struct CardState +{ + ImVec2 topLeft; + float width; + float headerHeight; +}; + +std::vector g_card_stack; +} + +bool BeginSection(const char* title, const char* id) +{ + ImGui::SeparatorText(title); + const char* sectionId = id ? id : title; + ImGui::PushID(sectionId); + ImGui::BeginGroup(); + return true; +} + +void EndSection() +{ + ImGui::EndGroup(); + ImGui::PopID(); + ImGui::Spacing(); +} + +bool BeginCard(const char* title, const char* id) +{ + const char* cardId = id ? id : title; + ImGui::PushID(cardId); + + const float width = ImGui::GetContentRegionAvail().x; + const ImVec2 topLeft = ImGui::GetCursorScreenPos(); + const float headerHeight = ImGui::GetFrameHeight() + 6.0f; + + ImDrawList* dl = ImGui::GetWindowDrawList(); + const ImVec4 borderCol = ImGui::GetStyleColorVec4(ImGuiCol_Border); + const ImVec4 headerCol = ImGui::GetStyleColorVec4(ImGuiCol_TitleBgActive); + const ImVec4 bgCol = ImGui::GetStyleColorVec4(ImGuiCol_FrameBg); + + dl->AddRectFilled(topLeft, ImVec2(topLeft.x + width, topLeft.y + headerHeight), ImGui::ColorConvertFloat4ToU32(headerCol), 0.0f); + dl->AddRectFilled(ImVec2(topLeft.x + 1.0f, topLeft.y + headerHeight + 1.0f), ImVec2(topLeft.x + width - 1.0f, topLeft.y + headerHeight + 2.0f), ImGui::ColorConvertFloat4ToU32(borderCol), 0.0f); + dl->AddRectFilled(ImVec2(topLeft.x + 1.0f, topLeft.y + headerHeight + 2.0f), ImVec2(topLeft.x + width - 1.0f, topLeft.y + headerHeight + 3.0f), ImGui::ColorConvertFloat4ToU32(bgCol), 0.0f); + dl->AddText(ImVec2(topLeft.x + 10.0f, topLeft.y + 4.0f), ImGui::GetColorU32(ImGuiCol_Text), title); + + ImGui::Dummy(ImVec2(width, headerHeight + 6.0f)); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10.0f); + ImGui::BeginGroup(); + + g_card_stack.push_back({ topLeft, width, headerHeight }); + return true; +} + +void EndCard() +{ + if (g_card_stack.empty()) + { + ImGui::PopID(); + return; + } + + ImGui::EndGroup(); + ImVec2 contentMax = ImGui::GetItemRectMax(); + CardState st = g_card_stack.back(); + g_card_stack.pop_back(); + + const float bottom = contentMax.y + 10.0f; + ImDrawList* dl = ImGui::GetWindowDrawList(); + dl->AddRect(st.topLeft, ImVec2(st.topLeft.x + st.width, bottom), ImGui::GetColorU32(ImGuiCol_Border), 0.0f, 0, 1.0f); + + const float localBottom = bottom - ImGui::GetWindowPos().y; + ImGui::SetCursorPosY(localBottom + 8.0f); + ImGui::PopID(); +} + +void AdaptiveItemWidth(float ratio, float minWidth, float maxWidth) +{ + const float avail = ImGui::GetContentRegionAvail().x; + const float width = std::clamp(avail * ratio, minWidth, maxWidth); + ImGui::SetNextItemWidth(width); +} +} diff --git a/RN_AI_cpp/overlay/ui_sections.h b/RN_AI_cpp/overlay/ui_sections.h new file mode 100644 index 00000000..f1024fa3 --- /dev/null +++ b/RN_AI_cpp/overlay/ui_sections.h @@ -0,0 +1,13 @@ +#ifndef OVERLAY_UI_SECTIONS_H +#define OVERLAY_UI_SECTIONS_H + +namespace OverlayUI +{ +bool BeginSection(const char* title, const char* id = nullptr); +void EndSection(); +bool BeginCard(const char* title, const char* id = nullptr); +void EndCard(); +void AdaptiveItemWidth(float ratio = 0.60f, float minWidth = 220.0f, float maxWidth = 520.0f); +} + +#endif // OVERLAY_UI_SECTIONS_H diff --git a/RN_AI_cpp/overlay/ui_theme.cpp b/RN_AI_cpp/overlay/ui_theme.cpp new file mode 100644 index 00000000..e866bb72 --- /dev/null +++ b/RN_AI_cpp/overlay/ui_theme.cpp @@ -0,0 +1,276 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "imgui/imgui.h" +#include "ui_theme.h" +#include "ui_runtime.h" + +namespace +{ +std::string trim_ascii(const std::string& s) +{ + size_t b = 0; + while (b < s.size() && std::isspace(static_cast(s[b])) != 0) + ++b; + size_t e = s.size(); + while (e > b && std::isspace(static_cast(s[e - 1])) != 0) + --e; + return s.substr(b, e - b); +} + +std::vector parse_floats_csv(const std::string& csv) +{ + std::vector out; + std::stringstream ss(csv); + std::string token; + while (std::getline(ss, token, ',')) + { + token = trim_ascii(token); + if (token.empty()) + continue; + try + { + out.push_back(std::stof(token)); + } + catch (...) + { + return {}; + } + } + return out; +} + +bool parse_color(const std::string& value, ImVec4& out) +{ + auto vals = parse_floats_csv(value); + if (vals.size() < 3 || vals.size() > 4) + return false; + + float r = vals[0]; + float g = vals[1]; + float b = vals[2]; + float a = vals.size() == 4 ? vals[3] : 1.0f; + + const bool byteRange = (r > 1.0f || g > 1.0f || b > 1.0f || a > 1.0f); + if (byteRange) + { + r /= 255.0f; + g /= 255.0f; + b /= 255.0f; + a /= 255.0f; + } + + out = ImVec4( + std::clamp(r, 0.0f, 1.0f), + std::clamp(g, 0.0f, 1.0f), + std::clamp(b, 0.0f, 1.0f), + std::clamp(a, 0.0f, 1.0f)); + return true; +} + +void write_default_theme_file(const char* filename) +{ + std::ofstream out(filename, std::ios::trunc); + if (!out.is_open()) + return; + + out << "# UI theme values. Colors: r,g,b,a (0..255 or 0..1)\n"; + out << "alpha = 1.0\n"; + out << "window_rounding = 6\n"; + out << "frame_rounding = 4\n"; + out << "grab_rounding = 4\n"; + out << "scrollbar_rounding = 6\n"; + out << "item_spacing_x = 8\n"; + out << "item_spacing_y = 6\n"; + out << "frame_padding_x = 6\n"; + out << "frame_padding_y = 4\n"; + out << "color_text = 230,230,230,255\n"; + out << "color_window_bg = 22,22,24,240\n"; + out << "color_title_bg = 28,30,34,255\n"; + out << "color_title_bg_active = 42,46,52,255\n"; + out << "color_frame_bg = 36,39,44,255\n"; + out << "color_frame_bg_hovered = 48,53,60,255\n"; + out << "color_frame_bg_active = 56,62,72,255\n"; + out << "color_button = 42,74,124,255\n"; + out << "color_button_hovered = 60,96,152,255\n"; + out << "color_button_active = 78,118,176,255\n"; + out << "color_header = 42,74,124,190\n"; + out << "color_header_hovered = 60,96,152,220\n"; + out << "color_header_active = 78,118,176,255\n"; + out << "color_border = 69,86,120,255\n"; + out << "color_tab = 45,47,52,255\n"; + out << "color_tab_hovered = 58,64,74,255\n"; + out << "color_tab_active = 67,74,86,255\n"; + out << "show_descriptions = 1\n"; + out << "row_button_width = 22\n"; + out << "row_input_width = 54\n"; + out << "nav_width = 172\n"; + out << "menu_bg_enabled = 0\n"; + out << "menu_bg_opacity = 0.22\n"; + out << "menu_bg_path = ui_bg.png\n"; + out << "overlay_fps_text_size = 19\n"; + out << "overlay_latency_text_size = 18\n"; +} + +bool load_and_apply_internal(const char* filename) +{ + ImGuiStyle& style = ImGui::GetStyle(); + if (!std::ifstream(filename).good()) + write_default_theme_file(filename); + + std::ifstream in(filename); + if (!in.is_open()) + return false; + + std::string line; + while (std::getline(in, line)) + { + line = trim_ascii(line); + if (line.empty() || line[0] == '#') + continue; + + const size_t eq = line.find('='); + if (eq == std::string::npos) + continue; + std::string key = trim_ascii(line.substr(0, eq)); + std::string val = trim_ascii(line.substr(eq + 1)); + if (key.empty() || val.empty()) + continue; + + try + { + if (key == "alpha") style.Alpha = std::stof(val); + else if (key == "window_rounding") style.WindowRounding = std::stof(val); + else if (key == "frame_rounding") style.FrameRounding = std::stof(val); + else if (key == "grab_rounding") style.GrabRounding = std::stof(val); + else if (key == "scrollbar_rounding") style.ScrollbarRounding = std::stof(val); + else if (key == "item_spacing_x") style.ItemSpacing.x = std::stof(val); + else if (key == "item_spacing_y") style.ItemSpacing.y = std::stof(val); + else if (key == "frame_padding_x") style.FramePadding.x = std::stof(val); + else if (key == "frame_padding_y") style.FramePadding.y = std::stof(val); + else if (key == "color_text") parse_color(val, style.Colors[ImGuiCol_Text]); + else if (key == "color_window_bg") parse_color(val, style.Colors[ImGuiCol_WindowBg]); + else if (key == "color_title_bg") parse_color(val, style.Colors[ImGuiCol_TitleBg]); + else if (key == "color_title_bg_active") parse_color(val, style.Colors[ImGuiCol_TitleBgActive]); + else if (key == "color_frame_bg") parse_color(val, style.Colors[ImGuiCol_FrameBg]); + else if (key == "color_frame_bg_hovered") parse_color(val, style.Colors[ImGuiCol_FrameBgHovered]); + else if (key == "color_frame_bg_active") parse_color(val, style.Colors[ImGuiCol_FrameBgActive]); + else if (key == "color_button") parse_color(val, style.Colors[ImGuiCol_Button]); + else if (key == "color_button_hovered") parse_color(val, style.Colors[ImGuiCol_ButtonHovered]); + else if (key == "color_button_active") parse_color(val, style.Colors[ImGuiCol_ButtonActive]); + else if (key == "color_header") parse_color(val, style.Colors[ImGuiCol_Header]); + else if (key == "color_header_hovered") parse_color(val, style.Colors[ImGuiCol_HeaderHovered]); + else if (key == "color_header_active") parse_color(val, style.Colors[ImGuiCol_HeaderActive]); + else if (key == "color_border") parse_color(val, style.Colors[ImGuiCol_Border]); + else if (key == "color_tab") parse_color(val, style.Colors[ImGuiCol_Tab]); + else if (key == "color_tab_hovered") parse_color(val, style.Colors[ImGuiCol_TabHovered]); + else if (key == "color_tab_active") parse_color(val, style.Colors[ImGuiCol_TabActive]); + else if (key == "show_descriptions") OverlayUI::g_show_descriptions = (std::stoi(val) != 0); + else if (key == "row_button_width") OverlayUI::g_row_button_width = std::stof(val); + else if (key == "row_input_width") OverlayUI::g_row_input_width = std::stof(val); + else if (key == "nav_width") OverlayUI::g_nav_width = std::stof(val); + else if (key == "menu_bg_enabled") OverlayUI::g_menu_bg_enabled = (std::stoi(val) != 0); + else if (key == "menu_bg_opacity") OverlayUI::g_menu_bg_opacity = std::stof(val); + else if (key == "menu_bg_path") OverlayUI::g_menu_bg_path = val; + else if (key == "overlay_fps_text_size") OverlayUI::g_overlay_fps_text_size = std::stof(val); + else if (key == "overlay_latency_text_size") OverlayUI::g_overlay_latency_text_size = std::stof(val); + } + catch (...) + { + } + } + + style.Alpha = std::clamp(style.Alpha, 0.20f, 1.00f); + OverlayUI::g_row_button_width = std::clamp(OverlayUI::g_row_button_width, 18.0f, 40.0f); + OverlayUI::g_row_input_width = std::clamp(OverlayUI::g_row_input_width, 46.0f, 120.0f); + OverlayUI::g_nav_width = std::clamp(OverlayUI::g_nav_width, 120.0f, 360.0f); + OverlayUI::g_menu_bg_opacity = std::clamp(OverlayUI::g_menu_bg_opacity, 0.02f, 1.00f); + OverlayUI::g_overlay_fps_text_size = std::clamp(OverlayUI::g_overlay_fps_text_size, 10.0f, 48.0f); + OverlayUI::g_overlay_latency_text_size = std::clamp(OverlayUI::g_overlay_latency_text_size, 10.0f, 48.0f); + return true; +} + +bool save_internal(const char* filename) +{ + if (!std::ifstream(filename).good()) + write_default_theme_file(filename); + + std::ofstream out(filename, std::ios::trunc); + if (!out.is_open()) + return false; + + const ImGuiStyle& style = ImGui::GetStyle(); + auto c = [&](ImGuiCol idx) + { + const ImVec4& v = style.Colors[idx]; + int r = static_cast(v.x * 255.0f + 0.5f); + int g = static_cast(v.y * 255.0f + 0.5f); + int b = static_cast(v.z * 255.0f + 0.5f); + int a = static_cast(v.w * 255.0f + 0.5f); + return std::to_string(r) + "," + std::to_string(g) + "," + std::to_string(b) + "," + std::to_string(a); + }; + + out << "# UI theme values. Colors: r,g,b,a (0..255 or 0..1)\n"; + out << "alpha = " << style.Alpha << "\n"; + out << "window_rounding = " << style.WindowRounding << "\n"; + out << "frame_rounding = " << style.FrameRounding << "\n"; + out << "grab_rounding = " << style.GrabRounding << "\n"; + out << "scrollbar_rounding = " << style.ScrollbarRounding << "\n"; + out << "item_spacing_x = " << style.ItemSpacing.x << "\n"; + out << "item_spacing_y = " << style.ItemSpacing.y << "\n"; + out << "frame_padding_x = " << style.FramePadding.x << "\n"; + out << "frame_padding_y = " << style.FramePadding.y << "\n\n"; + + out << "color_text = " << c(ImGuiCol_Text) << "\n"; + out << "color_window_bg = " << c(ImGuiCol_WindowBg) << "\n"; + out << "color_title_bg = " << c(ImGuiCol_TitleBg) << "\n"; + out << "color_title_bg_active = " << c(ImGuiCol_TitleBgActive) << "\n"; + out << "color_frame_bg = " << c(ImGuiCol_FrameBg) << "\n"; + out << "color_frame_bg_hovered = " << c(ImGuiCol_FrameBgHovered) << "\n"; + out << "color_frame_bg_active = " << c(ImGuiCol_FrameBgActive) << "\n"; + out << "color_button = " << c(ImGuiCol_Button) << "\n"; + out << "color_button_hovered = " << c(ImGuiCol_ButtonHovered) << "\n"; + out << "color_button_active = " << c(ImGuiCol_ButtonActive) << "\n"; + out << "color_header = " << c(ImGuiCol_Header) << "\n"; + out << "color_header_hovered = " << c(ImGuiCol_HeaderHovered) << "\n"; + out << "color_header_active = " << c(ImGuiCol_HeaderActive) << "\n"; + out << "color_border = " << c(ImGuiCol_Border) << "\n"; + out << "color_tab = " << c(ImGuiCol_Tab) << "\n"; + out << "color_tab_hovered = " << c(ImGuiCol_TabHovered) << "\n"; + out << "color_tab_active = " << c(ImGuiCol_TabActive) << "\n"; + out << "show_descriptions = " << (OverlayUI::g_show_descriptions ? 1 : 0) << "\n"; + out << "row_button_width = " << OverlayUI::g_row_button_width << "\n"; + out << "row_input_width = " << OverlayUI::g_row_input_width << "\n"; + out << "nav_width = " << OverlayUI::g_nav_width << "\n"; + out << "menu_bg_enabled = " << (OverlayUI::g_menu_bg_enabled ? 1 : 0) << "\n"; + out << "menu_bg_opacity = " << OverlayUI::g_menu_bg_opacity << "\n"; + out << "menu_bg_path = " << OverlayUI::g_menu_bg_path << "\n"; + out << "overlay_fps_text_size = " << OverlayUI::g_overlay_fps_text_size << "\n"; + out << "overlay_latency_text_size = " << OverlayUI::g_overlay_latency_text_size << "\n"; + return true; +} +} + +bool OverlayTheme_LoadAndApply(const char* filename) +{ + return load_and_apply_internal(filename); +} + +bool OverlayTheme_Reload(const char* filename) +{ + return load_and_apply_internal(filename); +} + +bool OverlayTheme_Save(const char* filename) +{ + return save_internal(filename); +} diff --git a/RN_AI_cpp/overlay/ui_theme.h b/RN_AI_cpp/overlay/ui_theme.h new file mode 100644 index 00000000..39c62a99 --- /dev/null +++ b/RN_AI_cpp/overlay/ui_theme.h @@ -0,0 +1,8 @@ +#ifndef OVERLAY_UI_THEME_H +#define OVERLAY_UI_THEME_H + +bool OverlayTheme_LoadAndApply(const char* filename = "ui_theme.ini"); +bool OverlayTheme_Reload(const char* filename = "ui_theme.ini"); +bool OverlayTheme_Save(const char* filename = "ui_theme.ini"); + +#endif // OVERLAY_UI_THEME_H diff --git a/sunone_aimbot_cpp/packages.config b/RN_AI_cpp/packages.config similarity index 100% rename from sunone_aimbot_cpp/packages.config rename to RN_AI_cpp/packages.config diff --git a/RN_AI_cpp/rn_ai_cpp.cpp b/RN_AI_cpp/rn_ai_cpp.cpp new file mode 100644 index 00000000..32eb1941 --- /dev/null +++ b/RN_AI_cpp/rn_ai_cpp.cpp @@ -0,0 +1,2416 @@ +#define WIN32_LEAN_AND_MEAN +#define _WINSOCKAPI_ +#include +#include +#ifndef NOMINMAX +#define NOMINMAX +#endif +#ifdef min +#undef min +#endif +#ifdef max +#undef max +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "capture.h" +#include "mouse.h" +#include "rn_ai_cpp.h" +#include "keyboard_listener.h" +#include "overlay.h" +#include "Game_overlay.h" +#include "overlay/ui_runtime.h" +#include "other_tools.h" +#include "virtual_camera.h" + +std::condition_variable frameCV; +std::atomic shouldExit(false); +std::atomic aiming(false); +std::atomic detectionPaused(false); +std::mutex configMutex; + +#ifdef USE_CUDA +TrtDetector trt_detector; +#endif + + +DirectMLDetector* dml_detector = nullptr; +MouseThread* globalMouseThread = nullptr; +Config config; + +ColorDetector* color_detector = nullptr; +std::thread color_detThread; + +SerialConnection* arduinoSerial = nullptr; +KmboxConnection* kmboxSerial = nullptr; +KmboxNetConnection* kmboxNetSerial = nullptr; +MakcuConnection* makcu_conn = nullptr; + +std::atomic detection_resolution_changed(false); +std::atomic capture_method_changed(false); +std::atomic capture_cursor_changed(false); +std::atomic capture_borders_changed(false); +std::atomic capture_fps_changed(false); +std::atomic capture_window_changed(false); +std::atomic detector_model_changed(false); +std::atomic show_window_changed(false); +std::atomic input_method_changed(false); + +std::atomic zooming(false); +std::atomic shooting(false); +std::atomic triggerbot_button(false); + +Game_overlay* gameOverlayPtr = nullptr; + +namespace +{ +struct MonitorQueryContext +{ + int target_index = 0; + int current_index = 0; + RECT result{ 0, 0, 0, 0 }; + bool found = false; +}; + +BOOL CALLBACK EnumMonitorsProc(HMONITOR hMon, HDC, LPRECT, LPARAM lParam) +{ + auto* ctx = reinterpret_cast(lParam); + if (!ctx) + return TRUE; + + if (ctx->current_index == ctx->target_index) + { + MONITORINFO mi{}; + mi.cbSize = sizeof(mi); + if (GetMonitorInfo(hMon, &mi)) + { + ctx->result = mi.rcMonitor; + ctx->found = true; + return FALSE; + } + } + ++ctx->current_index; + return TRUE; +} + +RECT GetMonitorRectByIndexOrPrimary(int monitorIndex) +{ + MonitorQueryContext ctx; + ctx.target_index = std::max(0, monitorIndex); + EnumDisplayMonitors(nullptr, nullptr, EnumMonitorsProc, reinterpret_cast(&ctx)); + if (ctx.found) + return ctx.result; + + MONITORINFO mi{}; + mi.cbSize = sizeof(mi); + HMONITOR primary = MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); + if (primary && GetMonitorInfo(primary, &mi)) + return mi.rcMonitor; + + RECT fallback{ 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) }; + return fallback; +} + +OverlayColor GetClassOverlayColor(int classId, uint8_t alpha) +{ + if (classId == 0) + return ARGB(alpha, 0, 220, 100); + + static const uint8_t palette[][3] = { + { 235, 80, 80 }, + { 80, 170, 255 }, + { 255, 180, 70 }, + { 180, 110, 255 }, + { 255, 95, 170 }, + { 80, 230, 220 }, + { 230, 230, 80 }, + { 255, 140, 210 } + }; + + const int idx = std::abs(classId) % static_cast(sizeof(palette) / sizeof(palette[0])); + return ARGB(alpha, palette[idx][0], palette[idx][1], palette[idx][2]); +} + +float GetOverlayInferenceLatencyMs() +{ + if (config.backend == "DML" && dml_detector) + return static_cast(dml_detector->lastInferenceTimeDML.count()); + +#ifdef USE_CUDA + return static_cast(trt_detector.lastInferenceTime.count()); +#else + return 0.0f; +#endif +} + +void StopGameOverlay() +{ + if (gameOverlayPtr) + { + gameOverlayPtr->Stop(); + delete gameOverlayPtr; + gameOverlayPtr = nullptr; + } +} + +struct AimSimVec2 +{ + double x = 0.0; + double y = 0.0; +}; + +struct AimSimHistorySample +{ + double timeSec = 0.0; + AimSimVec2 target; + AimSimVec2 aim; +}; + +struct AimSimQueuedMove +{ + double executeAtSec = 0.0; + int mx = 0; + int my = 0; +}; + +struct AimSimulationState +{ + bool initialized = false; + bool controllerInitialized = false; + int panelW = 0; + int panelH = 0; + + std::mt19937 rng{ std::random_device{}() }; + std::chrono::steady_clock::time_point lastWallTime{}; + + double simTimeSec = 0.0; + double accumulatorSec = 0.0; + double currentFps = 100.0; + double targetFps = 100.0; + double fpsRetargetSec = 0.0; + double targetMotionRetargetSec = 0.0; + double lastFrameDtSec = 1.0 / 100.0; + + AimSimVec2 targetPos; + AimSimVec2 targetVel; + AimSimVec2 targetDesiredVel; + AimSimVec2 aimPos; + AimSimVec2 observedTarget; + AimSimVec2 predictedTarget; + + double usedCaptureDelayMs = 0.0; + double usedInferenceDelayMs = 0.0; + double usedInputDelayMs = 0.0; + double usedExtraDelayMs = 0.0; + double usedTotalDelayMs = 0.0; + double lastErrorPx = 0.0; + int lastMoveX = 0; + int lastMoveY = 0; + + double ctrlPrevX = 0.0; + double ctrlPrevY = 0.0; + double ctrlPrevVelocityX = 0.0; + double ctrlPrevVelocityY = 0.0; + double ctrlPrevTimeSec = 0.0; + + double windCarryX = 0.0; + double windCarryY = 0.0; + double windVelX = 0.0; + double windVelY = 0.0; + double windNoiseX = 0.0; + double windNoiseY = 0.0; + double windFracX = 0.0; + double windFracY = 0.0; + double windPatternX = 0.0; + double windPatternY = 0.0; + double windPatternPhaseA = 0.0; + double windPatternPhaseB = 0.0; + double windPatternRateA = 0.0; + double windPatternRateB = 0.0; + std::mt19937 windRng{ std::random_device{}() }; + bool windEnabledSnapshot = false; + double windGSnapshot = 0.0; + double windWSnapshot = 0.0; + double windMSnapshot = 0.0; + double windDSnapshot = 0.0; + + std::deque history; + std::deque queuedMoves; + std::deque targetTrail; + std::deque aimTrail; +}; + +static double aim_sim_random_range(AimSimulationState& s, double minV, double maxV) +{ + std::uniform_real_distribution dist(minV, maxV); + return dist(s.rng); +} + +static double aim_sim_vec_len(const AimSimVec2& v) +{ + return std::hypot(v.x, v.y); +} + +static void aim_sim_reset_wind_state(AimSimulationState& s) +{ + constexpr double twoPi = 6.28318530717958647692; + std::uniform_real_distribution phaseDist(0.0, twoPi); + std::uniform_real_distribution rateDist(0.04, 0.16); + + s.windCarryX = 0.0; + s.windCarryY = 0.0; + s.windVelX = 0.0; + s.windVelY = 0.0; + s.windNoiseX = 0.0; + s.windNoiseY = 0.0; + s.windFracX = 0.0; + s.windFracY = 0.0; + s.windPatternX = 0.0; + s.windPatternY = 0.0; + s.windPatternPhaseA = phaseDist(s.windRng); + s.windPatternPhaseB = phaseDist(s.windRng); + s.windPatternRateA = rateDist(s.windRng); + s.windPatternRateB = rateDist(s.windRng); +} + +static void aim_sim_sync_wind_config(AimSimulationState& s) +{ + const bool windEnabled = config.wind_mouse_enabled; + const double windG = static_cast(config.wind_G); + const double windW = static_cast(config.wind_W); + const double windM = static_cast(config.wind_M); + const double windD = static_cast(config.wind_D); + + const bool changed = + (s.windEnabledSnapshot != windEnabled) || + (std::abs(s.windGSnapshot - windG) > 1e-6) || + (std::abs(s.windWSnapshot - windW) > 1e-6) || + (std::abs(s.windMSnapshot - windM) > 1e-6) || + (std::abs(s.windDSnapshot - windD) > 1e-6); + + if (!changed) + return; + + aim_sim_reset_wind_state(s); + s.windEnabledSnapshot = windEnabled; + s.windGSnapshot = windG; + s.windWSnapshot = windW; + s.windMSnapshot = windM; + s.windDSnapshot = windD; +} + +static void aim_sim_choose_target_motion(AimSimulationState& s) +{ + const double stopChance = std::clamp(static_cast(config.aim_sim_target_stop_chance), 0.0, 0.95); + const double maxSpeed = std::max(20.0, static_cast(config.aim_sim_target_max_speed)); + + if (aim_sim_random_range(s, 0.0, 1.0) < stopChance) + { + s.targetDesiredVel = { 0.0, 0.0 }; + s.targetMotionRetargetSec = aim_sim_random_range(s, 0.25, 0.95); + return; + } + + const double angle = aim_sim_random_range(s, 0.0, 2.0 * 3.14159265358979323846); + const double speed = aim_sim_random_range(s, maxSpeed * 0.25, maxSpeed); + s.targetDesiredVel = { std::cos(angle) * speed, std::sin(angle) * speed }; + s.targetMotionRetargetSec = aim_sim_random_range(s, 0.35, 1.35); +} + +static void aim_sim_reset(AimSimulationState& s, int panelW, int panelH) +{ + s.initialized = true; + s.controllerInitialized = false; + s.panelW = panelW; + s.panelH = panelH; + + s.simTimeSec = 0.0; + s.accumulatorSec = 0.0; + s.currentFps = std::clamp((config.aim_sim_fps_min + config.aim_sim_fps_max) * 0.5, 15.0, 360.0); + s.targetFps = s.currentFps; + s.fpsRetargetSec = 0.0; + s.targetMotionRetargetSec = 0.0; + s.lastFrameDtSec = 1.0 / std::max(15.0, s.currentFps); + + s.targetPos = { panelW * 0.72, panelH * 0.38 }; + s.targetVel = { 0.0, 0.0 }; + s.targetDesiredVel = { 0.0, 0.0 }; + s.aimPos = { panelW * 0.50, panelH * 0.50 }; + s.observedTarget = s.targetPos; + s.predictedTarget = s.targetPos; + + s.usedCaptureDelayMs = 0.0; + s.usedInferenceDelayMs = 0.0; + s.usedInputDelayMs = 0.0; + s.usedExtraDelayMs = 0.0; + s.usedTotalDelayMs = 0.0; + s.lastErrorPx = 0.0; + s.lastMoveX = 0; + s.lastMoveY = 0; + + s.ctrlPrevX = 0.0; + s.ctrlPrevY = 0.0; + s.ctrlPrevVelocityX = 0.0; + s.ctrlPrevVelocityY = 0.0; + s.ctrlPrevTimeSec = 0.0; + + aim_sim_reset_wind_state(s); + s.windEnabledSnapshot = config.wind_mouse_enabled; + s.windGSnapshot = static_cast(config.wind_G); + s.windWSnapshot = static_cast(config.wind_W); + s.windMSnapshot = static_cast(config.wind_M); + s.windDSnapshot = static_cast(config.wind_D); + + s.history.clear(); + s.queuedMoves.clear(); + s.targetTrail.clear(); + s.aimTrail.clear(); + + s.lastWallTime = std::chrono::steady_clock::now(); + aim_sim_choose_target_motion(s); +} + +static double aim_sim_get_live_inference_ms() +{ + double delayMs = static_cast(config.aim_sim_inference_delay_ms); + + if (config.backend == "DML") + { + if (dml_detector) + delayMs = dml_detector->lastInferenceTimeDML.count(); + } +#ifdef USE_CUDA + else + { + delayMs = trt_detector.lastInferenceTime.count(); + } +#endif + if (!std::isfinite(delayMs)) + delayMs = static_cast(config.aim_sim_inference_delay_ms); + + return std::clamp(delayMs, 0.0, 120.0); +} + +static AimSimHistorySample aim_sim_sample_history(const std::deque& history, double sampleTime) +{ + if (history.empty()) + return {}; + + if (sampleTime <= history.front().timeSec) + return history.front(); + if (sampleTime >= history.back().timeSec) + return history.back(); + + for (size_t i = 1; i < history.size(); ++i) + { + const auto& b = history[i]; + if (b.timeSec < sampleTime) + continue; + + const auto& a = history[i - 1]; + const double dt = std::max(1e-6, b.timeSec - a.timeSec); + const double t = std::clamp((sampleTime - a.timeSec) / dt, 0.0, 1.0); + + AimSimHistorySample out; + out.timeSec = sampleTime; + out.target.x = a.target.x + (b.target.x - a.target.x) * t; + out.target.y = a.target.y + (b.target.y - a.target.y) * t; + out.aim.x = a.aim.x + (b.aim.x - a.aim.x) * t; + out.aim.y = a.aim.y + (b.aim.y - a.aim.y) * t; + return out; + } + + return history.back(); +} + +static double aim_sim_calculate_speed_multiplier(double distance, double maxDistance) +{ + const double snapRadius = std::max(0.0, static_cast(config.snapRadius)); + const double nearRadius = std::max(1e-3, static_cast(config.nearRadius)); + const double curveExp = std::max(0.1, static_cast(config.speedCurveExponent)); + const double minSpeed = static_cast(config.minSpeedMultiplier); + const double maxSpeed = static_cast(config.maxSpeedMultiplier); + + if (distance < snapRadius) + return minSpeed * config.snapBoostFactor; + + if (distance < nearRadius) + { + const double t = distance / nearRadius; + const double curve = 1.0 - std::pow(1.0 - t, curveExp); + return minSpeed + (maxSpeed - minSpeed) * curve; + } + + const double norm = std::clamp(distance / std::max(1e-6, maxDistance), 0.0, 1.0); + return minSpeed + (maxSpeed - minSpeed) * norm; +} + +static void aim_sim_enqueue_move(AimSimulationState& s, double executeAtSec, int mx, int my) +{ + if (mx == 0 && my == 0) + return; + + if (!s.queuedMoves.empty()) + { + AimSimQueuedMove& back = s.queuedMoves.back(); + if (std::abs(back.executeAtSec - executeAtSec) <= 1e-6) + { + back.mx += mx; + back.my += my; + return; + } + } + + const double inputDelayMs = std::clamp(static_cast(config.aim_sim_input_delay_ms), 0.0, 60.0); + const double maxFps = std::clamp( + static_cast(std::max(config.aim_sim_fps_min, config.aim_sim_fps_max)), + 15.0, 360.0); + const double minFrameMs = 1000.0 / std::max(1.0, maxFps); + const double delayedFrames = inputDelayMs / std::max(0.1, minFrameMs); + const double stepsPerFrame = config.wind_mouse_enabled ? 5.0 : 1.0; + const int needed = static_cast(std::ceil((delayedFrames + 2.0) * stepsPerFrame)); + const size_t queueLimit = static_cast(std::clamp(needed, 32, 256)); + + if (s.queuedMoves.size() >= queueLimit) + s.queuedMoves.pop_front(); + + s.queuedMoves.push_back({ executeAtSec, mx, my }); +} + +static void aim_sim_enqueue_relative_path(AimSimulationState& s, double executeAtSec, int dx, int dy) +{ + if (dx == 0 && dy == 0) + return; + + if (!config.wind_mouse_enabled) + { + aim_sim_enqueue_move(s, executeAtSec, dx, dy); + return; + } + + s.windCarryX += static_cast(dx); + s.windCarryY += static_cast(dy); + + const double baseG = std::clamp(static_cast(config.wind_G), 0.05, 50.0); + const double baseW = std::clamp(static_cast(config.wind_W), 0.0, 80.0); + const double baseM = std::max(1.0, static_cast(config.wind_M)); + const double baseD = std::max(1.0, static_cast(config.wind_D)); + + std::uniform_real_distribution noiseDist(-1.0, 1.0); + std::uniform_real_distribution clipDist(0.55, 1.0); + constexpr double twoPi = 6.28318530717958647692; + + const double carryMag = std::hypot(s.windCarryX, s.windCarryY); + const int maxSubsteps = std::clamp(static_cast(carryMag * 0.24) + 1, 1, 5); + + for (int i = 0; i < maxSubsteps; ++i) + { + const double dist = std::hypot(s.windCarryX, s.windCarryY); + const double velMag = std::hypot(s.windVelX, s.windVelY); + if (dist < 0.20 && velMag < 0.12) + break; + + const double normDist = std::clamp(dist / baseD, 0.0, 1.0); + const double pullGain = baseG * (0.25 + 0.75 * normDist); + const double noiseAmp = baseW * (0.15 + 0.85 * normDist); + + double pullX = 0.0; + double pullY = 0.0; + if (dist > 1e-8) + { + pullX = s.windCarryX / dist * pullGain; + pullY = s.windCarryY / dist * pullGain; + } + + s.windPatternRateA = std::clamp(s.windPatternRateA + noiseDist(s.windRng) * 0.004, 0.025, 0.280); + s.windPatternRateB = std::clamp(s.windPatternRateB + noiseDist(s.windRng) * 0.004, 0.025, 0.280); + + const double stepTempo = 0.20 + 0.95 * normDist; + s.windPatternPhaseA += s.windPatternRateA * stepTempo; + s.windPatternPhaseB += s.windPatternRateB * stepTempo; + if (s.windPatternPhaseA > twoPi) s.windPatternPhaseA = std::fmod(s.windPatternPhaseA, twoPi); + if (s.windPatternPhaseB > twoPi) s.windPatternPhaseB = std::fmod(s.windPatternPhaseB, twoPi); + + const double oscAX = std::sin(s.windPatternPhaseA); + const double oscBX = std::sin(s.windPatternPhaseB + 1.61803398875); + const double oscAY = std::cos(s.windPatternPhaseA * 0.79 + 0.35); + const double oscBY = std::cos(s.windPatternPhaseB * 1.17 - 0.48); + + const double patternAmp = baseW * (0.05 + 0.55 * normDist); + const double patternTargetX = (oscAX + 0.58 * oscBX) * patternAmp; + const double patternTargetY = (oscAY + 0.58 * oscBY) * patternAmp; + const double patternBlend = 0.12 + 0.20 * normDist; + s.windPatternX = s.windPatternX * (1.0 - patternBlend) + patternTargetX * patternBlend; + s.windPatternY = s.windPatternY * (1.0 - patternBlend) + patternTargetY * patternBlend; + + s.windNoiseX = s.windNoiseX * 0.72 + noiseDist(s.windRng) * noiseAmp * 0.28; + s.windNoiseY = s.windNoiseY * 0.72 + noiseDist(s.windRng) * noiseAmp * 0.28; + + const double windForceX = s.windNoiseX + s.windPatternX * 0.42; + const double windForceY = s.windNoiseY + s.windPatternY * 0.42; + + const double drag = 0.82 + (1.0 - normDist) * 0.10; + s.windVelX = s.windVelX * drag + pullX + windForceX; + s.windVelY = s.windVelY * drag + pullY + windForceY; + + const double vCap = std::max(0.65, baseM * (0.30 + 0.70 * normDist)); + const double newVelMag = std::hypot(s.windVelX, s.windVelY); + if (newVelMag > vCap) + { + const double clip = vCap * clipDist(s.windRng); + s.windVelX = (s.windVelX / newVelMag) * clip; + s.windVelY = (s.windVelY / newVelMag) * clip; + } + + s.windFracX += s.windVelX; + s.windFracY += s.windVelY; + + const int stepX = static_cast(std::round(s.windFracX)); + const int stepY = static_cast(std::round(s.windFracY)); + if (stepX == 0 && stepY == 0) + continue; + + s.windFracX -= static_cast(stepX); + s.windFracY -= static_cast(stepY); + s.windCarryX -= static_cast(stepX); + s.windCarryY -= static_cast(stepY); + aim_sim_enqueue_move(s, executeAtSec, stepX, stepY); + } + + const double carryCap = 120.0; + const double finalCarryMag = std::hypot(s.windCarryX, s.windCarryY); + if (finalCarryMag > carryCap) + { + const double scale = carryCap / finalCarryMag; + s.windCarryX *= scale; + s.windCarryY *= scale; + } +} + +static AimSimVec2 aim_sim_counts_to_world_delta(int mx, int my, int detRes, double scaleToCtrlX, double scaleToCtrlY) +{ + if (detRes <= 0 || scaleToCtrlX <= 1e-8 || scaleToCtrlY <= 1e-8) + return {}; + + const Config::GameProfile* gpPtr = nullptr; + auto activeIt = config.game_profiles.find(config.active_game); + if (activeIt != config.game_profiles.end()) + gpPtr = &activeIt->second; + else + { + auto unifiedIt = config.game_profiles.find("UNIFIED"); + if (unifiedIt != config.game_profiles.end()) + gpPtr = &unifiedIt->second; + } + if (!gpPtr) + return {}; + const auto& gp = *gpPtr; + + if (gp.sens == 0.0 || gp.yaw == 0.0 || gp.pitch == 0.0) + return {}; + + const double fovNow = std::max(1.0, static_cast(config.fovX)); + const double fovScale = (gp.fovScaled && gp.baseFOV > 1.0) ? (fovNow / gp.baseFOV) : 1.0; + const double degX = static_cast(mx) * gp.sens * gp.yaw * fovScale; + const double degY = static_cast(my) * gp.sens * gp.pitch * fovScale; + + const double degPerPxX = fovNow / static_cast(detRes); + const double degPerPxY = std::max(1e-6, static_cast(config.fovY) / static_cast(detRes)); + + const double controlPxX = degX / degPerPxX; + const double controlPxY = degY / degPerPxY; + + AimSimVec2 deltaWorld; + deltaWorld.x = controlPxX / scaleToCtrlX; + deltaWorld.y = controlPxY / scaleToCtrlY; + return deltaWorld; +} + +static double aim_sim_next_frame_dt(AimSimulationState& s) +{ + const double fpsMin = std::clamp(static_cast(std::min(config.aim_sim_fps_min, config.aim_sim_fps_max)), 15.0, 360.0); + const double fpsMax = std::clamp(static_cast(std::max(config.aim_sim_fps_min, config.aim_sim_fps_max)), 15.0, 360.0); + + s.fpsRetargetSec -= s.lastFrameDtSec; + if (s.fpsRetargetSec <= 0.0) + { + s.targetFps = aim_sim_random_range(s, fpsMin, fpsMax); + s.fpsRetargetSec = aim_sim_random_range(s, 0.12, 0.55); + } + + const double alpha = 1.0 - std::exp(-s.lastFrameDtSec * 5.0); + s.currentFps += (s.targetFps - s.currentFps) * alpha; + + const double range = std::max(0.0, fpsMax - fpsMin); + const double jitter = range * std::clamp(static_cast(config.aim_sim_fps_jitter), 0.0, 0.8); + const double instantFps = std::clamp( + s.currentFps + aim_sim_random_range(s, -jitter, jitter), + fpsMin, fpsMax + ); + + s.lastFrameDtSec = 1.0 / std::max(15.0, instantFps); + return s.lastFrameDtSec; +} + +static void aim_sim_step(AimSimulationState& s, double dtSec, int panelW, int panelH) +{ + s.simTimeSec += dtSec; + aim_sim_sync_wind_config(s); + + s.targetMotionRetargetSec -= dtSec; + if (s.targetMotionRetargetSec <= 0.0) + aim_sim_choose_target_motion(s); + + const double maxAccel = std::max(20.0, static_cast(config.aim_sim_target_accel)); + const double dvX = s.targetDesiredVel.x - s.targetVel.x; + const double dvY = s.targetDesiredVel.y - s.targetVel.y; + const double dvLen = std::hypot(dvX, dvY); + const double maxDv = maxAccel * dtSec; + if (dvLen > maxDv && dvLen > 1e-8) + { + const double k = maxDv / dvLen; + s.targetVel.x += dvX * k; + s.targetVel.y += dvY * k; + } + else + { + s.targetVel.x = s.targetDesiredVel.x; + s.targetVel.y = s.targetDesiredVel.y; + } + + if (aim_sim_vec_len(s.targetDesiredVel) < 1.0) + { + const double damp = std::exp(-dtSec * 2.8); + s.targetVel.x *= damp; + s.targetVel.y *= damp; + } + + s.targetPos.x += s.targetVel.x * dtSec; + s.targetPos.y += s.targetVel.y * dtSec; + + const double margin = 10.0; + const double maxX = std::max(margin, static_cast(panelW) - margin); + const double maxY = std::max(margin, static_cast(panelH) - margin); + + if (s.targetPos.x < margin) + { + s.targetPos.x = margin; + s.targetVel.x = std::abs(s.targetVel.x) * 0.65; + s.targetDesiredVel.x = std::abs(s.targetDesiredVel.x); + } + else if (s.targetPos.x > maxX) + { + s.targetPos.x = maxX; + s.targetVel.x = -std::abs(s.targetVel.x) * 0.65; + s.targetDesiredVel.x = -std::abs(s.targetDesiredVel.x); + } + + if (s.targetPos.y < margin) + { + s.targetPos.y = margin; + s.targetVel.y = std::abs(s.targetVel.y) * 0.65; + s.targetDesiredVel.y = std::abs(s.targetDesiredVel.y); + } + else if (s.targetPos.y > maxY) + { + s.targetPos.y = maxY; + s.targetVel.y = -std::abs(s.targetVel.y) * 0.65; + s.targetDesiredVel.y = -std::abs(s.targetDesiredVel.y); + } + + s.history.push_back({ s.simTimeSec, s.targetPos, s.aimPos }); + while (!s.history.empty() && (s.simTimeSec - s.history.front().timeSec) > 3.0) + s.history.pop_front(); + + const double captureMs = std::clamp(static_cast(config.aim_sim_capture_delay_ms), 0.0, 80.0); + const double inferenceMs = config.aim_sim_use_live_inference + ? aim_sim_get_live_inference_ms() + : std::clamp(static_cast(config.aim_sim_inference_delay_ms), 0.0, 120.0); + const double inputMs = std::clamp(static_cast(config.aim_sim_input_delay_ms), 0.0, 60.0); + const double extraMs = std::clamp(static_cast(config.aim_sim_extra_delay_ms), 0.0, 60.0); + const double totalObsMs = captureMs + inferenceMs + extraMs; + + s.usedCaptureDelayMs = captureMs; + s.usedInferenceDelayMs = inferenceMs; + s.usedInputDelayMs = inputMs; + s.usedExtraDelayMs = extraMs; + s.usedTotalDelayMs = totalObsMs + inputMs; + + const double sampleTime = s.simTimeSec - (totalObsMs * 0.001); + const AimSimHistorySample delayed = aim_sim_sample_history(s.history, sampleTime); + s.observedTarget = delayed.target; + + const int detRes = std::max(32, config.detection_resolution); + const double scaleToCtrlX = static_cast(detRes) / std::max(1, panelW); + const double scaleToCtrlY = static_cast(detRes) / std::max(1, panelH); + const double centerCtrlX = static_cast(detRes) * 0.5; + const double centerCtrlY = static_cast(detRes) * 0.5; + + const double observedCtrlX = centerCtrlX + (delayed.target.x - delayed.aim.x) * scaleToCtrlX; + const double observedCtrlY = centerCtrlY + (delayed.target.y - delayed.aim.y) * scaleToCtrlY; + + double predictedCtrlX = observedCtrlX; + double predictedCtrlY = observedCtrlY; + + if (!s.controllerInitialized) + { + s.controllerInitialized = true; + s.ctrlPrevX = observedCtrlX; + s.ctrlPrevY = observedCtrlY; + s.ctrlPrevVelocityX = 0.0; + s.ctrlPrevVelocityY = 0.0; + s.ctrlPrevTimeSec = s.simTimeSec; + } + else + { + const double obsDt = std::max(s.simTimeSec - s.ctrlPrevTimeSec, 1e-8); + const double vx = std::clamp((observedCtrlX - s.ctrlPrevX) / obsDt, -20000.0, 20000.0); + const double vy = std::clamp((observedCtrlY - s.ctrlPrevY) / obsDt, -20000.0, 20000.0); + + s.ctrlPrevX = observedCtrlX; + s.ctrlPrevY = observedCtrlY; + s.ctrlPrevVelocityX = vx; + s.ctrlPrevVelocityY = vy; + s.ctrlPrevTimeSec = s.simTimeSec; + + predictedCtrlX = observedCtrlX + vx * static_cast(config.predictionInterval) + vx * 0.002; + predictedCtrlY = observedCtrlY + vy * static_cast(config.predictionInterval) + vy * 0.002; + } + + if (!std::isfinite(predictedCtrlX)) + predictedCtrlX = observedCtrlX; + if (!std::isfinite(predictedCtrlY)) + predictedCtrlY = observedCtrlY; + + const double offsetX = predictedCtrlX - centerCtrlX; + const double offsetY = predictedCtrlY - centerCtrlY; + const double distancePx = std::hypot(offsetX, offsetY); + + s.lastMoveX = 0; + s.lastMoveY = 0; + + if (distancePx > 0.0) + { + const double degPerPxX = static_cast(config.fovX) / static_cast(detRes); + const double degPerPxY = static_cast(config.fovY) / static_cast(detRes); + const double maxDistanceCtrl = std::hypot(static_cast(detRes), static_cast(detRes)) * 0.5; + const double speed = aim_sim_calculate_speed_multiplier(distancePx, maxDistanceCtrl); + const auto countsPair = config.degToCounts(offsetX * degPerPxX, offsetY * degPerPxY, config.fovX); + + double corr = 1.0; + const double fps = 1.0 / std::max(1e-8, dtSec); + if (fps > 30.0) + corr = 30.0 / fps; + + const double moveX = countsPair.first * speed * corr; + const double moveY = countsPair.second * speed * corr; + + const int mx = static_cast(moveX); + const int my = static_cast(moveY); + aim_sim_enqueue_relative_path(s, s.simTimeSec + inputMs * 0.001, mx, my); + } + + while (!s.queuedMoves.empty() && s.queuedMoves.front().executeAtSec <= s.simTimeSec) + { + const AimSimQueuedMove m = s.queuedMoves.front(); + s.queuedMoves.pop_front(); + + const AimSimVec2 worldDelta = aim_sim_counts_to_world_delta(m.mx, m.my, detRes, scaleToCtrlX, scaleToCtrlY); + s.aimPos.x += worldDelta.x; + s.aimPos.y += worldDelta.y; + s.lastMoveX += m.mx; + s.lastMoveY += m.my; + } + + const double aimMargin = 6.0; + s.aimPos.x = std::clamp(s.aimPos.x, aimMargin, std::max(aimMargin, static_cast(panelW) - aimMargin)); + s.aimPos.y = std::clamp(s.aimPos.y, aimMargin, std::max(aimMargin, static_cast(panelH) - aimMargin)); + + s.predictedTarget.x = s.aimPos.x + (predictedCtrlX - centerCtrlX) / scaleToCtrlX; + s.predictedTarget.y = s.aimPos.y + (predictedCtrlY - centerCtrlY) / scaleToCtrlY; + s.predictedTarget.x = std::clamp(s.predictedTarget.x, 0.0, static_cast(panelW)); + s.predictedTarget.y = std::clamp(s.predictedTarget.y, 0.0, static_cast(panelH)); + s.lastErrorPx = std::hypot(s.targetPos.x - s.aimPos.x, s.targetPos.y - s.aimPos.y); + + if (config.aim_sim_show_history) + { + s.targetTrail.push_back(s.targetPos); + s.aimTrail.push_back(s.aimPos); + const size_t maxTrail = 160; + while (s.targetTrail.size() > maxTrail) s.targetTrail.pop_front(); + while (s.aimTrail.size() > maxTrail) s.aimTrail.pop_front(); + } + else + { + s.targetTrail.clear(); + s.aimTrail.clear(); + } +} + +static void draw_aim_sim_panel( + Game_overlay* overlay, + AimSimulationState& s, + int screenW, + int screenH, + int originX, + int originY) +{ + if (!overlay || !config.aim_sim_enabled) + return; + + const int panelW = std::clamp(config.aim_sim_width, 220, 1920); + const int panelH = std::clamp(config.aim_sim_height, 180, 1080); + int panelX = std::max(0, config.aim_sim_x); + int panelY = screenH - panelH - std::max(0, config.aim_sim_y); + + const int minX = -panelW + 20; + const int minY = -panelH + 20; + const int maxX = std::max(20, screenW - 20); + const int maxY = std::max(20, screenH - 20); + panelX = std::clamp(panelX, minX, maxX); + panelY = std::clamp(panelY, minY, maxY); + + if (!s.initialized || s.panelW != panelW || s.panelH != panelH) + aim_sim_reset(s, panelW, panelH); + + auto now = std::chrono::steady_clock::now(); + double dtReal = 1.0 / 120.0; + if (s.lastWallTime.time_since_epoch().count() != 0) + { + dtReal = std::chrono::duration(now - s.lastWallTime).count(); + dtReal = std::clamp(dtReal, 0.001, 0.08); + } + s.lastWallTime = now; + s.accumulatorSec = std::min(0.15, s.accumulatorSec + dtReal); + + int loops = 0; + while (loops < 20) + { + const double frameDt = aim_sim_next_frame_dt(s); + if (s.accumulatorSec < frameDt) + break; + aim_sim_step(s, frameDt, panelW, panelH); + s.accumulatorSec -= frameDt; + ++loops; + } + if (loops >= 20) + s.accumulatorSec = 0.0; + + const float fx = static_cast(originX + panelX); + const float fy = static_cast(originY + panelY); + const float fw = static_cast(panelW); + const float fh = static_cast(panelH); + + overlay->FillRect({ fx, fy, fw, fh }, ARGB(155, 12, 16, 20)); + overlay->AddRect({ fx, fy, fw, fh }, ARGB(230, 185, 190, 200), 1.5f); + + const float cx = fx + fw * 0.5f; + const float cy = fy + fh * 0.5f; + overlay->AddLine({ fx, cy, fx + fw, cy }, ARGB(90, 255, 255, 255), 1.0f); + overlay->AddLine({ cx, fy, cx, fy + fh }, ARGB(90, 255, 255, 255), 1.0f); + + if (config.aim_sim_show_history && s.targetTrail.size() > 1) + { + const size_t n = s.targetTrail.size(); + for (size_t i = 1; i < n; ++i) + { + const float alpha = static_cast(50 + (180 * i) / n); + const auto& p0 = s.targetTrail[i - 1]; + const auto& p1 = s.targetTrail[i]; + overlay->AddLine( + { fx + static_cast(p0.x), fy + static_cast(p0.y), + fx + static_cast(p1.x), fy + static_cast(p1.y) }, + ARGB(static_cast(alpha), 255, 120, 120), 1.2f); + } + } + + if (config.aim_sim_show_history && s.aimTrail.size() > 1) + { + const size_t n = s.aimTrail.size(); + for (size_t i = 1; i < n; ++i) + { + const float alpha = static_cast(50 + (180 * i) / n); + const auto& p0 = s.aimTrail[i - 1]; + const auto& p1 = s.aimTrail[i]; + overlay->AddLine( + { fx + static_cast(p0.x), fy + static_cast(p0.y), + fx + static_cast(p1.x), fy + static_cast(p1.y) }, + ARGB(static_cast(alpha), 120, 220, 255), 1.2f); + } + } + + if (config.aim_sim_show_observed) + { + overlay->FillCircle( + { fx + static_cast(s.observedTarget.x), fy + static_cast(s.observedTarget.y), 4.0f }, + ARGB(230, 255, 205, 90)); + } + + overlay->AddCircle( + { fx + static_cast(s.predictedTarget.x), fy + static_cast(s.predictedTarget.y), 6.0f }, + ARGB(210, 255, 245, 100), 1.5f); + overlay->FillCircle( + { fx + static_cast(s.targetPos.x), fy + static_cast(s.targetPos.y), 5.0f }, + ARGB(250, 255, 90, 90)); + overlay->FillCircle( + { fx + static_cast(s.aimPos.x), fy + static_cast(s.aimPos.y), 4.0f }, + ARGB(255, 80, 200, 255)); + overlay->AddCircle( + { fx + static_cast(s.aimPos.x), fy + static_cast(s.aimPos.y), 9.0f }, + ARGB(235, 80, 200, 255), 1.8f); + overlay->AddLine( + { fx + static_cast(s.aimPos.x), fy + static_cast(s.aimPos.y), + fx + static_cast(s.targetPos.x), fy + static_cast(s.targetPos.y) }, + ARGB(160, 255, 255, 255), 1.0f); + + const float tx = fx + 12.0f; + float ty = fy + 8.0f; + const float step = 21.0f; + overlay->AddText(tx, ty, L"Aim Simulation", 20.0f, ARGB(245, 230, 235, 245)); + ty += step; + + wchar_t line[256]{}; + const double simFps = 1.0 / std::max(1e-6, s.lastFrameDtSec); + swprintf_s(line, L"FPS %.1f (range %d..%d)", simFps, config.aim_sim_fps_min, config.aim_sim_fps_max); + overlay->AddText(tx, ty, line, 17.0f, ARGB(220, 210, 220, 230)); + ty += step; + + swprintf_s(line, L"Delay %.1f ms (cap %.1f + inf %.1f + in %.1f + extra %.1f)", + s.usedTotalDelayMs, s.usedCaptureDelayMs, s.usedInferenceDelayMs, s.usedInputDelayMs, s.usedExtraDelayMs); + overlay->AddText(tx, ty, line, 17.0f, ARGB(220, 210, 220, 230)); + ty += step; + + swprintf_s(line, L"Target speed %.0f px/s | Error %.1f px", aim_sim_vec_len(s.targetVel), s.lastErrorPx); + overlay->AddText(tx, ty, line, 17.0f, ARGB(220, 210, 220, 230)); + ty += step; + + swprintf_s(line, L"Move counts dx=%d dy=%d", s.lastMoveX, s.lastMoveY); + overlay->AddText(tx, ty, line, 17.0f, ARGB(220, 210, 220, 230)); +} + +void GameOverlayThreadFunction() +{ + AimSimulationState aimSimState; + std::vector stickyBoxes; + std::vector stickyClasses; + auto stickyUntil = std::chrono::steady_clock::time_point{}; + constexpr auto kBoxHoldTime = std::chrono::milliseconds(90); + + while (!shouldExit) + { + bool enabled = false; + int detRes = 320; + int monitorIdx = 0; + int maxFps = 0; + bool drawFrame = false; + bool drawBoxes = true; + bool drawFuture = true; + bool showCorrection = true; + bool showFpsCounter = true; + bool showLatency = true; + bool aimSimEnabled = false; + int fa = 180, fr = 255, fg = 255, fb = 255; + int ba = 255, br = 0, bg = 255, bb = 0; + float frameThickness = 1.5f; + float boxThickness = 2.0f; + float futurePointRadius = 5.0f; + float aimScope = 40.0f; + float snapRadius = 4.0f; + float nearRadius = 12.0f; + + { + std::lock_guard lock(configMutex); + enabled = config.game_overlay_enabled; + detRes = config.detection_resolution; + monitorIdx = config.monitor_idx; + maxFps = config.game_overlay_max_fps; + drawFrame = config.game_overlay_draw_frame; + drawBoxes = config.game_overlay_draw_boxes; + drawFuture = config.game_overlay_draw_future; + showCorrection = config.game_overlay_show_target_correction; + showFpsCounter = config.game_overlay_show_fps_counter; + showLatency = config.game_overlay_show_latency; + aimSimEnabled = config.aim_sim_enabled; + fa = config.game_overlay_frame_a; fr = config.game_overlay_frame_r; fg = config.game_overlay_frame_g; fb = config.game_overlay_frame_b; + ba = config.game_overlay_box_a; br = config.game_overlay_box_r; bg = config.game_overlay_box_g; bb = config.game_overlay_box_b; + frameThickness = config.game_overlay_frame_thickness; + boxThickness = config.game_overlay_box_thickness; + futurePointRadius = config.game_overlay_future_point_radius; + aimScope = std::max(4.0f, static_cast(config.aim_bot_scope)); + snapRadius = std::max(1.0f, static_cast(config.snapRadius)); + nearRadius = std::max(snapRadius + 1.0f, static_cast(config.nearRadius)); + } + + if (!enabled) + { + StopGameOverlay(); + std::this_thread::sleep_for(std::chrono::milliseconds(80)); + continue; + } + + if (!gameOverlayPtr) + { + gameOverlayPtr = new Game_overlay(); + if (!gameOverlayPtr->Start()) + { + delete gameOverlayPtr; + gameOverlayPtr = nullptr; + std::cerr << "[GameOverlay] Failed to start overlay window." << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + continue; + } + } + + gameOverlayPtr->SetMaxFPS(maxFps > 0 ? static_cast(maxFps) : 0u); + gameOverlayPtr->BeginFrame(); + + const RECT monRect = GetMonitorRectByIndexOrPrimary(monitorIdx); + const int monLeft = monRect.left; + const int monTop = monRect.top; + const int monW = static_cast(monRect.right - monRect.left); + const int monH = static_cast(monRect.bottom - monRect.top); + const int sw = std::max(1, monW); + const int sh = std::max(1, monH); + const float capW = static_cast(std::max(1, detRes)); + const float capH = static_cast(std::max(1, detRes)); + const float offX = static_cast(monLeft) + (static_cast(sw) - capW) * 0.5f; + const float offY = static_cast(monTop) + (static_cast(sh) - capH) * 0.5f; + + if (drawFrame) + { + gameOverlayPtr->AddRect({ offX, offY, capW, capH }, ARGB((uint8_t)fa, (uint8_t)fr, (uint8_t)fg, (uint8_t)fb), frameThickness); + } + + std::vector boxesCopy; + std::vector classesCopy; + { + std::lock_guard lk(detectionBuffer.mutex); + boxesCopy = detectionBuffer.boxes; + classesCopy = detectionBuffer.classes; + } + + const auto now = std::chrono::steady_clock::now(); + if (!boxesCopy.empty()) + { + stickyBoxes = boxesCopy; + stickyClasses = classesCopy; + stickyUntil = now + kBoxHoldTime; + } + else if (!stickyBoxes.empty() && now <= stickyUntil) + { + boxesCopy = stickyBoxes; + classesCopy = stickyClasses; + } + else + { + stickyBoxes.clear(); + stickyClasses.clear(); + } + + if (drawBoxes) + { + const OverlayColor fallbackCol = ARGB((uint8_t)ba, (uint8_t)br, (uint8_t)bg, (uint8_t)bb); + for (size_t i = 0; i < boxesCopy.size(); ++i) + { + const auto& b = boxesCopy[i]; + const int cls = (i < classesCopy.size()) ? classesCopy[i] : -1; + const OverlayColor classCol = (cls >= 0) ? GetClassOverlayColor(cls, static_cast(ba)) : fallbackCol; + gameOverlayPtr->AddRect( + { offX + static_cast(b.x), offY + static_cast(b.y), static_cast(b.width), static_cast(b.height) }, + classCol, + boxThickness); + } + } + + if (drawFuture && globalMouseThread) + { + const auto pts = globalMouseThread->getFuturePositions(); + for (const auto& p : pts) + { + gameOverlayPtr->FillCircle( + { offX + static_cast(p.first), offY + static_cast(p.second), futurePointRadius }, + ARGB(190, 120, 230, 120)); + } + } + + if (showCorrection) + { + const float cx = static_cast(monLeft) + static_cast(sw) * 0.5f; + const float cy = static_cast(monTop) + static_cast(sh) * 0.5f; + gameOverlayPtr->AddCircle({ cx, cy, aimScope }, ARGB(140, 80, 120, 255), 1.5f); + gameOverlayPtr->AddCircle({ cx, cy, snapRadius }, ARGB(190, 65, 245, 150), 1.25f); + gameOverlayPtr->AddCircle({ cx, cy, nearRadius }, ARGB(190, 255, 210, 70), 1.25f); + gameOverlayPtr->AddLine({ cx - 8.0f, cy, cx + 8.0f, cy }, ARGB(200, 255, 255, 255), 1.0f); + gameOverlayPtr->AddLine({ cx, cy - 8.0f, cx, cy + 8.0f }, ARGB(200, 255, 255, 255), 1.0f); + + wchar_t corrLine[128]; + swprintf_s(corrLine, L"scope %.0f | snap %.1f | near %.1f", aimScope, snapRadius, nearRadius); + gameOverlayPtr->AddText(cx + 12.0f, cy + 10.0f, corrLine, 16.0f, ARGB(220, 230, 235, 245)); + } + + if (showFpsCounter || showLatency) + { + float textY = static_cast(monTop) + 14.0f; + const float textX = static_cast(monLeft + sw) - 230.0f; + + if (showFpsCounter) + { + wchar_t fpsLine[64]; + swprintf_s(fpsLine, L"FPS: %d", captureFps.load()); + const float fpsTextSize = std::max(10.0f, OverlayUI::g_overlay_fps_text_size); + gameOverlayPtr->AddText(textX, textY, fpsLine, fpsTextSize, ARGB(235, 98, 238, 118)); + textY += fpsTextSize + 3.0f; + } + + if (showLatency) + { + const float latencyMs = std::max(0.0f, GetOverlayInferenceLatencyMs()); + wchar_t latLine[64]; + swprintf_s(latLine, L"Latency: %.2f ms", latencyMs); + const float latencyTextSize = std::max(10.0f, OverlayUI::g_overlay_latency_text_size); + gameOverlayPtr->AddText(textX, textY, latLine, latencyTextSize, ARGB(235, 110, 190, 255)); + } + } + + if (aimSimEnabled) + { + draw_aim_sim_panel(gameOverlayPtr, aimSimState, sw, sh, monLeft, monTop); + } + + gameOverlayPtr->EndFrame(); + std::this_thread::sleep_for(std::chrono::milliseconds(2)); + } + + StopGameOverlay(); +} +} + +namespace +{ +class TeeStreamBuf : public std::streambuf +{ +public: + TeeStreamBuf(std::streambuf* primary, std::streambuf* secondary) + : primary_(primary), secondary_(secondary) {} + +protected: + int overflow(int ch) override + { + if (ch == EOF) + return !EOF; + + std::lock_guard lock(mutex_); + const int p = primary_ ? primary_->sputc(static_cast(ch)) : ch; + const int s = secondary_ ? secondary_->sputc(static_cast(ch)) : ch; + return (p == EOF || s == EOF) ? EOF : ch; + } + + std::streamsize xsputn(const char* s, std::streamsize n) override + { + std::lock_guard lock(mutex_); + if (primary_) + primary_->sputn(s, n); + if (secondary_) + secondary_->sputn(s, n); + return n; + } + + int sync() override + { + std::lock_guard lock(mutex_); + int p = primary_ ? primary_->pubsync() : 0; + int s = secondary_ ? secondary_->pubsync() : 0; + return (p == 0 && s == 0) ? 0 : -1; + } + +private: + std::streambuf* primary_; + std::streambuf* secondary_; + std::mutex mutex_; +}; + +std::mutex g_console_log_mutex; +std::ofstream g_console_log_file; +std::unique_ptr g_cout_tee; +std::unique_ptr g_cerr_tee; +std::streambuf* g_orig_cout = nullptr; +std::streambuf* g_orig_cerr = nullptr; +bool g_console_file_logging_enabled = false; +const char* k_console_log_path = "runtime_console.log"; +} + +void SetConsoleFileLoggingEnabled(bool enabled, bool clear_on_enable) +{ + std::lock_guard lock(g_console_log_mutex); + + if (enabled) + { + if (g_console_file_logging_enabled) + return; + + std::ios::openmode mode = std::ios::out | std::ios::binary; + mode |= clear_on_enable ? std::ios::trunc : std::ios::app; + g_console_log_file.open(k_console_log_path, mode); + if (!g_console_log_file.is_open()) + return; + + g_orig_cout = std::cout.rdbuf(); + g_orig_cerr = std::cerr.rdbuf(); + g_cout_tee = std::make_unique(g_orig_cout, g_console_log_file.rdbuf()); + g_cerr_tee = std::make_unique(g_orig_cerr, g_console_log_file.rdbuf()); + std::cout.rdbuf(g_cout_tee.get()); + std::cerr.rdbuf(g_cerr_tee.get()); + g_console_file_logging_enabled = true; + return; + } + + if (!g_console_file_logging_enabled) + return; + + if (g_orig_cout) + std::cout.rdbuf(g_orig_cout); + if (g_orig_cerr) + std::cerr.rdbuf(g_orig_cerr); + + g_cout_tee.reset(); + g_cerr_tee.reset(); + if (g_console_log_file.is_open()) + g_console_log_file.close(); + + g_console_file_logging_enabled = false; +} + + +//ERRORS: '(': illegal token on right side of '::' +//'exists': identifier not found +//'exists' : identifier not found +//'exists' : is not a member of 'std::filesystem' +//'exists' : is not a member of 'std::filesystem' +//'modelPath' uses undefined class 'std::filesystem::path' +// namespace "std::filesystem" has no member "exists" +//namespace "std::filesystem" has no member "exists" +//syntax error : ')' +//use of undefined type 'std::filesystem::path' +void createInputDevices() +{ + if (arduinoSerial) + { + delete arduinoSerial; + arduinoSerial = nullptr; + } + + if (kmboxSerial) + { + delete kmboxSerial; + kmboxSerial = nullptr; + } + + if (makcu_conn) + { + delete makcu_conn; + makcu_conn = nullptr; + } + + if (kmboxNetSerial) + { + delete kmboxNetSerial; + kmboxNetSerial = nullptr; + } + + if (config.input_method == "ARDUINO") + { + std::cout << "[Mouse] Using Arduino method input." << std::endl; + arduinoSerial = new SerialConnection(config.arduino_port, config.arduino_baudrate); + } + else if (config.input_method == "KMBOX_B") + { + std::cout << "[Mouse] Using KMBOX_B method input." << std::endl; + kmboxSerial = new KmboxConnection(config.kmbox_b_port, config.kmbox_b_baudrate); + if (!kmboxSerial->isOpen()) + { + std::cerr << "[Kmbox] Error connecting to Kmbox serial." << std::endl; + delete kmboxSerial; + kmboxSerial = nullptr; + } + } + else if (config.input_method == "KMBOX_NET") + { + std::cout << "[Mouse] Using KMBOX_NET input." << std::endl; + kmboxNetSerial = new KmboxNetConnection(config.kmbox_net_ip, config.kmbox_net_port, config.kmbox_net_uuid); + if (!kmboxNetSerial->isOpen()) + { + std::cerr << "[KmboxNet] Error connecting." << std::endl; + delete kmboxNetSerial; kmboxNetSerial = nullptr; + } + } + else if (config.input_method == "MAKCU") + { + std::cout << "[Mouse] Using Makcu method input." << std::endl; + makcu_conn = new MakcuConnection(config.makcu_port, config.makcu_baudrate); + if (!makcu_conn->isOpen()) + { + std::cerr << "[Makcu] Error connecting to Makcu." << std::endl; + delete makcu_conn; + makcu_conn = nullptr; + } + } + else + { + std::cout << "[Mouse] Using default Win32 method input." << std::endl; + } +} + + +void assignInputDevices() +{ + if (globalMouseThread) + { + globalMouseThread->setSerialConnection(arduinoSerial); + globalMouseThread->setKmboxConnection(kmboxSerial); + globalMouseThread->setKmboxNetConnection(kmboxNetSerial); + globalMouseThread->setMakcuConnection(makcu_conn); + } +} + +void handleEasyNoRecoil(MouseThread& mouseThread) +{ + if (config.easynorecoil && shooting.load() && zooming.load()) + { + std::lock_guard lock(mouseThread.input_method_mutex); + int recoil_compensation = static_cast(config.easynorecoilstrength); + + if (makcu_conn) + { + makcu_conn->move(0, recoil_compensation); + } + else if (arduinoSerial) + { + arduinoSerial->move(0, recoil_compensation); + } + else if (kmboxSerial) + { + kmboxSerial->move(0, recoil_compensation); + } + else if (kmboxNetSerial) + { + kmboxNetSerial->move(0, recoil_compensation); + } + else + { + INPUT input = { 0 }; + input.type = INPUT_MOUSE; + input.mi.dx = 0; + input.mi.dy = recoil_compensation; + input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK; + SendInput(1, &input, sizeof(INPUT)); + } + } +} + +void mouseThreadFunction(MouseThread& mouseThread) +{ + int lastVersion = -1; + struct TargetCandidate + { + cv::Rect box; + int class_id{ -1 }; + double pivot_x{ 0.0 }; + double pivot_y{ 0.0 }; + double size{ 0.0 }; + double relative_size{ 0.0 }; + double distance_to_center{ 0.0 }; + double dx{ 0.0 }; + double dy{ 0.0 }; + uint64_t lock_id{ 0 }; + bool smoothed{ false }; + }; + + struct SmartTargetState + { + bool lock_active{ false }; + uint64_t lock_id{ 0 }; + cv::Point2d lock_center{ 0.0, 0.0 }; + std::chrono::steady_clock::time_point lock_lost_time{}; + int lock_class{ -1 }; + int last_target_count{ 0 }; + std::unordered_map last_target_count_by_class; + bool is_waiting_for_switch{ false }; + std::chrono::steady_clock::time_point target_switch_time{}; + }; + + struct TargetHistoryFrame + { + double x{ 0.0 }; + double y{ 0.0 }; + double size{ 0.0 }; + std::chrono::steady_clock::time_point time{}; + }; + + static SmartTargetState smart_state; + static std::unordered_map> target_history; + static std::mt19937 rng{ std::random_device{}() }; + + auto clear_lock_state = [&]() + { + smart_state.lock_active = false; + smart_state.lock_id = 0; + smart_state.lock_center = { 0.0, 0.0 }; + smart_state.lock_lost_time = std::chrono::steady_clock::time_point{}; + smart_state.lock_class = -1; + }; + + auto make_lock_id = [](const cv::Rect& box, int grid) -> uint64_t + { + int x1 = (box.x / grid) * grid; + int y1 = (box.y / grid) * grid; + int x2 = ((box.x + box.width) / grid) * grid; + int y2 = ((box.y + box.height) / grid) * grid; + + uint64_t id = 0; + id |= (static_cast(x1) & 0xFFFF); + id |= (static_cast(y1) & 0xFFFF) << 16; + id |= (static_cast(x2) & 0xFFFF) << 32; + id |= (static_cast(y2) & 0xFFFF) << 48; + return id; + }; + + auto get_box_center = [](const cv::Rect& box) -> cv::Point2d + { + return cv::Point2d(box.x + box.width * 0.5, box.y + box.height * 0.5); + }; + + auto parse_int_list = [](const std::string& text) -> std::vector + { + std::vector values; + std::string cleaned; + cleaned.reserve(text.size()); + for (char c : text) + { + if (std::isdigit(static_cast(c))) + cleaned.push_back(c); + else + cleaned.push_back(' '); + } + std::stringstream ss(cleaned); + int val = 0; + while (ss >> val) + values.push_back(val); + return values; + }; + + auto get_aim_position_for_class = [&](int class_id) -> double + { + double pos1 = config.aim_bot_position; + double pos2 = config.aim_bot_position2; + + auto it = config.class_aim_positions.find(class_id); + if (it != config.class_aim_positions.end()) + { + pos1 = it->second.first; + pos2 = it->second.second; + } + else if (config.class_aim_positions.empty()) + { + if (class_id == config.class_head) + { + pos1 = config.head_y_offset; + pos2 = config.head_y_offset; + } + else + { + pos1 = config.body_y_offset; + pos2 = config.body_y_offset; + } + } + + if (config.disable_headshot) + return std::max(pos1, pos2); + + if (pos1 > pos2) + std::swap(pos1, pos2); + std::uniform_real_distribution dist(pos1, pos2); + return dist(rng); + }; + + auto make_target_id = [&](const TargetCandidate& target) -> uint64_t + { + uint64_t x = static_cast(std::max(0, static_cast(std::round(target.pivot_x)))); + uint64_t y = static_cast(std::max(0, static_cast(std::round(target.pivot_y)))); + uint64_t cls = static_cast(std::max(0, target.class_id)); + return (cls << 48) ^ (x << 24) ^ y; + }; + + auto update_target_counts = [&](const std::vector& targets, int reference_class) + { + smart_state.last_target_count = static_cast(targets.size()); + int current_target_count = 0; + for (const auto& t : targets) + { + if (t.class_id == reference_class) + ++current_target_count; + } + smart_state.last_target_count_by_class[reference_class] = current_target_count; + }; + + auto update_lock = [&](const TargetCandidate& target) + { + smart_state.lock_active = true; + smart_state.lock_id = make_lock_id(target.box, 10); + smart_state.lock_center = get_box_center(target.box); + smart_state.lock_lost_time = std::chrono::steady_clock::time_point{}; + smart_state.lock_class = target.class_id; + }; + + auto apply_target_lock = [&](const std::vector& targets, + double lock_distance, + double reacquire_time, + int reference_class, + int fallback_class, + bool& lock_blocking) -> int + { + lock_blocking = false; + if (!smart_state.lock_active) + return -1; + + auto now = std::chrono::steady_clock::now(); + + if (targets.empty()) + { + if (smart_state.lock_lost_time.time_since_epoch().count() == 0) + smart_state.lock_lost_time = now; + double lost_for = std::chrono::duration(now - smart_state.lock_lost_time).count(); + if (lost_for >= reacquire_time) + { + clear_lock_state(); + return -1; + } + lock_blocking = true; + return -1; + } + + int locked_idx = -1; + for (size_t i = 0; i < targets.size(); ++i) + { + if (make_lock_id(targets[i].box, 10) == smart_state.lock_id) + { + locked_idx = static_cast(i); + break; + } + } + + if (locked_idx == -1) + { + double best_dist = std::numeric_limits::max(); + bool restrict_to_fallback = (fallback_class >= 0 && + reference_class >= 0 && + smart_state.lock_class == reference_class); + for (size_t i = 0; i < targets.size(); ++i) + { + if (restrict_to_fallback) + { + if (targets[i].class_id != fallback_class) + continue; + } + else if (smart_state.lock_class != -1 && targets[i].class_id != smart_state.lock_class) + { + continue; + } + cv::Point2d center = get_box_center(targets[i].box); + double dx = center.x - smart_state.lock_center.x; + double dy = center.y - smart_state.lock_center.y; + double dist = std::hypot(dx, dy); + if (dist < best_dist) + { + best_dist = dist; + locked_idx = static_cast(i); + } + } + + double reacquire_distance = std::max(10.0, std::min(lock_distance, lock_distance * 0.35)); + if (locked_idx != -1 && best_dist > reacquire_distance) + locked_idx = -1; + } + + if (locked_idx != -1) + { + update_lock(targets[locked_idx]); + return locked_idx; + } + + if (smart_state.lock_lost_time.time_since_epoch().count() == 0) + smart_state.lock_lost_time = now; + double lost_for = std::chrono::duration(now - smart_state.lock_lost_time).count(); + if (lost_for >= reacquire_time) + { + clear_lock_state(); + return -1; + } + lock_blocking = true; + return -1; + }; + + auto choose_with_weights = [&](const std::vector& candidates, + double aim_scope) -> TargetCandidate* + { + if (candidates.empty()) + return nullptr; + if (candidates.size() == 1) + return candidates[0]; + + double tiebreak_ratio = std::max(0.0, static_cast(config.aim_weight_tiebreak_ratio)); + double min_dist = std::numeric_limits::max(); + for (auto* t : candidates) + min_dist = std::min(min_dist, t->distance_to_center); + if (tiebreak_ratio <= 0.0) + { + return *std::min_element( + candidates.begin(), candidates.end(), + [](const TargetCandidate* a, const TargetCandidate* b) + { + return a->distance_to_center < b->distance_to_center; + }); + } + + double scope = aim_scope > 0.0 ? aim_scope : std::max(1.0, min_dist); + double threshold = scope * tiebreak_ratio; + std::vector near_candidates; + for (auto* t : candidates) + { + if (t->distance_to_center <= min_dist + threshold) + near_candidates.push_back(t); + } + if (near_candidates.size() == 1) + return near_candidates[0]; + + double w_dist = static_cast(config.distance_scoring_weight); + double w_center = static_cast(config.center_scoring_weight); + double w_size = static_cast(config.size_scoring_weight); + if (w_dist == 0.0 && w_center == 0.0 && w_size == 0.0) + { + return *std::min_element( + near_candidates.begin(), near_candidates.end(), + [](const TargetCandidate* a, const TargetCandidate* b) + { + return a->distance_to_center < b->distance_to_center; + }); + } + double max_dist = 1.0; + double max_center = 1.0; + double max_size = 1e-6; + for (auto* t : near_candidates) + { + max_dist = std::max(max_dist, t->distance_to_center); + max_center = std::max(max_center, std::abs(t->dx) + std::abs(t->dy)); + max_size = std::max(max_size, t->size); + } + + auto score = [&](const TargetCandidate* t) + { + double dist_norm = t->distance_to_center / max_dist; + double center_norm = (std::abs(t->dx) + std::abs(t->dy)) / max_center; + double size_norm = t->size / max_size; + return (w_dist * dist_norm) + + (w_center * center_norm) + + (w_size * (1.0 - size_norm)); + }; + + return *std::min_element( + near_candidates.begin(), near_candidates.end(), + [&](const TargetCandidate* a, const TargetCandidate* b) + { + return score(a) < score(b); + }); + }; + + while (!shouldExit) + { + std::vector boxes; + std::vector classes; + + { + std::unique_lock lock(detectionBuffer.mutex); + detectionBuffer.cv.wait(lock, [&] { + return detectionBuffer.version > lastVersion || shouldExit; + }); + if (shouldExit) break; + boxes = detectionBuffer.boxes; + classes = detectionBuffer.classes; + lastVersion = detectionBuffer.version; + } + + if (input_method_changed.load()) + { + createInputDevices(); + assignInputDevices(); + input_method_changed.store(false); + } + + if (detection_resolution_changed.load()) + { + { + std::lock_guard cfgLock(configMutex); + mouseThread.updateConfig( + config.detection_resolution, + config.fovX, + config.fovY, + config.minSpeedMultiplier, + config.maxSpeedMultiplier, + config.predictionInterval, + config.auto_shoot, + config.bScope_multiplier, + config.triggerbot_bScope_multiplier + ); + mouseThread.setUseSmoothing(config.use_smoothing); + mouseThread.setUseKalman(config.use_kalman); + mouseThread.setSmoothnessValue(config.smoothness); + } + detection_resolution_changed.store(false); + } + + // ????? ?????? + int screenCenterX = config.detection_resolution / 2; + int screenCenterY = config.detection_resolution / 2; + double max_distance = std::hypot( + static_cast(config.detection_resolution), + static_cast(config.detection_resolution)) / 2.0; + double aim_scope = config.aim_bot_scope > 0.0 ? config.aim_bot_scope : max_distance; + double base_scope = config.aim_bot_scope > 0.0 ? config.aim_bot_scope : aim_scope; + + auto allowed_list = parse_int_list(config.allowed_classes); + std::unordered_set allowed_set; + if (!allowed_list.empty()) + allowed_set.insert(allowed_list.begin(), allowed_list.end()); + auto priority_order = parse_int_list(config.class_priority_order); + + int reference_class = config.target_reference_class; + if (reference_class < 0) + reference_class = config.class_player; + int fallback_class = config.target_lock_fallback_class; + if (fallback_class < 0) + fallback_class = -1; + + auto is_valid_target_class = [&](int cls) + { + auto it_name = config.custom_class_names.find(cls); + if (it_name != config.custom_class_names.end() && it_name->second == "__deleted__") + return false; + if (config.disable_headshot && cls == config.class_head) + return false; + if (cls == config.class_third_person && config.ignore_third_person) + return false; + if ((cls == config.class_hideout_target_human || cls == config.class_hideout_target_balls) && + !config.shooting_range_targets) + return false; + if (allowed_set.empty()) + return false; + return allowed_set.find(cls) != allowed_set.end(); + }; + + double lock_distance = std::max(1.0, static_cast(config.target_lock_distance)); + if (!config.target_lock_enabled && config.focusTarget) + lock_distance = max_distance; + bool lock_enabled = (config.smart_target_lock || config.target_lock_enabled || config.focusTarget) && lock_distance > 0.0; + if (!lock_enabled || (!aiming.load() && !config.auto_aim)) + { + clear_lock_state(); + } + double reacquire_time = std::max(0.0, static_cast(config.target_lock_reacquire_time)); + + std::vector candidates; + candidates.reserve(boxes.size()); + for (size_t i = 0; i < boxes.size(); ++i) + { + if (i >= classes.size()) + break; + int cls = classes[i]; + if (!is_valid_target_class(cls)) + continue; + const cv::Rect& box = boxes[i]; + TargetCandidate cand; + cand.box = box; + cand.class_id = cls; + cand.lock_id = make_lock_id(box, 10); + double aim_pos = get_aim_position_for_class(cls); + cand.pivot_x = box.x + box.width * 0.5; + cand.pivot_y = box.y + box.height * aim_pos; + double area = static_cast(box.width) * static_cast(box.height); + double frame_area = static_cast(config.detection_resolution) * + static_cast(config.detection_resolution); + cand.relative_size = frame_area > 0.0 ? area / frame_area : 0.0; + double size_boost = 1.0; + if (config.small_target_enhancement_enabled) + { + if (cand.relative_size < config.small_target_threshold) + size_boost = config.small_target_boost_factor; + else if (cand.relative_size < config.small_target_medium_threshold) + size_boost = config.small_target_medium_boost; + } + cand.size = cand.relative_size * size_boost; + candidates.push_back(cand); + } + + if (config.small_target_enhancement_enabled && config.small_target_smooth_enabled && !candidates.empty()) + { + auto now = std::chrono::steady_clock::now(); + int max_frames = std::max(1, config.small_target_smooth_frames); + for (auto it = target_history.begin(); it != target_history.end();) + { + auto& frames = it->second; + while (!frames.empty()) + { + double age = std::chrono::duration(now - frames.front().time).count(); + if (age > 1.0) + frames.pop_front(); + else + break; + } + if (frames.empty()) + it = target_history.erase(it); + else + ++it; + } + + for (auto& cand : candidates) + { + if (cand.relative_size >= config.small_target_threshold) + continue; + uint64_t id = make_target_id(cand); + auto& frames = target_history[id]; + frames.push_back({ cand.pivot_x, cand.pivot_y, cand.size, now }); + if (static_cast(frames.size()) > max_frames) + frames.pop_front(); + if (frames.size() >= 2) + { + double sum_x = 0.0; + double sum_y = 0.0; + double sum_size = 0.0; + for (const auto& f : frames) + { + sum_x += f.x; + sum_y += f.y; + sum_size += f.size; + } + cand.pivot_x = sum_x / frames.size(); + cand.pivot_y = sum_y / frames.size(); + cand.size = sum_size / frames.size(); + cand.smoothed = true; + } + } + } + + bool lock_blocking = false; + int locked_idx = -1; + if (lock_enabled) + { + locked_idx = apply_target_lock(candidates, lock_distance, reacquire_time, reference_class, fallback_class, lock_blocking); + if (lock_blocking) + candidates.clear(); + else if (locked_idx >= 0 && locked_idx < static_cast(candidates.size())) + { + TargetCandidate locked = candidates[locked_idx]; + candidates.clear(); + candidates.push_back(locked); + } + } + else + { + clear_lock_state(); + } + + TargetCandidate* selected = nullptr; + if (!candidates.empty()) + { + if (lock_enabled && smart_state.lock_active && candidates.size() == 1) + { + update_target_counts(candidates, reference_class); + update_lock(candidates[0]); + selected = &candidates[0]; + } + else + { + std::vector valid_targets; + valid_targets.reserve(candidates.size()); + for (auto& t : candidates) + { + t.dx = t.pivot_x - screenCenterX; + t.dy = t.pivot_y - screenCenterY; + t.distance_to_center = std::hypot(t.dx, t.dy); + if (aim_scope <= 0.0 || t.distance_to_center <= aim_scope) + valid_targets.push_back(&t); + } + + if (!lock_enabled) + clear_lock_state(); + + if (!priority_order.empty()) + { + for (int class_id : priority_order) + { + std::vector class_candidates; + for (auto& t : candidates) + { + if (t.class_id != class_id) + continue; + if (base_scope > 0.0 && t.distance_to_center > base_scope) + continue; + class_candidates.push_back(&t); + } + if (!class_candidates.empty()) + { + selected = choose_with_weights(class_candidates, aim_scope); + if (selected && lock_enabled && lock_distance > 0.0) + update_lock(*selected); + else if (!lock_enabled) + clear_lock_state(); + break; + } + } + } + + if (!selected) + { + if (valid_targets.empty()) + { + if (!lock_enabled || !smart_state.lock_active) + { + clear_lock_state(); + if (smart_state.last_target_count > 0) + { + smart_state.last_target_count = 0; + smart_state.last_target_count_by_class.clear(); + } + } + } + else + { + int target_switch_delay = std::max(0, config.target_switch_delay); + int current_total_count = static_cast(valid_targets.size()); + int prev_total_count = smart_state.last_target_count; + int current_target_count = 0; + for (auto* t : valid_targets) + { + if (t->class_id == reference_class) + ++current_target_count; + } + + if (target_switch_delay > 0 && + !smart_state.is_waiting_for_switch && + prev_total_count > 1 && + current_total_count < prev_total_count) + { + smart_state.is_waiting_for_switch = true; + smart_state.target_switch_time = std::chrono::steady_clock::now(); + } + + if (smart_state.is_waiting_for_switch && current_total_count > prev_total_count) + smart_state.is_waiting_for_switch = false; + + if (smart_state.is_waiting_for_switch) + { + double elapsed_ms = std::chrono::duration( + std::chrono::steady_clock::now() - smart_state.target_switch_time).count(); + if (elapsed_ms >= target_switch_delay) + smart_state.is_waiting_for_switch = false; + else + { + selected = nullptr; + } + } + + if (!smart_state.is_waiting_for_switch) + { + smart_state.last_target_count_by_class[reference_class] = current_target_count; + smart_state.last_target_count = current_total_count; + + if (!priority_order.empty()) + { + std::unordered_map priority_map; + for (size_t idx = 0; idx < priority_order.size(); ++idx) + priority_map[priority_order[idx]] = static_cast(idx); + std::sort(valid_targets.begin(), valid_targets.end(), + [&](const TargetCandidate* a, const TargetCandidate* b) + { + int pa = priority_map.count(a->class_id) ? priority_map[a->class_id] : static_cast(priority_map.size()); + int pb = priority_map.count(b->class_id) ? priority_map[b->class_id] : static_cast(priority_map.size()); + if (pa != pb) + return pa < pb; + return a->distance_to_center < b->distance_to_center; + }); + } + else + { + std::sort(valid_targets.begin(), valid_targets.end(), + [](const TargetCandidate* a, const TargetCandidate* b) + { + return a->distance_to_center < b->distance_to_center; + }); + } + + selected = choose_with_weights(valid_targets, aim_scope); + if (selected && lock_enabled && lock_distance > 0.0) + update_lock(*selected); + else if (!lock_enabled) + clear_lock_state(); + } + } + } + } + } + else + { + if (!lock_blocking && (!lock_enabled || !smart_state.lock_active)) + { + clear_lock_state(); + if (smart_state.last_target_count > 0) + { + smart_state.last_target_count = 0; + smart_state.last_target_count_by_class.clear(); + } + } + } + + AimbotTarget* target = nullptr; + if (selected) + { + target = new AimbotTarget( + selected->box.x, + selected->box.y, + selected->box.width, + selected->box.height, + selected->class_id, + selected->pivot_x, + selected->pivot_y); + } + + if (target) + { + mouseThread.setLastTargetTime(std::chrono::steady_clock::now()); + mouseThread.setTargetDetected(true); + + auto futurePositions = mouseThread.predictFuturePositions( + target->pivotX, + target->pivotY, + config.prediction_futurePositions + ); + mouseThread.storeFuturePositions(futurePositions); + } + else + { + mouseThread.clearFuturePositions(); + mouseThread.setTargetDetected(false); + } + + bool shouldPressAuto = false; + bool shouldPressTrigger = false; + bool triggerbotActive = config.triggerbot && triggerbot_button.load(); + static auto lastTriggerShot = std::chrono::steady_clock::now() - std::chrono::milliseconds(500); + + bool triggerbotInScope = false; + if (target) + { + triggerbotInScope = mouseThread.check_target_in_scope( + target->x, + target->y, + target->w, + target->h, + config.triggerbot_bScope_multiplier); + } + + if (aiming && target) + { + mouseThread.moveMousePivot(target->pivotX, target->pivotY); + if (config.auto_shoot) + shouldPressAuto = true; + } + + if (triggerbotActive && triggerbotInScope) + { + auto now = std::chrono::steady_clock::now(); + int reaction_ms = std::max(0, config.triggerbot_reaction_ms); + if (reaction_ms <= 0 || now - lastTriggerShot >= std::chrono::milliseconds(reaction_ms)) + { + shouldPressTrigger = true; + lastTriggerShot = now; + } + } + + if (target && (shouldPressAuto || shouldPressTrigger)) + { + if (shouldPressTrigger) + mouseThread.pressMouse(*target, config.triggerbot_bScope_multiplier); + else + mouseThread.pressMouse(*target); + } + else + { + mouseThread.releaseMouse(); + } + + handleEasyNoRecoil(mouseThread); + mouseThread.checkAndResetPredictions(); + + delete target; + } +} + + +int main() +{ + try + { +#ifdef USE_CUDA + int cuda_devices = 0; + if (cudaGetDeviceCount(&cuda_devices) != cudaSuccess || cuda_devices == 0) + { + std::cerr << "[MAIN] CUDA required but no devices found." << std::endl; + std::cin.get(); + return -1; + } +#endif + + SetConsoleOutputCP(CP_UTF8); + cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_FATAL); + + if (!CreateDirectory(L"screenshots", NULL) && GetLastError() != ERROR_ALREADY_EXISTS) + { + std::cout << "[MAIN] Error with screenshoot folder" << std::endl; + std::cin.get(); + return -1; + } + + if (!CreateDirectory(L"models", NULL) && GetLastError() != ERROR_ALREADY_EXISTS) + { + std::cout << "[MAIN] Error with models folder" << std::endl; + std::cin.get(); + return -1; + } + + if (!config.loadConfig()) + { + std::cerr << "[Config] Error with loading config!" << std::endl; + std::cin.get(); + return -1; + } + + // Always start each run with a fresh console log file. + { + std::ofstream clear_log(k_console_log_path, std::ios::out | std::ios::trunc); + } + SetConsoleFileLoggingEnabled(config.verbose, false); + + if (config.capture_method == "virtual_camera") + { + auto cams = VirtualCameraCapture::GetAvailableVirtualCameras(); + if (!cams.empty()) + { + if (config.virtual_camera_name == "None" || + std::find(cams.begin(), cams.end(), config.virtual_camera_name) == cams.end()) + { + config.virtual_camera_name = cams[0]; + config.saveConfig("config.ini"); + std::cout << "[MAIN] Set virtual_camera_name = " << config.virtual_camera_name << std::endl; + } + std::cout << "[MAIN] Virtual cameras loaded: " << cams.size() << std::endl; + } + else + { + std::cerr << "[MAIN] No virtual cameras found" << std::endl; + } + } + + std::string modelPath = "models/" + config.ai_model; + + if (!std::filesystem::exists(modelPath)) + { + std::cerr << "[MAIN] Specified model does not exist: " << modelPath << std::endl; + + std::vector modelFiles = getModelFiles(); + + if (!modelFiles.empty()) + { + config.ai_model = modelFiles[0]; + config.saveConfig(); + std::cout << "[MAIN] Loaded first available model: " << config.ai_model << std::endl; + } + else + { + std::cerr << "[MAIN] No models found in 'models' directory." << std::endl; + std::cin.get(); + return -1; + } + } + + createInputDevices(); + + MouseThread mouseThread( + config.detection_resolution, + config.fovX, + config.fovY, + config.minSpeedMultiplier, + config.maxSpeedMultiplier, + config.predictionInterval, + config.auto_shoot, + config.bScope_multiplier, + config.triggerbot_bScope_multiplier, + arduinoSerial, + kmboxSerial, + kmboxNetSerial, + makcu_conn + ); + + mouseThread.setUseSmoothing(config.use_smoothing); + mouseThread.setSmoothnessValue(config.smoothness); + mouseThread.setUseKalman(config.use_kalman); + + globalMouseThread = &mouseThread; + assignInputDevices(); + + std::vector availableModels = getAvailableModels(); + + if (!config.ai_model.empty()) + { + std::string modelPath = "models/" + config.ai_model; + if (!std::filesystem::exists(modelPath)) + { + std::cerr << "[MAIN] Specified model does not exist: " << modelPath << std::endl; + + if (!availableModels.empty()) + { + config.ai_model = availableModels[0]; + config.saveConfig("config.ini"); + std::cout << "[MAIN] Loaded first available model: " << config.ai_model << std::endl; + } + else + { + std::cerr << "[MAIN] No models found in 'models' directory." << std::endl; + std::cin.get(); + return -1; + } + } + } + else + { + if (!availableModels.empty()) + { + config.ai_model = availableModels[0]; + config.saveConfig(); + std::cout << "[MAIN] No AI model specified in config. Loaded first available model: " << config.ai_model << std::endl; + } + else + { + std::cerr << "[MAIN] No AI models found in 'models' directory." << std::endl; + std::cin.get(); + return -1; + } + } + + std::thread dml_detThread; + + if (config.backend == "DML") + { + dml_detector = new DirectMLDetector("models/" + config.ai_model); + std::cout << "[MAIN] DML detector initialized." << std::endl; + dml_detThread = std::thread(&DirectMLDetector::dmlInferenceThread, dml_detector); + } + else if (config.backend == "COLOR") + { + color_detector = new ColorDetector(); + std::cout << "[Capture] backend=" << config.backend << std::endl; + color_detector->initializeFromConfig(config); + std::cout << "[MAIN] Color detector initialized." << std::endl; + color_detThread = std::thread(&ColorDetector::inferenceThread, color_detector); + } +#ifdef USE_CUDA + else + { + trt_detector.initialize("models/" + config.ai_model); + } +#endif + + detection_resolution_changed.store(true); + + std::thread keyThread(keyboardListener); + std::thread capThread(captureThread, config.detection_resolution, config.detection_resolution); + +#ifdef USE_CUDA + std::thread trt_detThread(&TrtDetector::inferenceThread, &trt_detector); +#endif + std::thread mouseMovThread(mouseThreadFunction, std::ref(mouseThread)); + std::thread overlayThread(OverlayThread); + std::thread gameOverlayThread(GameOverlayThreadFunction); + + welcome_message(); + + keyThread.join(); + capThread.join(); + if (dml_detThread.joinable()) + { + dml_detector->shouldExit = true; + dml_detector->inferenceCV.notify_all(); + dml_detThread.join(); + } + + if (color_detThread.joinable()) + { + color_detector->stop(); + color_detThread.join(); + delete color_detector; + color_detector = nullptr; + } + + +#ifdef USE_CUDA + trt_detThread.join(); +#endif + mouseMovThread.join(); + overlayThread.join(); + gameOverlayThread.join(); + + if (arduinoSerial) + { + delete arduinoSerial; + } + + if (makcu_conn) + { + delete makcu_conn; + makcu_conn = nullptr; + } + + if (dml_detector) + { + delete dml_detector; + dml_detector = nullptr; + } + + SetConsoleFileLoggingEnabled(false); + + return 0; + } + catch (const std::exception& e) + { + std::cerr << "[MAIN] An error has occurred in the main stream: " << e.what() << std::endl; + std::cout << "Press Enter to exit..."; + std::cin.get(); + return -1; + } +} diff --git a/sunone_aimbot_cpp/sunone_aimbot_cpp.h b/RN_AI_cpp/rn_ai_cpp.h similarity index 73% rename from sunone_aimbot_cpp/sunone_aimbot_cpp.h rename to RN_AI_cpp/rn_ai_cpp.h index 03ba1fcf..1ca8c4ee 100644 --- a/sunone_aimbot_cpp/sunone_aimbot_cpp.h +++ b/RN_AI_cpp/rn_ai_cpp.h @@ -1,5 +1,5 @@ -#ifndef SUNONE_AIMBOT_CPP_H -#define SUNONE_AIMBOT_CPP_H +#ifndef RN_AI_CPP_H +#define RN_AI_CPP_H #include @@ -26,13 +26,20 @@ extern MouseThread* globalMouseThread; extern SerialConnection* arduinoSerial; extern KmboxConnection* kmboxSerial; extern KmboxNetConnection* kmboxNetSerial; -extern MakcuConnection* makcu; +extern MakcuConnection* makcu_conn; extern ColorDetector* color_detector; +// Backward-compatible alias for legacy code paths that still reference `makcu`. +#ifndef makcu +#define makcu makcu_conn +#endif + extern std::atomic input_method_changed; extern std::atomic aiming; extern std::atomic shooting; extern std::atomic zooming; extern std::atomic triggerbot_button; -#endif // SUNONE_AIMBOT_CPP_H +void SetConsoleFileLoggingEnabled(bool enabled, bool clear_on_enable = false); + +#endif // RN_AI_CPP_H diff --git a/RN_AI_cpp/runtime_console.log b/RN_AI_cpp/runtime_console.log new file mode 100644 index 00000000..495c9018 --- /dev/null +++ b/RN_AI_cpp/runtime_console.log @@ -0,0 +1,23 @@ +[Mouse] Using default Win32 method input. +[Detector] Loading engine: models/sunxds_0.5.6.engine +[TensorRT] The engine was successfully loaded from the file: models/sunxds_0.5.6.engine +[Detector] Detected input: images +[Detector] Detected output: output0 +[Detector] Allocated 4915200 bytes for input images +[Detector] Allocated 7200 bytes for output output0 + + +Aimbot is started! +RightMouseButton -> Targeting +F2 -> Exit +F3 -> Pause Aiming +F4 -> Reload Config +Home -> Overlay (OPTIONS) +[Capture] OpenCV version: 4.10.0 +[Capture] Using Duplication API +[Detector] Loading engine: models/sunxds_0.5.6.engine +[TensorRT] The engine was successfully loaded from the file: models/sunxds_0.5.6.engine +[Detector] Detected input: images +[Detector] Detected output: output0 +[Detector] Allocated 4915200 bytes for input images +[Detector] Allocated 7200 bytes for output output0 diff --git a/sunone_aimbot_cpp/scr/other_tools.cpp b/RN_AI_cpp/scr/other_tools.cpp similarity index 99% rename from sunone_aimbot_cpp/scr/other_tools.cpp rename to RN_AI_cpp/scr/other_tools.cpp index 835f5b11..f4e55283 100644 --- a/sunone_aimbot_cpp/scr/other_tools.cpp +++ b/RN_AI_cpp/scr/other_tools.cpp @@ -26,7 +26,7 @@ #include "other_tools.h" #include "config.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" diff --git a/sunone_aimbot_cpp/tensorrt/nvinf.cpp b/RN_AI_cpp/tensorrt/nvinf.cpp similarity index 99% rename from sunone_aimbot_cpp/tensorrt/nvinf.cpp rename to RN_AI_cpp/tensorrt/nvinf.cpp index c02147bd..bcf7d4d6 100644 --- a/sunone_aimbot_cpp/tensorrt/nvinf.cpp +++ b/RN_AI_cpp/tensorrt/nvinf.cpp @@ -1,4 +1,4 @@ -#ifdef USE_CUDA +#ifdef USE_CUDA #define WIN32_LEAN_AND_MEAN #define _WINSOCKAPI_ #include @@ -10,7 +10,7 @@ #include #include "nvinf.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" #include "trt_monitor.h" Logger gLogger; diff --git a/sunone_aimbot_cpp/tensorrt/nvinf.h b/RN_AI_cpp/tensorrt/nvinf.h similarity index 95% rename from sunone_aimbot_cpp/tensorrt/nvinf.h rename to RN_AI_cpp/tensorrt/nvinf.h index b6c249bd..d975d638 100644 --- a/sunone_aimbot_cpp/tensorrt/nvinf.h +++ b/RN_AI_cpp/tensorrt/nvinf.h @@ -3,7 +3,7 @@ #define NVINF_H #include "NvInfer.h" -#include "sunone_aimbot_cpp.h" +#include "rn_ai_cpp.h" class Logger : public nvinfer1::ILogger { diff --git a/sunone_aimbot_cpp/tensorrt/trt_monitor.h b/RN_AI_cpp/tensorrt/trt_monitor.h similarity index 100% rename from sunone_aimbot_cpp/tensorrt/trt_monitor.h rename to RN_AI_cpp/tensorrt/trt_monitor.h diff --git a/RN_AI_cpp/ui_bg.png b/RN_AI_cpp/ui_bg.png new file mode 100644 index 00000000..fc67a6a9 Binary files /dev/null and b/RN_AI_cpp/ui_bg.png differ diff --git a/RN_AI_cpp/ui_theme.ini b/RN_AI_cpp/ui_theme.ini new file mode 100644 index 00000000..6d881b18 --- /dev/null +++ b/RN_AI_cpp/ui_theme.ini @@ -0,0 +1,37 @@ +# UI theme values. Colors: r,g,b,a (0..255 or 0..1) +alpha = 1 +window_rounding = 3 +frame_rounding = 2 +grab_rounding = 2 +scrollbar_rounding = 3 +item_spacing_x = 10.1 +item_spacing_y = 5 +frame_padding_x = 6.3 +frame_padding_y = 3 + +color_text = 234,234,242,255 +color_window_bg = 20,24,42,255 +color_title_bg = 40,41,45,255 +color_title_bg_active = 44,45,49,255 +color_frame_bg = 45,54,92,255 +color_frame_bg_hovered = 53,57,65,255 +color_frame_bg_active = 60,65,74,255 +color_button = 44,53,96,255 +color_button_hovered = 56,60,68,255 +color_button_active = 66,71,80,255 +color_header = 46,50,58,220 +color_header_hovered = 58,64,74,235 +color_header_active = 67,74,86,255 +color_border = 63,74,122,255 +color_tab = 34,40,69,255 +color_tab_hovered = 58,64,74,255 +color_tab_active = 74,93,159,255 +show_descriptions = 0 +row_button_width = 22 +row_input_width = 120 +nav_width = 147.23 +menu_bg_enabled = 1 +menu_bg_opacity = 0.62 +menu_bg_path = ui_bg.png +overlay_fps_text_size = 30 +overlay_latency_text_size = 30.3 diff --git a/docs/Build.md b/docs/Build.md new file mode 100644 index 00000000..828da91c --- /dev/null +++ b/docs/Build.md @@ -0,0 +1,235 @@ +# 🛠️ Build From Source (Advanced Users) + +If you want to compile the project yourself or modify code, follow these instructions. + +## 1. Requirements + +* **Visual Studio 2022 Community** ([Download](https://visualstudio.microsoft.com/vs/community/)) +* **Windows 10 or 11 (x64)** +* **Windows SDK 10.0.26100.0** or newer +* **CMake** ([Download](https://cmake.org/)) +* **OpenCV 4.10.0** +* **\[For CUDA version]** + + * [CUDA Toolkit 12.8](https://developer.nvidia.com/cuda-12-8-0-download-archive) + * [cuDNN 9.7.1](https://developer.nvidia.com/cudnn-downloads) + * [TensorRT 10.8.0.43](https://developer.nvidia.com/tensorrt/download/10x) +* **\[For DML version]** + + * You can use [pre-built OpenCV DLLs](https://github.com/opencv/opencv/releases/tag/4.10.0) (just copy `opencv_world4100.dll` to your exe folder) +* Other dependencies: + + * [simpleIni](https://github.com/brofield/simpleini/blob/master/SimpleIni.h) + * [serial](https://github.com/wjwwood/serial) + * [GLFW](https://www.glfw.org/download.html) + * [ImGui](https://github.com/ocornut/imgui) + +--- + +## 2. Choose Build Target in Visual Studio + +* **DML (DirectML):** + Select `Release | x64 | DML` (works on any modern GPU) +* **CUDA (TensorRT):** + Select `Release | x64 | CUDA` (requires supported NVIDIA GPU, see above) + +--- + +## 3. Placement of Third-Party Modules and Libraries + +Before building the project, **download and place all third-party dependencies** in the following directories inside your project structure: + +**Required folders inside your repository:** + +``` +rn_ai_cpp/ +└── rn_ai_cpp/ + └── modules/ +``` + +**Place each dependency as follows:** + +| Library | Path | +| --------- | ----------------------------------------------------------------- | +| SimpleIni | `rn_ai_cpp/rn_ai_cpp/modules/SimpleIni.h` | +| serial | `rn_ai_cpp/rn_ai_cpp/modules/serial/` | +| TensorRT | `rn_ai_cpp/rn_ai_cpp/modules/TensorRT-10.8.0.43/` | +| GLFW | `rn_ai_cpp/rn_ai_cpp/modules/glfw-3.4.bin.WIN64/` | +| OpenCV | `rn_ai_cpp/rn_ai_cpp/modules/opencv/` | +| cuDNN | `rn_ai_cpp/rn_ai_cpp/modules/cudnn/` | + +* **SimpleIni:** + Download [`SimpleIni.h`](https://github.com/brofield/simpleini/blob/master/SimpleIni.h) + Place in `modules/`. + +* **serial:** + Download the [`serial`](https://github.com/wjwwood/serial) library (whole folder). + To build, open + + ``` + rn_ai_cpp/rn_ai_cpp/modules/serial/visual_studio/visual_studio.sln + ``` + + * Set **C/C++ > Code Generation > Runtime Library** to **Multi-threaded (/MT)** + * Build in **Release x64** + * Use the built DLL/LIB with your project. + +* **TensorRT:** + Download [TensorRT 10.8.0.43](https://developer.nvidia.com/tensorrt/download/10x) + Place the folder as shown above. + +* **GLFW:** + Download [GLFW Windows binaries](https://www.glfw.org/download.html) + Place the folder as shown above. + +* **OpenCV:** + Use your custom build or official DLLs (see CUDA/DML notes below). + Place DLLs either next to your exe or in `modules/opencv/`. + +* **cuDNN:** + Place cuDNN files here (for CUDA build): + `rn_ai_cpp/rn_ai_cpp/modules/cudnn/` + +**Example structure after setup:** + +``` +rn_ai_cpp/ +└── rn_ai_cpp/ + └── modules/ + ├── SimpleIni.h + ├── serial/ + ├── TensorRT-10.8.0.43/ + ├── glfw-3.4.bin.WIN64/ + ├── opencv/ + └── cudnn/ +``` + +--- + +## 4. How to Build OpenCV 4.10.0 with CUDA Support (For CUDA Version Only) + +> This section is **only required** if you want to use the CUDA (TensorRT) version and need OpenCV with CUDA support. +> For DML build, skip this step — you can use the pre-built OpenCV DLL. + +**Step-by-step instructions:** + +1. **Download Sources** + + * [OpenCV 4.10.0](https://github.com/opencv/opencv/releases/tag/4.10.0) + * [OpenCV Contrib 4.10.0](https://github.com/opencv/opencv_contrib/releases/tag/4.10.0) + * [CMake](https://cmake.org/download/) + * [CUDA Toolkit 12.8](https://developer.nvidia.com/cuda-12-8-0-download-archive) + * [cuDNN 9.7.1](https://developer.nvidia.com/cudnn-downloads) + +2. **Prepare Directories** + + * Create: + `rn_ai_cpp/rn_ai_cpp/modules/opencv/` + `rn_ai_cpp/rn_ai_cpp/modules/opencv/build` + * Extract `opencv-4.10.0` into + `rn_ai_cpp/rn_ai_cpp/modules/opencv/opencv-4.10.0` + * Extract `opencv_contrib-4.10.0` into + `rn_ai_cpp/rn_ai_cpp/modules/opencv/opencv_contrib-4.10.0` + * Extract cuDNN to + `rn_ai_cpp/rn_ai_cpp/modules/cudnn` + +3. **Configure with CMake** + + * Open CMake GUI + * Source code: + `rn_ai_cpp/rn_ai_cpp/modules/opencv/opencv-4.10.0` + * Build directory: + `rn_ai_cpp/rn_ai_cpp/modules/opencv/build` + * Click **Configure** + (Choose "Visual Studio 17 2022", x64) + +4. **Enable CUDA Options** + + * After first configure, set the following: + + * `WITH_CUDA` = ON + * `WITH_CUBLAS` = ON + * `ENABLE_FAST_MATH` = ON + * `CUDA_FAST_MATH` = ON + * `WITH_CUDNN` = ON + * `CUDNN_LIBRARY` = + `full_path_to/rn_ai_cpp/rn_ai_cpp/modules/cudnn/lib/x64/cudnn.lib` + * `CUDNN_INCLUDE_DIR` = + `full_path_to/rn_ai_cpp/rn_ai_cpp/modules/cudnn/include` + * `CUDA_ARCH_BIN` = + See [CUDA Wikipedia](https://en.wikipedia.org/wiki/CUDA) for your GPU. + Example for RTX 3080-Ti: `8.6` + * `OPENCV_DNN_CUDA` = ON + * `OPENCV_EXTRA_MODULES_PATH` = + `full_path_to/rn_ai_cpp/rn_ai_cpp/modules/opencv/opencv_contrib-4.10.0/modules` + * `BUILD_opencv_world` = ON + * Uncheck: + + * `WITH_NVCUVENC` + * `WITH_NVCUVID` + * Click **Configure** again + (make sure nothing is reset) + * Click **Generate** + +5. **Build in Visual Studio** + + * Open `rn_ai_cpp/rn_ai_cpp/modules/opencv/build/OpenCV.sln` + or click "Open Project" in CMake + * Set build config: **x64 | Release** + * Build `ALL_BUILD` target (can take up to 2 hours) + * Then build `INSTALL` target + +6. **Copy Resulting DLLs** + + * DLLs: + `rn_ai_cpp/rn_ai_cpp/modules/opencv/build/install/x64/vc16/bin/` + * LIBs: + `rn_ai_cpp/rn_ai_cpp/modules/opencv/build/install/x64/vc16/lib/` + * Includes: + `rn_ai_cpp/rn_ai_cpp/modules/opencv/build/install/include/opencv2` + * Copy needed DLLs (`opencv_world4100.dll`, etc.) next to your project’s executable. + +--- + +## 5. Notes on OpenCV for CUDA/DML + +* **For CUDA build (TensorRT backend):** + + * You **must** build OpenCV with CUDA support (see the guide above). + * Place all built DLLs (e.g., `opencv_world4100.dll`) next to your executable or in the `modules` folder. +* **For DML build (DirectML backend):** + + * You can use the official pre-built OpenCV DLLs if you **only** plan to use DirectML. + * If you want to use both CUDA and DML modes in the same executable, you should always use your custom OpenCV build with CUDA enabled (it will work for both modes). +* **Note:** + If you run the CUDA backend with non-CUDA OpenCV DLLs, the program will not work and may crash due to missing symbols. + +--- + +## 6. Build and Run + +1. Open the solution in Visual Studio 2022. +2. Choose your configuration (`Release | x64 | DML` or `Release | x64 | CUDA`). +3. Build the solution. +4. Run `ai.exe` from the output folder. + +--- + +## 🔄 Exporting AI Models + +* Convert PyTorch `.pt` models to ONNX: + + ```bash + pip install ultralytics -U + yolo export model=sunxds_0.5.6.pt format=onnx dynamic=true simplify=true + ``` +* To convert `.onnx` to `.engine` for TensorRT, use the overlay export tab (open overlay with HOME). + +## 📋 Configuration + +* See all configuration options and documentation here: + [config\_cpp.md](https://github.com/SunOner/sunone_aimbot_docs/blob/main/config/config_cpp.md) + +--- + +## 📚 References & Useful Links \ No newline at end of file diff --git a/docs/config_en.md b/docs/config_en.md new file mode 100644 index 00000000..4f288638 --- /dev/null +++ b/docs/config_en.md @@ -0,0 +1,250 @@ +# Config Logic Guide (RN_AI) + +This document explains parameter behavior and runtime logic, not file structure. + +## 1) How Target Selection Works + +Pipeline: +1. Read detections from the current frame. +2. Apply class filters and user constraints. +3. Compute pivot (aim point) for each candidate. +4. If lock is enabled, try to keep the current target first. +5. Otherwise choose a new target using priority and weights. +6. Compute mouse movement for the selected target. + +--- + +## 2) Target: Core Flags + +`disable_headshot` +- Excludes `class_head` from target selection. + +`ignore_third_person` +- Ignores `class_third_person`. + +`auto_aim` +- Enables automatic aiming when the aim condition is active. + +`aim_bot_scope` +- Search radius around screen center, in pixels. + +--- + +## 3) Smart Target Lock + +`smart_target_lock` +- Keeps the current target across frames and reduces target hopping. + +`target_lock_distance` +- Maximum distance for lock keep/reacquire. + +`target_lock_reacquire_time` +- Time to wait after target loss before hard lock reset. + +`target_switch_delay` +- Debounce for switching to another target (ms), reduces jittery switching. + +--- + +## 4) Advanced Class Controls + +`target_reference_class` +- Base class used by lock logic. + +`target_lock_fallback_class` +- Backup class when reference class is lost (`-1` = disabled). + +`allowed_classes` +- Allow-list of classes. Classes outside are ignored. + +`class_priority_order` +- Hard class order. If set, selection starts from the first available class in this order. + +`class_aim_positions` +- Per-class vertical pivot range (`pos1..pos2`). + +`head -> body` example: +1. `class_head` is set to head class ID. +2. Head and body are both in `allowed_classes`. +3. `target_reference_class` = head (or head first in `class_priority_order`). +4. `target_lock_fallback_class` = body. + +Result: +- head visible: lock stays on head; +- head lost: lock tries to keep target via body; +- head returns: can switch back to head (with `target_switch_delay` applied). + +Important: +- if `disable_headshot=true`, head fallback/return cannot happen. + +--- + +## 5) Target Weights + +`distance_scoring_weight` +- Weight for distance to center. + +`center_scoring_weight` +- Extra center-bias weight. + +`size_scoring_weight` +- Bounding-box size weight. + +`aim_weight_tiebreak_ratio` +- Tie-break behavior for near-equal candidates. + +--- + +## 6) Mouse: Correction and Tracking + +`snapRadius` +- Inner fast-capture zone. + +`nearRadius` +- Transition zone for smoother movement. + +`minSpeed`, `maxSpeed`, `speedCurveExponent`, `snapBoostFactor` +- Define speed curve toward the target. + +`use_smoothing` +- Enables mouse movement smoothing. +- Recommended to keep enabled. + +`use_kalman` +- Enables Kalman in mouse movement loop. +- Usually works best with `use_smoothing=true`. + +`tracking_smoothing` +- Moving-target tracking mode. +- Makes tracking "stickier": faster catch-up with fewer sharp jumps. + +`kalman_process_noise` +- Movement-Kalman process noise. +- Higher value: faster response, more noise sensitivity. + +`kalman_measurement_noise` +- Movement-Kalman measurement noise. +- Higher value: stronger filtering, more inertia. + +`kalman_speed_multiplier_x`, `kalman_speed_multiplier_y` +- Per-axis post-Kalman movement multipliers. + +`camera_compensation_enabled` +- Enables camera-motion compensation in target velocity estimation. + +`camera_compensation_max_shift` +- Clamp for camera delta input. + +`camera_compensation_strength` +- Camera compensation strength. +- `0` almost off, `1` baseline compensation, `>1` stronger compensation. + +4K note: +- `aim_bot_scope`, `snapRadius`, `nearRadius` are pixel-based, so they are typically increased for 4K vs FHD. + +--- + +## 7) Prediction + Kalman + +Important: there are two different loops. +- Prediction-Kalman: predicts future target position. +- Movement-Kalman: smooths mouse movement (section 6). + +`prediction_mode` +- `0`: classic velocity. +- `1`: Kalman lead. +- `2`: Kalman + raw velocity (hybrid). + +`predictionInterval` +- Base lead horizon (seconds). + +`prediction_kalman_lead_ms` +- Extra lead in milliseconds. + +`prediction_kalman_max_lead_ms` +- Upper cap for lead. + +`prediction_velocity_smoothing` +- EMA smoothing for predicted velocity. + +`prediction_velocity_scale` +- Predicted velocity multiplier. + +`prediction_kalman_process_noise` (`Pred Kalman Q`) +- Prediction-Kalman process noise. + +`prediction_kalman_measurement_noise` (`Pred Kalman R`) +- Prediction-Kalman measurement noise. + +`prediction_use_future_for_aim` +- If enabled, aim uses the last point of future trajectory. + +`prediction_futurePositions` +- Number of future trajectory points. + +`draw_futurePositions` +- Draw future trajectory in debug. + +`game_overlay_draw_future` +- Draw future trajectory in game overlay. + +Noise summary: +- prediction: `prediction_kalman_process_noise`, `prediction_kalman_measurement_noise`. +- movement: `kalman_process_noise`, `kalman_measurement_noise`. + +--- + +## 8) AI: NMS and Small Targets + +`nms_threshold` +- Base NMS IoU threshold. + +`adaptive_nms` +- Enables adaptive NMS for small boxes. +- Logic: median detection area is computed; for small boxes, threshold is increased to `min(nms_threshold * 1.5, 0.8)`. + +`small_target_enhancement_enabled` +- Enables small-target boost in scoring. + +`small_target_threshold` +- Relative-size threshold for "small" targets. + +`small_target_boost_factor` +- Boost for very small targets. + +`small_target_medium_threshold` +- Threshold for "medium-small" targets. + +`small_target_medium_boost` +- Boost for medium-small targets. + +`small_target_smooth_enabled` +- Enables history-based smoothing of small target pivot/size. + +`small_target_smooth_frames` +- Number of history frames used for smoothing. + +--- + +## 9) Game Overlay + +`show fps counter` +- Shows FPS on game overlay. + +`show latency` +- Shows latency on game overlay. + +`overlay_fps_text_size`, `overlay_latency_text_size` +- Metrics text size. + +Box colors: +- class `0` is always green; +- other classes are auto-assigned from palette. + +--- + +## 10) Debug and Logs + +When file logging is enabled: +- log is cleared at the start of a new session; +- console events are written to runtime log. diff --git a/docs/config_ru.md b/docs/config_ru.md new file mode 100644 index 00000000..ecbd07bc --- /dev/null +++ b/docs/config_ru.md @@ -0,0 +1,250 @@ +# Config Logic Guide (RN_AI) + +Этот документ описывает логику параметров без привязки к файлам. + +## 1) Как выбирается цель + +Пайплайн: +1. Берутся детекции текущего кадра. +2. Применяются фильтры по классам и ограничениям. +3. Для кандидатов считается pivot (точка прицеливания). +4. Если включен lock, сначала удерживается текущая цель. +5. Иначе выбирается новая цель по приоритетам и весам. +6. Для выбранной цели считается движение мыши. + +--- + +## 2) Target: базовые флаги + +`disable_headshot` +- Исключает `class_head` из выбора. + +`ignore_third_person` +- Игнорирует `class_third_person`. + +`auto_aim` +- Разрешает автоматическую наводку при активном условии прицеливания. + +`aim_bot_scope` +- Радиус зоны поиска цели в пикселях от центра. + +--- + +## 3) Smart Target Lock + +`smart_target_lock` +- Удерживает текущую цель между кадрами, уменьшает перескоки. + +`target_lock_distance` +- Максимальная дистанция удержания/переискания lock. + +`target_lock_reacquire_time` +- Сколько ждать после потери lock-цели до полного сброса. + +`target_switch_delay` +- Debounce переключения на другую цель (мс), убирает дрожание выбора. + +--- + +## 4) Advanced Class Controls + +`target_reference_class` +- Базовый класс для lock-логики. + +`target_lock_fallback_class` +- Запасной класс при потере reference-класса (`-1` = выключено). + +`allowed_classes` +- Белый список классов. Вне списка цель не участвует. + +`class_priority_order` +- Жесткий порядок классов. Если задан, сначала выбирается первый доступный класс. + +`class_aim_positions` +- Для каждого класса задает вертикальный диапазон точки прицеливания (`pos1..pos2`). + +Пример `head -> body`: +1. `class_head` = ID головы. +2. Head и body есть в `allowed_classes`. +3. `target_reference_class` = head (или head первый в `class_priority_order`). +4. `target_lock_fallback_class` = body. + +Результат: +- head есть: lock держит head; +- head пропал: lock удерживается через body; +- head вернулся: возможен возврат на head с учетом `target_switch_delay`. + +Важно: +- при `disable_headshot=true` возврат на head не произойдет. + +--- + +## 5) Target Weights + +`distance_scoring_weight` +- Вес дистанции до центра. + +`center_scoring_weight` +- Дополнительный вес центральности. + +`size_scoring_weight` +- Вес размера бокса. + +`aim_weight_tiebreak_ratio` +- Развязка почти равных кандидатов. + +--- + +## 6) Mouse: коррекция и ведение + +`snapRadius` +- Внутренняя зона быстрого захвата. + +`nearRadius` +- Переходная зона для более мягкого движения. + +`minSpeed`, `maxSpeed`, `speedCurveExponent`, `snapBoostFactor` +- Формируют кривую скорости движения к цели. + +`use_smoothing` +- Включает сглаживание движения мыши. +- Рекомендуется держать включенным. + +`use_kalman` +- Включает Kalman в контуре движения мыши. +- Обычно хорошо работает в паре с `use_smoothing=true`. + +`tracking_smoothing` +- Режим сопровождения движущейся цели. +- Делает трекинг более "липким": быстрее догоняет цель без резких рывков. + +`kalman_process_noise` +- Шум процесса movement-Kalman. +- Больше значение: быстрее реакция, больше чувствительность к шуму. + +`kalman_measurement_noise` +- Шум измерения movement-Kalman. +- Больше значение: сильнее фильтрация, больше инерция. + +`kalman_speed_multiplier_x`, `kalman_speed_multiplier_y` +- Осевые множители движения после Kalman. + +`camera_compensation_enabled` +- Включает компенсацию движения камеры в оценке скорости цели. + +`camera_compensation_max_shift` +- Ограничение входного смещения камеры (clamp). + +`camera_compensation_strength` +- Сила компенсации камеры. +- `0` почти выключает эффект, `1` базовая компенсация, `>1` усиленная. + +Примечание для 4K: +- `aim_bot_scope`, `snapRadius`, `nearRadius` заданы в пикселях, на 4K их обычно увеличивают относительно FHD. + +--- + +## 7) Prediction + Kalman + +Важно: здесь два разных контура. +- Prediction-Kalman: прогноз будущей позиции цели. +- Movement-Kalman: сглаживание движения мыши (раздел 6). + +`prediction_mode` +- `0`: classic velocity. +- `1`: Kalman lead. +- `2`: Kalman + raw velocity (hybrid). + +`predictionInterval` +- Базовый горизонт упреждения (сек). + +`prediction_kalman_lead_ms` +- Дополнительный lead в миллисекундах. + +`prediction_kalman_max_lead_ms` +- Верхний лимит для lead. + +`prediction_velocity_smoothing` +- EMA-сглаживание предсказанной скорости. + +`prediction_velocity_scale` +- Множитель предсказанной скорости. + +`prediction_kalman_process_noise` (`Pred Kalman Q`) +- Шум процесса prediction-Kalman. + +`prediction_kalman_measurement_noise` (`Pred Kalman R`) +- Шум измерения prediction-Kalman. + +`prediction_use_future_for_aim` +- Если включено, аим использует последнюю точку future-траектории. + +`prediction_futurePositions` +- Количество точек future path. + +`draw_futurePositions` +- Рисовать future path в debug. + +`game_overlay_draw_future` +- Рисовать future path в game overlay. + +Итого по шумам: +- prediction: `prediction_kalman_process_noise`, `prediction_kalman_measurement_noise`. +- movement: `kalman_process_noise`, `kalman_measurement_noise`. + +--- + +## 8) AI: NMS и малые цели + +`nms_threshold` +- Базовый IoU-порог NMS. + +`adaptive_nms` +- Включает адаптивный NMS для маленьких боксов. +- Логика: считается медианная площадь детекций; для маленьких боксов порог повышается до `min(nms_threshold * 1.5, 0.8)`. + +`small_target_enhancement_enabled` +- Включает буст маленьких целей в scoring. + +`small_target_threshold` +- Порог относительного размера для "малой" цели. + +`small_target_boost_factor` +- Буст для очень маленьких целей. + +`small_target_medium_threshold` +- Порог для "средне-малых" целей. + +`small_target_medium_boost` +- Буст для средне-малых целей. + +`small_target_smooth_enabled` +- Включает сглаживание pivot/size маленьких целей по истории. + +`small_target_smooth_frames` +- Количество кадров истории для сглаживания. + +--- + +## 9) Game Overlay + +`show fps counter` +- Показывает FPS поверх игры. + +`show latency` +- Показывает latency поверх игры. + +`overlay_fps_text_size`, `overlay_latency_text_size` +- Размер текста метрик. + +Цвета боксов: +- класс `0` всегда зеленый; +- остальные классы получают цвет автоматически из палитры. + +--- + +## 10) Debug и логи + +При включенном логировании в файл: +- лог очищается при старте новой сессии; +- события из консоли пишутся в runtime лог. diff --git a/docs/demo.gif b/docs/demo.gif new file mode 100644 index 00000000..a027c55d Binary files /dev/null and b/docs/demo.gif differ diff --git a/docs/menu/status.jpg b/docs/menu/status.jpg new file mode 100644 index 00000000..ddf1d8eb Binary files /dev/null and b/docs/menu/status.jpg differ diff --git "a/docs/menu/\321\201apture.jpg" "b/docs/menu/\321\201apture.jpg" new file mode 100644 index 00000000..3ba7e207 Binary files /dev/null and "b/docs/menu/\321\201apture.jpg" differ diff --git a/docs/obs/gaming.jpg b/docs/obs/gaming.jpg new file mode 100644 index 00000000..e547ebc5 Binary files /dev/null and b/docs/obs/gaming.jpg differ diff --git a/docs/obs/obs_en.md b/docs/obs/obs_en.md new file mode 100644 index 00000000..c8c30b49 --- /dev/null +++ b/docs/obs/obs_en.md @@ -0,0 +1,23 @@ +# OBS Configuration + +**[🇷🇺 Русский](obs_ru.md)** + +## Gaming PC Setup + +Follow the instructions on the screenshot: + +Gaming PC Setup + +In the **file path or url** parameters, specify the IP address of the second PC where our bot is located. + +### Display Capture Area + +- Go to **Videos** +- Set **base resolution** to your screen size: **640x640** or **320x320** +- The choice depends on your model and preference + +## Main PC Setup + +Set the IP address as shown on the screenshot: + +Main PC Setup diff --git a/docs/obs/obs_ru.md b/docs/obs/obs_ru.md new file mode 100644 index 00000000..31028012 --- /dev/null +++ b/docs/obs/obs_ru.md @@ -0,0 +1,23 @@ +# Настройка OBS + +**[🇺🇸 English](obs_en.md)** + +## На игровом ПК + +Следуем инструкции на скрине: + +Настройка игрового ПК + +В параметрах **file path or url** указываем IP второго ПК, где находится наш бот. + +### Область захвата + +- Переходим в **Videos** +- **base resolution** устанавливаем под наш обзор: **640х640** или **320х320** +- Выбор зависит от вашей модели и удобства + +## На основном ПК + +Указываем IP как на скрине: + +Настройка основного ПК diff --git a/docs/obs/second.jpg b/docs/obs/second.jpg new file mode 100644 index 00000000..f6febdb7 Binary files /dev/null and b/docs/obs/second.jpg differ diff --git a/sunone_aimbot_cpp/ZTXAI/core/config.py b/sunone_aimbot_cpp/ZTXAI/core/config.py deleted file mode 100644 index 95a2f352..00000000 --- a/sunone_aimbot_cpp/ZTXAI/core/config.py +++ /dev/null @@ -1,578 +0,0 @@ -import json -import os -import random -import threading - -from .utils import TENSORRT_AVAILABLE - - -class ConfigMixin: - """Mixin class for configuration management.""" - - def save_config_callback(self): - """Async save configuration callback - saves to local cfg.json""" - - def _async_save_callback(): - try: - with open("cfg.json", "w", encoding="utf-8") as f: - json.dump(self.config, f, ensure_ascii=False, indent=2) - print("Configuration saved successfully") - return True - except Exception as e: - print(f"Configuration save callback exception: {e}") - return False - - save_thread = threading.Thread(target=_async_save_callback, daemon=True) - save_thread.start() - return True - - def build_config(self): - """ - Build configuration and return related parameters - - Process TRT related path settings and get current group's key configuration - - Returns: - tuple: (config, aim_keys_dist, aim_keys, group) config dict, key config dict, key list and current group name - """ - if hasattr(self, "config") and self.config: - config = self.config - else: - # Load from local cfg.json - config = None - if os.path.exists("cfg.json"): - try: - with open("cfg.json", "r", encoding="utf-8") as f: - config = json.load(f) - except Exception as e: - print(f"Failed to load cfg.json: {e}") - if config is None: - print("cfg.json not found or invalid, generating default configuration.") - config = self._create_default_config() - self.config = config - self.save_config_callback() - if config.get("move_method") != "makcu": - print("Only makcu move method is supported, forcing move_method to 'makcu'") - config["move_method"] = "makcu" - if "enable_parallel_processing" not in config: - config["enable_parallel_processing"] = True - if "turbo_mode" not in config: - config["turbo_mode"] = True - if "skip_frame_processing" not in config: - config["skip_frame_processing"] = True - if "performance_mode" not in config: - config["performance_mode"] = "balanced" - if "use_async_move" not in config: - config["use_async_move"] = False - if "frame_skip_ratio" not in config: - config["frame_skip_ratio"] = 0 - if "cpu_optimization" not in config: - config["cpu_optimization"] = True - if "memory_optimization" not in config: - config["memory_optimization"] = True - if "capture_offset_x" not in config: - config["capture_offset_x"] = 0 - if "capture_offset_y" not in config: - config["capture_offset_y"] = 0 - if "aim_controller" not in config: - config["aim_controller"] = "pid" - if "ui_language" not in config: - config["ui_language"] = "en" - if "gui_width_scale" not in config: - config["gui_width_scale"] = 1.0 - if "gui_font_scale" not in config: - config["gui_font_scale"] = 1.0 - if "small_target_enhancement" not in config: - config["small_target_enhancement"] = { - "enabled": True, - "boost_factor": 0.1, - "threshold": 0.02, - "medium_threshold": 0.05, - "medium_boost": 1.5, - "smooth_enabled": True, - "smooth_frames": 2, - "adaptive_nms": True, - } - if "class_names" not in config: - config["class_names"] = [] - if "class_names_file" not in config: - config["class_names_file"] = "" - if "sunone" not in config: - config["sunone"] = {} - sunone = config["sunone"] - if "use_smoothing" not in sunone: - sunone["use_smoothing"] = True - if "smoothness" not in sunone: - sunone["smoothness"] = 6 - if "tracking_smoothing" not in sunone: - sunone["tracking_smoothing"] = False - if "use_kalman" not in sunone: - sunone["use_kalman"] = False - if "kalman_process_noise" not in sunone: - sunone["kalman_process_noise"] = 0.01 - if "kalman_measurement_noise" not in sunone: - sunone["kalman_measurement_noise"] = 0.1 - if "kalman_speed_multiplier_x" not in sunone: - sunone["kalman_speed_multiplier_x"] = 1.0 - if "kalman_speed_multiplier_y" not in sunone: - sunone["kalman_speed_multiplier_y"] = 1.0 - if "reset_threshold" not in sunone: - sunone["reset_threshold"] = 4.0 - if "speed" not in sunone: - sunone["speed"] = {} - speed = sunone["speed"] - if "min_multiplier" not in speed: - speed["min_multiplier"] = 0.5 - if "max_multiplier" not in speed: - speed["max_multiplier"] = 0.7 - if "snap_radius" not in speed: - speed["snap_radius"] = 3.2 - if "near_radius" not in speed: - speed["near_radius"] = 40.0 - if "speed_curve_exponent" not in speed: - speed["speed_curve_exponent"] = 10.0 - if "snap_boost_factor" not in speed: - speed["snap_boost_factor"] = 4.0 - if "prediction" not in sunone: - sunone["prediction"] = {} - prediction = sunone["prediction"] - if "mode" not in prediction: - prediction["mode"] = 0 - if "interval" not in prediction: - prediction["interval"] = 0.01 - if "kalman_lead_ms" not in prediction: - prediction["kalman_lead_ms"] = 0.0 - if "kalman_max_lead_ms" not in prediction: - prediction["kalman_max_lead_ms"] = 0.0 - if "velocity_smoothing" not in prediction: - prediction["velocity_smoothing"] = 0.4 - if "velocity_scale" not in prediction: - prediction["velocity_scale"] = 1.0 - if "kalman_process_noise" not in prediction: - prediction["kalman_process_noise"] = 0.01 - if "kalman_measurement_noise" not in prediction: - prediction["kalman_measurement_noise"] = 0.1 - if "future_positions" not in prediction: - prediction["future_positions"] = 6 - if "draw_future_positions" not in prediction: - prediction["draw_future_positions"] = False - if "debug" not in sunone: - sunone["debug"] = {} - debug = sunone["debug"] - if "show_prediction" not in debug: - debug["show_prediction"] = False - if "show_step" not in debug: - debug["show_step"] = False - if "show_future" not in debug: - debug["show_future"] = False - if "sunone_max_detections" not in config: - config["sunone_max_detections"] = 0 - if "auto_flashbang" not in config: - config["auto_flashbang"] = { - "enabled": False, - "delay_ms": 150, - "turn_angle": 90, - "sensitivity_multiplier": 2.5, - "return_delay": 80, - "min_confidence": 0.3, - "min_size": 5, - "use_curve": True, - "curve_speed": 8.0, - "curve_knots": 3, - } - for group_key, group_val in config.get("groups", {}).items(): - if "disable_headshot" not in group_val: - group_val["disable_headshot"] = False - if "disable_headshot_keys" not in group_val: - group_val["disable_headshot_keys"] = ["m"] - if "disable_headshot_class_id" not in group_val: - group_val["disable_headshot_class_id"] = -1 - if "targeting_button_key" not in group_val: - default_target = "" - for key_name, key_cfg in group_val.get("aim_keys", {}).items(): - if not key_cfg.get("trigger_only", False): - default_target = key_name - break - if not default_target and group_val.get("aim_keys"): - default_target = next(iter(group_val["aim_keys"].keys())) - group_val["targeting_button_key"] = default_target - if "triggerbot_button_key" not in group_val: - default_trigger = "" - for key_name, key_cfg in group_val.get("aim_keys", {}).items(): - if key_cfg.get("trigger_only", False): - default_trigger = key_name - break - group_val["triggerbot_button_key"] = default_trigger - if "disable_headshot_button_key" not in group_val: - keys = group_val.get("disable_headshot_keys", []) - group_val["disable_headshot_button_key"] = keys[0] if keys else "m" - disable_key = group_val.get("disable_headshot_button_key", "") - group_val["disable_headshot_keys"] = [disable_key] if disable_key else [] - if "is_trt" not in group_val: - group_val["is_trt"] = False - if "yolo_format" not in group_val: - group_val["yolo_format"] = ( - "v8" if group_val.get("is_v8", False) else "auto" - ) - if "use_sunone_processing" not in group_val: - group_val["use_sunone_processing"] = False - if "sunone_model_variant" not in group_val: - group_val["sunone_model_variant"] = "yolo11" - if "infer_model" not in group_val: - continue - current_model = group_val["infer_model"] - if "original_infer_model" not in group_val: - if current_model.endswith(".engine"): - onnx_path = os.path.splitext(current_model)[0] + ".onnx" - if os.path.exists(onnx_path): - group_val["original_infer_model"] = onnx_path - elif current_model.endswith(".onnx"): - group_val["original_infer_model"] = current_model - if group_val.get("is_trt", False): - if not TENSORRT_AVAILABLE: - print( - f"Group {group_key} is set to use TRT, but TensorRT environment is unavailable, automatically switching to original mode" - ) - group_val["is_trt"] = False - original_path = group_val.get( - "original_infer_model", group_val["infer_model"] - ) - if original_path != group_val["infer_model"] and os.path.exists( - original_path - ): - group_val["infer_model"] = original_path - print( - f"Automatically switched back to ONNX mode: {original_path}" - ) - else: - original_path = group_val.get( - "original_infer_model", group_val["infer_model"] - ) - engine_path = os.path.splitext(original_path)[0] + ".engine" - if os.path.exists(engine_path): - group_val["infer_model"] = engine_path - else: - print(f"Warning: TRT engine file does not exist: {engine_path}") - if original_path != group_val["infer_model"] and os.path.exists( - original_path - ): - group_val["infer_model"] = original_path - else: - original_path = group_val.get( - "original_infer_model", group_val["infer_model"] - ) - if os.path.exists(original_path): - group_val["infer_model"] = original_path - group = config["group"] - if group and group in config["groups"]: - aim_keys_dist = config["groups"][group]["aim_keys"] - aim_keys = list(aim_keys_dist.keys()) - self.migrate_config_to_class_based(config) - self.init_all_keys_class_aim_positions(group, config) - else: - aim_keys_dist = {} - aim_keys = [] - return (config, aim_keys_dist, aim_keys, group) - - def _create_default_config(self): - class_names = [ - "player", - "bot", - "weapon", - "outline", - "dead_body", - "hideout_target_human", - "hideout_target_balls", - "head", - "smoke", - "fire", - "third_person", - ] - default_classes = list(range(len(class_names))) - - default_trigger = { - "status": False, - "start_delay": 150, - "press_delay": 1, - "end_delay": 200, - "random_delay": 20, - "x_trigger_scope": 0.5, - "y_trigger_scope": 0.5, - "x_trigger_offset": 0.0, - "y_trigger_offset": 0.0, - "continuous": False, - "recoil": False, - } - default_key = { - "confidence_threshold": 0.5, - "iou_t": 0.8, - "aim_bot_position": 0.5, - "aim_bot_position2": 0.5, - "aim_bot_scope": 160, - "smoothing_factor": 0.5, - "base_step": 0.17, - "distance_weight": 1.0, - "fov_angle": 90, - "history_size": 12, - "output_scale_x": 1.0, - "output_scale_y": 1.0, - "deadzone": 2.0, - "uniform_threshold": 1.0, - "compensation_factor": 1.0, - "trigger": default_trigger, - "classes": default_classes, - "class_priority_order": default_classes[:], - "class_aim_positions": { - str(i): { - "aim_bot_position": 0.5, - "aim_bot_position2": 0.5, - "confidence_threshold": 0.5, - "iou_t": 1.0, - } - for i in default_classes - }, - "overshoot_threshold": 3.0, - "overshoot_x_factor": 0.5, - "overshoot_y_factor": 0.3, - "move_deadzone": 1.0, - "pid_kp_x": 0.4, - "pid_kp_y": 0.4, - "pid_ki_x": 0.001, - "pid_ki_y": 0.001, - "pid_kd_x": 0.05, - "pid_kd_y": 0.05, - "smooth_x": 0, - "smooth_y": 0, - "smooth_deadzone": 0.0, - "smooth_algorithm": 1.0, - "target_switch_delay": 0, - "dynamic_scope": {"enabled": False}, - "trigger_only": False, - "disable_headshot_removed": False, - } - return { - "group": "Default", - "groups": { - "Default": { - "infer_model": "", - "original_infer_model": "", - "is_trt": False, - "yolo_format": "auto", - "sunone_model_variant": "yolo11", - "use_sunone_processing": False, - "right_down": False, - "aim_keys": {"mouse_side2": default_key}, - "disable_headshot": False, - "disable_headshot_keys": ["m"], - "disable_headshot_class_id": -1, - "targeting_button_key": "mouse_side2", - "triggerbot_button_key": "", - "disable_headshot_button_key": "m", - } - }, - "class_names": class_names, - "class_names_file": "", - "infer_debug": False, - "print_fps": False, - "show_motion_speed": False, - "move_method": "makcu", - "screen_width": 1920, - "screen_height": 1080, - "capture_offset_x": 0, - "capture_offset_y": 0, - "ui_language": "en", - "gui_width_scale": 1.0, - "gui_font_scale": 1.0, - "small_target_enhancement": { - "enabled": True, - "boost_factor": 0.1, - "threshold": 0.02, - "medium_threshold": 0.05, - "medium_boost": 1.5, - "smooth_enabled": True, - "smooth_frames": 2, - "adaptive_nms": True, - }, - } - - def init_all_keys_class_aim_positions(self, group, config): - """Initialize class aim position configuration for all keys""" - try: - old_group = getattr(self, "group", None) - self.group = group - self.config = config - class_num = self.get_current_class_num() - for key_name in config["groups"][group]["aim_keys"]: - key_config = config["groups"][group]["aim_keys"][key_name] - if "class_aim_positions" not in key_config: - key_config["class_aim_positions"] = {} - cap = key_config["class_aim_positions"] - if isinstance(cap, list): - converted = {} - for idx, item in enumerate(cap): - if isinstance(item, dict): - converted[str(idx)] = { - "aim_bot_position": float( - item.get("aim_bot_position", 0.0) - ), - "aim_bot_position2": float( - item.get("aim_bot_position2", 0.0) - ), - "confidence_threshold": float( - item.get("confidence_threshold", 0.5) - ), - "iou_t": float(item.get("iou_t", 1.0)), - } - else: - converted[str(idx)] = { - "aim_bot_position": 0.0, - "aim_bot_position2": 0.0, - "confidence_threshold": 0.5, - "iou_t": 1.0, - } - key_config["class_aim_positions"] = converted - else: - if not isinstance(cap, dict): - key_config["class_aim_positions"] = {} - if "class_priority_order" not in key_config: - key_config["class_priority_order"] = list(range(class_num)) - if "overshoot_threshold" not in key_config: - key_config["overshoot_threshold"] = 3.0 - if "overshoot_x_factor" not in key_config: - key_config["overshoot_x_factor"] = 0.5 - if "overshoot_y_factor" not in key_config: - key_config["overshoot_y_factor"] = 0.3 - if "trigger_only" not in key_config: - key_config["trigger_only"] = False - if "disable_headshot_removed" not in key_config: - key_config["disable_headshot_removed"] = False - for i in range(class_num): - class_str = str(i) - if class_str not in key_config["class_aim_positions"]: - key_config["class_aim_positions"][class_str] = { - "aim_bot_position": 0.0, - "aim_bot_position2": 0.0, - "confidence_threshold": 0.5, - "iou_t": 1.0, - } - if old_group is not None: - self.group = old_group - except Exception as e: - print(f"Failed to initialize class aim configuration for all keys: {e}") - import traceback - - traceback.print_exc() - - def migrate_config_to_class_based(self, config): - """Migrate configuration: migrate global confidence threshold and IOU config to class-based config""" - try: - for group_name, group_config in config.get("groups", {}).items(): - for key_name, key_config in group_config.get("aim_keys", {}).items(): - old_conf_thresh = key_config.get("confidence_threshold") - old_iou_t = key_config.get("iou_t") - if old_conf_thresh is not None or old_iou_t is not None: - if "class_aim_positions" not in key_config: - key_config["class_aim_positions"] = {} - class_aim_positions = key_config["class_aim_positions"] - if isinstance(class_aim_positions, list): - key_config["class_aim_positions"] = {} - class_aim_positions = {} - else: - if not isinstance(class_aim_positions, dict): - key_config["class_aim_positions"] = {} - class_aim_positions = {} - for class_str, class_config in class_aim_positions.items(): - if isinstance(class_config, dict): - if ( - old_conf_thresh is not None - and "confidence_threshold" not in class_config - ): - class_config["confidence_threshold"] = ( - old_conf_thresh - ) - if ( - old_iou_t is not None - and "iou_t" not in class_config - ): - class_config["iou_t"] = old_iou_t - except Exception as e: - print(f"Configuration migration failed: {e}") - import traceback - - traceback.print_exc() - - def calculate_max_pixel_distance(self, screen_width, screen_height, fov_angle): - diagonal_distance = (screen_width**2 + screen_height**2) ** 0.5 - max_pixel_distance = diagonal_distance / 2 * (fov_angle / 180) - return max_pixel_distance - - def refresh_controller_params(self): - self.dual_pid.set_pid_params( - kp=[ - self.pressed_key_config.get("pid_kp_x", 0.4), - self.pressed_key_config.get("pid_kp_y", 0.4), - ], - ki=[ - self.pressed_key_config.get("pid_ki_x", 0.02), - self.pressed_key_config.get("pid_ki_y", 0.02), - ], - kd=[ - self.pressed_key_config.get("pid_kd_x", 0.002), - self.pressed_key_config.get("pid_kd_y", 0), - ], - ) - integral_limit_x = self.pressed_key_config.get("pid_integral_limit_x", 0.0) - integral_limit_y = self.pressed_key_config.get("pid_integral_limit_y", 0.0) - self.dual_pid.set_windup_guard([integral_limit_x, integral_limit_y]) - smooth_x = self.pressed_key_config.get("smooth_x", 0) - smooth_y = self.pressed_key_config.get("smooth_y", 0) - smooth_deadzone = self.pressed_key_config.get("smooth_deadzone", 0.0) - smooth_algorithm = self.pressed_key_config.get("smooth_algorithm", 1.0) - self.dual_pid.set_smooth_params( - smooth_x, smooth_y, smooth_deadzone, smooth_algorithm - ) - - def refresh_pressed_key_config(self, key): - """ - Refresh currently pressed key's configuration - - Args: - key: Key name - """ - if key != self.old_refreshed_aim_key: - self.old_refreshed_aim_key = key - self.pressed_key_config = self.aim_keys_dist[key] - if hasattr(self, "dual_pid"): - self.dual_pid.reset() - if hasattr(self, "sunone_aim"): - self.sunone_aim.reset() - self.refresh_controller_params() - - def get_aim_position_for_class(self, class_id): - """Get aim position based on class ID""" - disable_headshot = False - try: - disable_headshot = bool( - self.config["groups"][self.group].get("disable_headshot", False) - ) - except Exception: - disable_headshot = False - - def pick_position(a, b): - if disable_headshot: - return max(a, b) - return random.uniform(a, b) - - if "class_aim_positions" not in self.pressed_key_config: - return pick_position( - self.pressed_key_config.get("aim_bot_position", 0.5), - self.pressed_key_config.get("aim_bot_position2", 0.5), - ) - class_str = str(class_id) - if class_str in self.pressed_key_config["class_aim_positions"]: - config = self.pressed_key_config["class_aim_positions"][class_str] - return pick_position(config["aim_bot_position"], config["aim_bot_position2"]) - return pick_position( - self.pressed_key_config.get("aim_bot_position", 0.5), - self.pressed_key_config.get("aim_bot_position2", 0.5), - ) diff --git a/sunone_aimbot_cpp/mouse/MakcuConnection.cpp b/sunone_aimbot_cpp/mouse/MakcuConnection.cpp deleted file mode 100644 index ea40991e..00000000 --- a/sunone_aimbot_cpp/mouse/MakcuConnection.cpp +++ /dev/null @@ -1,273 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#define _WINSOCKAPI_ -#include -#include -#include -#include -#include -#include -#include - -#include "MakcuConnection.h" -#include "config.h" -#include "sunone_aimbot_cpp.h" - -/* ---------- Makcu-специфические константы ---------------------------- */ -static const uint32_t BOOT_BAUD = 115200; // скорость после подключения -static const uint32_t WORK_BAUD = 4000000; // рабочая – 4 Мбит/с - -/* Команда смены скорости (из a.py): 0xDEAD0500A500093D00 */ -static const uint8_t BAUD_CHANGE_CMD[9] = -{ 0xDE,0xAD,0x05,0x00,0xA5,0x00,0x09,0x3D,0x00 }; - -/* ===================================================================== */ -/* КОНСТРУКТОР */ -MakcuConnection::MakcuConnection(const std::string& port, unsigned int /*baud_rate*/) - : is_open_(false), listening_(false), - aiming_active(false), shooting_active(false), zooming_active(false), triggerbot_active(false) -{ - try { - /* 1. открываем порт на 115 200 */ - serial_.setPort(port); - serial_.setBaudrate(BOOT_BAUD); - serial_.open(); - if (!serial_.isOpen()) - throw std::runtime_error("open failed"); - - /* 2. посылаем «секретный» пакет -> MCU перезапускается @4 Мбит */ - serial_.write(BAUD_CHANGE_CMD, sizeof(BAUD_CHANGE_CMD)); - serial_.close(); - std::this_thread::sleep_for(std::chrono::milliseconds(100)); // MCU reset - - /* 3. открываем снова, уже 4 Мбит/с */ - serial_.setBaudrate(WORK_BAUD); - serial_.open(); - if (!serial_.isOpen()) - throw std::runtime_error("re-open @4M failed"); - - is_open_ = true; - std::cout << "[Makcu] Connected @4 Mbps on " << port << '\n'; - - /* 4. глушим echo и включаем поток кнопок */ - sendCommand("km.echo(0)"); - sendCommand("km.buttons(1)"); - - startListening(); - } - catch (const std::exception& e) { - std::cerr << "[Makcu] Error: " << e.what() << '\n'; - } -} - -/* ===================================================================== */ -/* ДЕСТРУКТОР */ -MakcuConnection::~MakcuConnection() -{ - listening_ = false; - if (serial_.isOpen()) { - try { serial_.close(); } - catch (...) {} - } - if (listening_thread_.joinable()) - listening_thread_.join(); - is_open_ = false; -} - -/* ===================================================================== */ -/* ВСПОМОГАТЕЛЬНЫЕ МЕТОДЫ */ - -bool MakcuConnection::isOpen() const { return is_open_; } - -void MakcuConnection::write(const std::string& data) -{ - std::lock_guard lock(write_mutex_); - if (!is_open_) return; - try { serial_.write(data); } - catch (...) { is_open_ = false; } -} - -std::string MakcuConnection::read() -{ - if (!is_open_) - return std::string(); - - std::string result; - try - { - result = serial_.readline(65536, "\n"); - std::cout << result << std::endl; - } - catch (...) - { - is_open_ = false; - } - return result; -} - -void MakcuConnection::move(int x, int y) -{ - if (!is_open_) - return; - - std::string cmd = "km.move(" - + std::to_string(x) + "," - + std::to_string(y) + ")\r\n"; - write(cmd); -} - -void MakcuConnection::click(int button = 0) -{ - std::string cmd = "km.click(" - + std::to_string(button) - + ")\r\n"; - sendCommand(cmd); -} - -void MakcuConnection::press(int button) -{ - sendCommand("km.left(1)"); -} - -void MakcuConnection::release(int button) -{ - sendCommand("km.left(0)"); -} - -void MakcuConnection::start_boot() -{ - write("\x03\x03"); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - write("exec(open('boot.py').read(),globals())\r\n"); -} - -void MakcuConnection::reboot() -{ - write("\x03\x03"); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - write("km.reboot()"); -} - -void MakcuConnection::send_stop() -{ - write("\x03\x03"); -} - -void MakcuConnection::sendCommand(const std::string& cmd) { write(cmd + "\r\n"); } - -std::vector MakcuConnection::splitValue(int value) -{ - std::vector values; - return values; -} - -/* ===================================================================== */ -/* ЗАПУСК ПОТОКА СЛУШАТЕЛЯ */ -void MakcuConnection::startListening() -{ - listening_ = true; - if (listening_thread_.joinable()) - listening_thread_.join(); - - listening_thread_ = std::thread(&MakcuConnection::listeningThreadFunc, this); -} - -/* ===================================================================== */ -/* ОСНОВНОЙ ЦИКЛ ЧТЕНИЯ Makcu */ -void MakcuConnection::listeningThreadFunc() -{ - /* допустимые байты: 0x00 (нет), 0x01 (ЛКМ), 0x02 (ПКМ), 0x03 (обе) */ - const std::array legal{ 0x00,0x01,0x02,0x03,0x10,0x11 }; - - while (listening_ && is_open_) { - try { - if (!serial_.available()) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - uint8_t b = 0; - serial_.read(&b, 1); - - if (std::find(legal.begin(), legal.end(), b) == legal.end()) - continue; // отброс «мусора» - - // Боковые кнопки (0x10 верхняя, 0x11 нижняя) - if (b == 0x10) { - aiming_active = true; - aiming.store(true); - triggerbot_active = false; - std::cout << "Side1 (aim) PRESS" << std::endl; - continue; - } - if (b == 0x11) { - triggerbot_active = true; - triggerbot_button.store(true); - std::cout << "Side2 (triggerbot) PRESS" << std::endl; - continue; - } - - if (b == 0x00) { - shooting_active = false; - aiming_active = false; - triggerbot_active = false; - shooting.store(false); - aiming.store(false); - triggerbot_button.store(false); - std::cout << "Buttons released" << std::endl; - continue; - } - - /* обновляем флаги */ - shooting_active = b & 0x01; // ЛКМ - aiming_active = b & 0x02; // ПКМ - shooting.store(shooting_active); - aiming.store(aiming_active); - - /* выводим состояние */ - std::cout << "LMB: " << (shooting_active ? "PRESS" : "release") - << " | RMB: " << (aiming_active ? "PRESS" : "release") - << std::endl; - } - catch (...) { is_open_ = false; break; } - } -} - -void MakcuConnection::processIncomingLine(const std::string& line) -{ - try - { - if (line.rfind("BD:", 0) == 0) - { - int btnId = std::stoi(line.substr(3)); - switch (btnId) - { - case 1: - shooting_active = true; - shooting.store(true); - break; - case 2: - aiming_active = true; - aiming.store(true); - break; - } - } - else if (line.rfind("BU:", 0) == 0) - { - int btnId = std::stoi(line.substr(3)); - switch (btnId) - { - case 1: - shooting_active = false; - shooting.store(false); - break; - case 2: - aiming_active = false; - aiming.store(false); - break; - } - } - } - catch (const std::exception& e) - { - std::cerr << "[Makcu_b] Error processing line '" << line << "': " << e.what() << std::endl; - } -} diff --git a/sunone_aimbot_cpp/mouse/MakcuConnection.h b/sunone_aimbot_cpp/mouse/MakcuConnection.h deleted file mode 100644 index e53c4bf3..00000000 --- a/sunone_aimbot_cpp/mouse/MakcuConnection.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef MAKCUCONNECTION_H -#define MAKCUCONNECTION_H - -#define WIN32_LEAN_AND_MEAN -#define _WINSOCKAPI_ -#include -#include -#include -#include -#include - -#include "serial/serial.h" - -class MakcuConnection -{ -public: - MakcuConnection(const std::string& port, unsigned int baud_rate); - ~MakcuConnection(); - - bool isOpen() const; - - void write(const std::string& data); - std::string read(); - - void click(int button); - void press(int button); - void release(int button); - void move(int x, int y); - - void start_boot(); - void reboot(); - void send_stop(); - - bool aiming_active; - bool shooting_active; - bool zooming_active; - bool triggerbot_active; - -private: - void sendCommand(const std::string& command); - std::vector splitValue(int value); - - void startListening(); - void listeningThreadFunc(); - void processIncomingLine(const std::string& line); - -private: - serial::Serial serial_; - std::atomic is_open_; - std::atomic listening_; - std::thread listening_thread_; - std::mutex write_mutex_; -}; - -#endif // MAKCUCONNECTION_H diff --git a/sunone_aimbot_cpp/mouse/mouse.cpp b/sunone_aimbot_cpp/mouse/mouse.cpp deleted file mode 100644 index 30c8caf6..00000000 --- a/sunone_aimbot_cpp/mouse/mouse.cpp +++ /dev/null @@ -1,800 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#define _WINSOCKAPI_ -#include -#include - -#define _USE_MATH_DEFINES -#include -#include -#include -#include -#include -#include - -#include "mouse.h" -#include "capture.h" -#include "SerialConnection.h" -#include "sunone_aimbot_cpp.h" - -MouseThread::MouseThread( - int resolution, - int fovX, - int fovY, - double minSpeedMultiplier, - double maxSpeedMultiplier, - double predictionInterval, - bool auto_shoot, - float bScope_multiplier, - float triggerbot_bScope_multiplier, - SerialConnection* serialConnection, - KmboxConnection* kmboxConnection, - KmboxNetConnection* Kmbox_Net_Connection, - MakcuConnection* makcu) - : screen_width(resolution), - screen_height(resolution), - prediction_interval(predictionInterval), - fov_x(fovX), - fov_y(fovY), - max_distance(std::hypot(resolution, resolution) / 2.0), - min_speed_multiplier(minSpeedMultiplier), - max_speed_multiplier(maxSpeedMultiplier), - center_x(resolution / 2.0), - center_y(resolution / 2.0), - auto_shoot(auto_shoot), - bScope_multiplier(bScope_multiplier), - triggerbot_bScope_multiplier(triggerbot_bScope_multiplier), - serial(serialConnection), - kmbox(kmboxConnection), - kmbox_net(Kmbox_Net_Connection), - makcu(makcu), - - prev_velocity_x(0.0), - prev_velocity_y(0.0), - prev_x(0.0), - prev_y(0.0) -{ - prev_time = std::chrono::steady_clock::time_point(); - last_target_time = std::chrono::steady_clock::now(); - - wind_mouse_enabled = config.wind_mouse_enabled; - wind_G = config.wind_G; - wind_W = config.wind_W; - wind_M = config.wind_M; - wind_D = config.wind_D; - - use_smoothing = config.use_smoothing; - use_kalman = config.use_kalman; - - kfX = Kalman1D(config.kalman_process_noise, config.kalman_measurement_noise); - kfY = Kalman1D(config.kalman_process_noise, config.kalman_measurement_noise); - - moveWorker = std::thread(&MouseThread::moveWorkerLoop, this); -} - -void MouseThread::updateConfig( - int resolution, - int fovX, - int fovY, - double minSpeedMultiplier, - double maxSpeedMultiplier, - double predictionInterval, - bool auto_shoot, - float bScope_multiplier, - float triggerbot_bScope_multiplier -) -{ - screen_width = screen_height = resolution; - fov_x = fovX; fov_y = fovY; - min_speed_multiplier = minSpeedMultiplier; - max_speed_multiplier = maxSpeedMultiplier; - prediction_interval = predictionInterval; - this->auto_shoot = auto_shoot; - this->bScope_multiplier = bScope_multiplier; - this->triggerbot_bScope_multiplier = triggerbot_bScope_multiplier; - - center_x = center_y = resolution / 2.0; - max_distance = std::hypot(resolution, resolution) / 2.0; - - wind_mouse_enabled = config.wind_mouse_enabled; - wind_G = config.wind_G; wind_W = config.wind_W; - wind_M = config.wind_M; wind_D = config.wind_D; - - use_smoothing = config.use_smoothing; - use_kalman = config.use_kalman; - - kfX = Kalman1D(config.kalman_process_noise, config.kalman_measurement_noise); - kfY = Kalman1D(config.kalman_process_noise, config.kalman_measurement_noise); - -} - -MouseThread::~MouseThread() -{ - workerStop = true; - queueCv.notify_all(); - if (moveWorker.joinable()) moveWorker.join(); -} - -void MouseThread::queueMove(int dx, int dy) -{ - std::lock_guard lg(queueMtx); - if (moveQueue.size() >= queueLimit) moveQueue.pop(); - moveQueue.push({ dx,dy }); - queueCv.notify_one(); -} - -void MouseThread::moveWorkerLoop() -{ - while (!workerStop) - { - std::unique_lock ul(queueMtx); - queueCv.wait(ul, [&] { return workerStop || !moveQueue.empty(); }); - - while (!moveQueue.empty()) - { - Move m = moveQueue.front(); - moveQueue.pop(); - ul.unlock(); - sendMovementToDriver(m.dx, m.dy); - ul.lock(); - } - } -} - -void MouseThread::windMouseMoveRelative(int dx, int dy) -{ - if (dx == 0 && dy == 0) return; - - constexpr double SQRT3 = 1.7320508075688772; - constexpr double SQRT5 = 2.23606797749979; - - double sx = 0, sy = 0; - double dxF = static_cast(dx); - double dyF = static_cast(dy); - double vx = 0, vy = 0, wX = 0, wY = 0; - int cx = 0, cy = 0; - - while (std::hypot(dxF - sx, dyF - sy) >= 1.0) - { - double dist = std::hypot(dxF - sx, dyF - sy); - double wMag = std::min(wind_W, dist); - - if (dist >= wind_D) - { - wX = wX / SQRT3 + ((double)rand() / RAND_MAX * 2.0 - 1.0) * wMag / SQRT5; - wY = wY / SQRT3 + ((double)rand() / RAND_MAX * 2.0 - 1.0) * wMag / SQRT5; - } - else - { - wX /= SQRT3; wY /= SQRT3; - wind_M = wind_M < 3.0 ? ((double)rand() / RAND_MAX) * 3.0 + 3.0 : wind_M / SQRT5; - } - - vx += wX + wind_G * (dxF - sx) / dist; - vy += wY + wind_G * (dyF - sy) / dist; - - double vMag = std::hypot(vx, vy); - if (vMag > wind_M) - { - double vClip = wind_M / 2.0 + ((double)rand() / RAND_MAX) * wind_M / 2.0; - vx = (vx / vMag) * vClip; - vy = (vy / vMag) * vClip; - } - - sx += vx; sy += vy; - int rx = static_cast(std::round(sx)); - int ry = static_cast(std::round(sy)); - int step_x = rx - cx; - int step_y = ry - cy; - if (step_x || step_y) - { - queueMove(step_x, step_y); - cx = rx; cy = ry; - } - } -} - -std::pair MouseThread::predict_target_position(double target_x, double target_y) -{ - auto current_time = std::chrono::steady_clock::now(); - - if (prev_time.time_since_epoch().count() == 0 || !target_detected.load()) - { - prev_time = current_time; - prev_x = target_x; - prev_y = target_y; - prev_velocity_x = 0.0; - prev_velocity_y = 0.0; - return { target_x, target_y }; - } - - double dt = std::chrono::duration(current_time - prev_time).count(); - if (dt < 1e-8) dt = 1e-8; - - double vx = (target_x - prev_x) / dt; - double vy = (target_y - prev_y) / dt; - - vx = std::clamp(vx, -20000.0, 20000.0); - vy = std::clamp(vy, -20000.0, 20000.0); - - prev_time = current_time; - prev_x = target_x; - prev_y = target_y; - prev_velocity_x = vx; - prev_velocity_y = vy; - - double predictedX = target_x + vx * prediction_interval; - double predictedY = target_y + vy * prediction_interval; - - double detectionDelay = 0.05; - if (config.backend == "DML") - { - detectionDelay = dml_detector->lastInferenceTimeDML.count(); - } -#ifdef USE_CUDA - else - { - detectionDelay = trt_detector.lastInferenceTime.count(); - } -#endif - predictedX += vx * detectionDelay; - predictedY += vy * detectionDelay; - - return { predictedX, predictedY }; -} - -void MouseThread::sendMovementToDriver(int dx, int dy) -{ - std::lock_guard lock(input_method_mutex); - if (makcu) - { - makcu->move(dx, dy); - } - else if (kmbox) - { - kmbox->move(dx, dy); - } - else if (kmbox_net) - { - kmbox_net->move(dx, dy); - } - else if (serial) - { - serial->move(dx, dy); - } - else - { - INPUT in{ 0 }; - in.type = INPUT_MOUSE; - in.mi.dx = dx; in.mi.dy = dy; - in.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK; - SendInput(1, &in, sizeof(INPUT)); - } -} - -std::pair MouseThread::calc_movement(double tx, double ty) -{ - double offx = tx - center_x; - double offy = ty - center_y; - double dist = std::hypot(offx, offy); - double speed = calculate_speed_multiplier(dist); - - double degPerPxX = fov_x / screen_width; - double degPerPxY = fov_y / screen_height; - - double mmx = offx * degPerPxX; - double mmy = offy * degPerPxY; - - double corr = 1.0; - double fps = static_cast(captureFps.load()); - if (fps > 30.0) corr = 30.0 / fps; - - auto counts_pair = config.degToCounts(mmx, mmy, fov_x); - double move_x = counts_pair.first * speed * corr; - double move_y = counts_pair.second * speed * corr; - - return { move_x, move_y }; -} - -double MouseThread::calculate_speed_multiplier(double distance) -{ - if (distance < config.snapRadius) - return min_speed_multiplier * config.snapBoostFactor; - - if (distance < config.nearRadius) - { - double t = distance / config.nearRadius; - double curve = 1.0 - std::pow(1.0 - t, config.speedCurveExponent); - return min_speed_multiplier + - (max_speed_multiplier - min_speed_multiplier) * curve; - } - - double norm = std::clamp(distance / max_distance, 0.0, 1.0); - return min_speed_multiplier + - (max_speed_multiplier - min_speed_multiplier) * norm; -} - -bool MouseThread::check_target_in_scope(double target_x, double target_y, double target_w, double target_h, double reduction_factor) -{ - double center_target_x = target_x + target_w / 2.0; - double center_target_y = target_y + target_h / 2.0; - - double reduced_w = target_w * (reduction_factor / 2.0); - double reduced_h = target_h * (reduction_factor / 2.0); - - double x1 = center_target_x - reduced_w; - double x2 = center_target_x + reduced_w; - double y1 = center_target_y - reduced_h; - double y2 = center_target_y + reduced_h; - - return (center_x > x1 && center_x < x2 && center_y > y1 && center_y < y2); -} - -void MouseThread::pressMouse(const AimbotTarget& target, float scope_multiplier) -{ - std::lock_guard lock(input_method_mutex); - - double multiplier = scope_multiplier > 0.0f ? scope_multiplier : bScope_multiplier; - bool bScope = check_target_in_scope(target.x, target.y, target.w, target.h, multiplier); - if (bScope && !mouse_pressed) - { - if (makcu) - { - makcu->press(0); - } - else if (kmbox) - { - kmbox->press(0); - } - else if (kmbox_net) - { - kmbox_net->keyDown(0); - } - else if (serial) - { - serial->press(); - } - else - { - INPUT input = { 0 }; - input.type = INPUT_MOUSE; - input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN; - SendInput(1, &input, sizeof(INPUT)); - } - mouse_pressed = true; - } - else if (!bScope && mouse_pressed) - { - if (makcu) - { - makcu->release(0); - } - else if (kmbox) - { - kmbox->release(0); - } - else if (kmbox_net) - { - kmbox_net->keyUp(0); - } - else if (serial) - { - serial->release(); - } - else - { - INPUT input = { 0 }; - input.type = INPUT_MOUSE; - input.mi.dwFlags = MOUSEEVENTF_LEFTUP; - SendInput(1, &input, sizeof(INPUT)); - } - mouse_pressed = false; - } -} - -void MouseThread::releaseMouse() -{ - std::lock_guard lock(input_method_mutex); - - if (mouse_pressed) - { - if (makcu) - { - makcu->release(0); - } - else if (kmbox) - { - kmbox->release(0); - } - else if (kmbox_net) - { - kmbox_net->keyUp(0); - } - else if (serial) - { - serial->release(); - } - else - { - INPUT input = { 0 }; - input.type = INPUT_MOUSE; - input.mi.dwFlags = MOUSEEVENTF_LEFTUP; - SendInput(1, &input, sizeof(INPUT)); - } - mouse_pressed = false; - } -} - -void MouseThread::resetPrediction() -{ - prev_time = std::chrono::steady_clock::time_point(); - prev_x = 0; - prev_y = 0; - prev_velocity_x = 0; - prev_velocity_y = 0; - target_detected.store(false); -} - -void MouseThread::checkAndResetPredictions() -{ - auto current_time = std::chrono::steady_clock::now(); - double elapsed = std::chrono::duration(current_time - last_target_time).count(); - - if (elapsed > 0.5 && target_detected.load()) - { - resetPrediction(); - } -} - -std::vector> MouseThread::predictFuturePositions(double pivotX, double pivotY, int frames) -{ - std::vector> result; - result.reserve(frames); - - const double fixedFps = 30.0; - double frame_time = 1.0 / fixedFps; - - auto current_time = std::chrono::steady_clock::now(); - double dt = std::chrono::duration(current_time - prev_time).count(); - - if (prev_time.time_since_epoch().count() == 0 || dt > 0.5) - { - return result; - } - - double vx = prev_velocity_x; - double vy = prev_velocity_y; - - for (int i = 1; i <= frames; i++) - { - double t = frame_time * i; - - double px = pivotX + vx * t; - double py = pivotY + vy * t; - - result.push_back({ px, py }); - } - - return result; -} - -void MouseThread::storeFuturePositions(const std::vector>& positions) -{ - std::lock_guard lock(futurePositionsMutex); - futurePositions = positions; -} - -void MouseThread::clearFuturePositions() -{ - std::lock_guard lock(futurePositionsMutex); - futurePositions.clear(); -} - -std::vector> MouseThread::getFuturePositions() -{ - std::lock_guard lock(futurePositionsMutex); - return futurePositions; -} - -void MouseThread::setSerialConnection(SerialConnection* newSerial) -{ - std::lock_guard lock(input_method_mutex); - serial = newSerial; -} - -void MouseThread::setKmboxConnection(KmboxConnection* newKmbox) -{ - std::lock_guard lock(input_method_mutex); - kmbox = newKmbox; -} - -void MouseThread::setKmboxNetConnection(KmboxNetConnection* newKmbox_net) -{ - std::lock_guard lock(input_method_mutex); - kmbox_net = newKmbox_net; -} - -void MouseThread::setMakcuConnection(MakcuConnection* newMakcu) -{ - std::lock_guard lock( input_method_mutex); - makcu = newMakcu; -} -// Kalma -void MouseThread::moveMouseWithKalman(double targetX, double targetY) { - double rawX = targetX, rawY = targetY; - static double lastRawX = 0.0, lastRawY = 0.0; - static bool firstCall = true; - const double resetThreshold = config.resetThreshold; - - // 0) Сброс при большом «прыжке» цели или первом вызове - if (firstCall || std::hypot(rawX - lastRawX, rawY - lastRawY) > resetThreshold) { - kfX.x = rawX; kfX.v = 0.0; kfX.P = 1.0; - kfY.x = rawY; kfY.v = 0.0; kfY.P = 1.0; - prevKalmanTime = std::chrono::steady_clock::now(); - firstCall = false; - } - lastRawX = rawX; - lastRawY = rawY; - - // 1) dt - auto now = std::chrono::steady_clock::now(); - double dt = prevKalmanTime.time_since_epoch().count() == 0 - ? 1.0 / static_cast(config.capture_fps) - : std::max(std::chrono::duration(now - prevKalmanTime).count(), 1e-8); - prevKalmanTime = now; - - // 2) Predict+Update - double filtX = kfX.update(rawX, dt); - double filtY = kfY.update(rawY, dt); - - // 3) В дельту мыши - auto [mvX, mvY] = calc_movement(filtX, filtY); - mvX *= kalman_speed_multiplier_x; - mvY *= kalman_speed_multiplier_y; - - // 4) Отправка - int dx = static_cast(std::round(mvX)); - int dy = static_cast(std::round(mvY)); - if (wind_mouse_enabled) windMouseMoveRelative(dx, dy); - else queueMove(dx, dy); -} - -// Kalma + smooth -void MouseThread::moveMouseWithKalmanAndSmoothing(double targetX, double targetY) -{ - double rawX = targetX; - double rawY = targetY; - - const double resetThreshold = config.resetThreshold; - - auto now = std::chrono::steady_clock::now(); - - const double maxDt = 0.25; // avoid using stale timestamps after long pauses - bool needReset = !kalman_smoothing_initialized; - - if (!needReset) - { - double jump = std::hypot(rawX - last_raw_kalman_x, rawY - last_raw_kalman_y); - if (jump > resetThreshold) needReset = true; - - double dtSinceLast = std::chrono::duration(now - prevKalmanTime).count(); - if (dtSinceLast > maxDt) needReset = true; - } - - if (needReset || prevKalmanTime.time_since_epoch().count() == 0) { - kfX.x = rawX; kfX.v = 0.0; kfX.P = 1.0; - kfY.x = rawY; kfY.v = 0.0; kfY.P = 1.0; - prevKalmanTime = now; - - last_kX = rawX; - last_kY = rawY; - - move_overflow_x = 0.0; - move_overflow_y = 0.0; - - kalman_smoothing_initialized = true; - } - last_raw_kalman_x = rawX; - last_raw_kalman_y = rawY; - - double dt; - if (prevKalmanTime.time_since_epoch().count() == 0 || needReset) { - dt = 1.0 / static_cast(std::max(config.capture_fps, 1)); - } else { - dt = std::chrono::duration(now - prevKalmanTime).count(); - } - prevKalmanTime = now; - dt = std::clamp(dt, 1e-8, maxDt); - - double filtX = kfX.update(rawX, dt); - double filtY = kfY.update(rawY, dt); - - int N = smoothness > 0 ? smoothness : 1; - double baseAlpha = 1.0 - std::exp(-dt * static_cast(config.capture_fps) / N); - - double delta = std::hypot(filtX - last_kX, filtY - last_kY); - double catchup = std::clamp(delta / std::max(resetThreshold, 1e-3), 0.0, 1.0); - double alpha = std::clamp(baseAlpha + (0.45 - baseAlpha) * catchup, baseAlpha, 0.45); - - if (delta > resetThreshold) { - last_kX = filtX; - last_kY = filtY; - } else { - last_kX += (filtX - last_kX) * alpha; - last_kY += (filtY - last_kY) * alpha; - } - - auto [mvX, mvY] = calc_movement(last_kX, last_kY); - - mvX *= kalman_speed_multiplier_x; - mvY *= kalman_speed_multiplier_y; - - auto [stepX, stepY] = addOverflow(mvX, mvY, move_overflow_x, move_overflow_y); - int dx = static_cast(stepX); - int dy = static_cast(stepY); - - if (dx || dy) { - if (wind_mouse_enabled) { - windMouseMoveRelative(dx, dy); - } else { - queueMove(dx, dy); - } - } -} - - -// easing-функция для плавности -double MouseThread::easeInOut(double t) { - return -0.5 * (std::cos(M_PI * t) - 1.0); -} - -// Управление дробной частью, чтобы не терять пиксели -std::pair MouseThread::addOverflow( - double dx, double dy, - double& overflow_x, double& overflow_y) -{ - double int_x = 0.0, int_y = 0.0; - double frac_x = std::modf(dx + overflow_x, &int_x); - double frac_y = std::modf(dy + overflow_y, &int_y); - - if (std::abs(frac_x) > 1.0) { - double extra = 0.0; - frac_x = std::modf(frac_x, &extra); - int_x += extra; - } - if (std::abs(frac_y) > 1.0) { - double extra = 0.0; - frac_y = std::modf(frac_y, &extra); - int_y += extra; - } - - overflow_x = frac_x; - overflow_y = frac_y; - return { int_x, int_y }; -} - -// «Микрошаговая» плавная наводка -void MouseThread::moveMouseWithSmoothing(double targetX, double targetY) -{ - if (smoothness <= 0) smoothness = 1; - - static double startX = 0.0, startY = 0.0; - static double prevX = 0.0, prevY = 0.0; - static double lastTX = 0.0, lastTY = 0.0; - static int frame = 0; - - std::lock_guard lg(input_method_mutex); - - if (frame == 0 || std::hypot(targetX - lastTX, targetY - lastTY) > 1.0) { - startX = center_x; - startY = center_y; - prevX = startX; - prevY = startY; - frame = 0; - } - lastTX = targetX; - lastTY = targetY; - - int N = smoothness; - frame = std::min(frame + 1, N); - double t = double(frame) / N; - double p = easeInOut(t); - - double curX = startX + (targetX - startX) * p; - double curY = startY + (targetY - startY) * p; - - double dx = curX - prevX; - double dy = curY - prevY; - - auto mv = addOverflow(dx, dy, move_overflow_x, move_overflow_y); - int ix = static_cast(mv.first); - int iy = static_cast(mv.second); - if (ix || iy) queueMove(ix, iy); - - prevX = curX; - prevY = curY; -} - -void MouseThread::setKalmanParams(double processNoise, double measurementNoise) { - std::lock_guard lg(input_method_mutex); - // просто перезапускаем фильтры с новыми Q/R - kfX = Kalman1D(processNoise, measurementNoise); - kfY = Kalman1D(processNoise, measurementNoise); -} - -void MouseThread::moveMouse(const AimbotTarget& target) -{ - auto now = std::chrono::steady_clock::now(); - double dt; - if (prevKalmanTime.time_since_epoch().count() == 0) { - dt = 1.0 / static_cast(config.capture_fps); - } - else { - dt = std::chrono::duration(now - prevKalmanTime).count(); - dt = std::max(dt, 1e-8); - } - prevKalmanTime = now; - - double rawX = target.x + target.w * 0.5; - double rawY = target.y + target.h * 0.5; - auto [predX, predY] = predict_target_position(rawX, rawY); - - if (use_kalman && !use_smoothing) { - moveMouseWithKalman(predX, predY); - } - else if (!use_kalman && use_smoothing) { - moveMouseWithSmoothing(predX, predY); - } - else if (use_kalman && use_smoothing) { - moveMouseWithKalmanAndSmoothing(predX, predY); - } - else { - auto [mvX, mvY] = calc_movement(predX, predY); - if (wind_mouse_enabled) - windMouseMoveRelative(static_cast(mvX), static_cast(mvY)); - else - queueMove(static_cast(std::round(mvX)), - static_cast(std::round(mvY))); - } -} - -// Аналогично для moveMousePivot -void MouseThread::moveMousePivot(double pivotX, double pivotY) -{ - auto now = std::chrono::steady_clock::now(); - - if (prev_time.time_since_epoch().count() == 0 || !target_detected.load()) { - prev_time = now; - prev_x = pivotX; prev_y = pivotY; - prev_velocity_x = prev_velocity_y = 0.0; - } - else { - double dt0 = std::max(1e-8, - std::chrono::duration(now - prev_time).count()); - prev_time = now; - double vx = std::clamp((pivotX - prev_x) / dt0, -20000.0, 20000.0); - double vy = std::clamp((pivotY - prev_y) / dt0, -20000.0, 20000.0); - prev_x = pivotX; prev_y = pivotY; - prev_velocity_x = vx; prev_velocity_y = vy; - } - - double predX = pivotX + prev_velocity_x * (prediction_interval + 0.002); - double predY = pivotY + prev_velocity_y * (prediction_interval + 0.002); - - if (use_kalman && !use_smoothing) { - moveMouseWithKalman(predX, predY); - } - else if (!use_kalman && use_smoothing) { - moveMouseWithSmoothing(predX, predY); - } - else if (use_kalman && use_smoothing) { - moveMouseWithKalmanAndSmoothing(predX, predY); - } - else { - auto [mvX, mvY] = calc_movement(predX, predY); - if (wind_mouse_enabled) - windMouseMoveRelative(static_cast(mvX), static_cast(mvY)); - else - queueMove(static_cast(std::round(mvX)), - static_cast(std::round(mvY))); - } -} diff --git a/sunone_aimbot_cpp/overlay/draw_capture.cpp b/sunone_aimbot_cpp/overlay/draw_capture.cpp deleted file mode 100644 index b00af9e7..00000000 --- a/sunone_aimbot_cpp/overlay/draw_capture.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#define _WINSOCKAPI_ -#include -#include - -#include -#include - -#include -#include "imgui/imgui_internal.h" - -#include "config.h" -#include "sunone_aimbot_cpp.h" -#include "capture.h" -#include "other_tools.h" -#include "virtual_camera.h" -#include "draw_settings.h" -#include "overlay.h" - -bool disable_winrt_futures = checkwin1903(); -int monitors = get_active_monitors(); - -static std::vector virtual_cameras; -static char virtual_camera_filter_buf[128] = ""; - -void ensureVirtualCamerasLoaded() { - if (virtual_cameras.empty()) { - virtual_cameras = VirtualCameraCapture::GetAvailableVirtualCameras(); - } -} - -void draw_capture_settings() -{ - static const int allowed_resolutions[] = { 220, 320, 640 }; - static int current_resolution_idx = 1; - - for (int i = 0; i < 3; ++i) - if (config.detection_resolution == allowed_resolutions[i]) - current_resolution_idx = i; - - if (ImGui::Combo("Detection Resolution", ¤t_resolution_idx, "220\0""320\0""640\0")) - { - config.detection_resolution = allowed_resolutions[current_resolution_idx]; - detection_resolution_changed.store(true); - detector_model_changed.store(true); - - globalMouseThread->updateConfig( - config.detection_resolution, - config.fovX, - config.fovY, - config.minSpeedMultiplier, - config.maxSpeedMultiplier, - config.predictionInterval, - config.auto_shoot, - config.bScope_multiplier, - config.triggerbot_bScope_multiplier); - config.saveConfig(); - } - - if (ImGui::SliderInt("Capture FPS", &config.capture_fps, 0, 400)) - { - capture_fps_changed.store(true); - config.saveConfig(); - } - - if (config.capture_fps == 0) - { - ImGui::SameLine(); - ImGui::TextColored(ImVec4(255, 0, 0, 255), "-> Disabled"); - } - - if (config.capture_fps == 0 || config.capture_fps >= 61) - { - ImGui::TextColored(ImVec4(255, 255, 0, 255), "WARNING: A large number of FPS can negatively affect performance."); - } - - if (ImGui::Checkbox("Circle mask", &config.circle_mask)) - { - capture_method_changed.store(true); - config.saveConfig(); - } - - std::vector captureMethodOptions = { "duplication_api", "winrt", "virtual_camera" }; - std::vector captureMethodItems; - - for (const auto& option : captureMethodOptions) - { - captureMethodItems.push_back(option.c_str()); - } - - int currentcaptureMethodIndex = 0; - for (size_t i = 0; i < captureMethodOptions.size(); ++i) - { - if (captureMethodOptions[i] == config.capture_method) - { - currentcaptureMethodIndex = static_cast(i); - break; - } - } - - if (ImGui::Combo("Capture method", ¤tcaptureMethodIndex, captureMethodItems.data(), static_cast(captureMethodItems.size()))) { - config.capture_method = captureMethodOptions[currentcaptureMethodIndex]; - config.saveConfig(); - capture_method_changed.store(true); - } - - if (config.capture_method == "winrt") - { - if (disable_winrt_futures) - { - ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); - ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); - } - - if (ImGui::Checkbox("Capture Borders", &config.capture_borders)) - { - capture_borders_changed.store(true); - config.saveConfig(); - } - - if (ImGui::Checkbox("Capture Cursor", &config.capture_cursor)) - { - capture_cursor_changed.store(true); - config.saveConfig(); - } - - if (disable_winrt_futures) - { - ImGui::PopStyleVar(); - ImGui::PopItemFlag(); - } - } - - if (config.capture_method == "duplication_api" || config.capture_method == "winrt") - { - std::vector monitorNames; - if (monitors == -1) - { - monitorNames.push_back("Monitor 1"); - } - else - { - for (int i = -1; i < monitors; ++i) - { - monitorNames.push_back("Monitor " + std::to_string(i + 1)); - } - } - - std::vector monitorItems; - for (const auto& name : monitorNames) - { - monitorItems.push_back(name.c_str()); - } - - if (ImGui::Combo("Capture monitor", &config.monitor_idx, monitorItems.data(), static_cast(monitorItems.size()))) - { - config.saveConfig(); - capture_method_changed.store(true); - } - } - - if (config.capture_method == "virtual_camera") - { - ensureVirtualCamerasLoaded(); - ImGui::Text("Select virtual camera:"); - - // Filter - ImGui::Text("Filter:"); - if (ImGui::InputText("##VCFilter", virtual_camera_filter_buf, IM_ARRAYSIZE(virtual_camera_filter_buf))) - { - - } - - std::string filter_lower = virtual_camera_filter_buf; - std::transform(filter_lower.begin(), filter_lower.end(), filter_lower.begin(), ::tolower); - - // Filter list - std::vector filtered_indices; - for (int i = 0; i < static_cast(virtual_cameras.size()); ++i) - { - std::string name_lower = virtual_cameras[i]; - std::transform(name_lower.begin(), name_lower.end(), name_lower.begin(), ::tolower); - if (filter_lower.empty() || name_lower.find(filter_lower) != std::string::npos) - { - filtered_indices.push_back(i); - } - } - - if (!filtered_indices.empty()) - { - int currentIndex = 0; - for (int fi = 0; fi < static_cast(filtered_indices.size()); ++fi) - { - if (virtual_cameras[filtered_indices[fi]] == config.virtual_camera_name) - { - currentIndex = fi; - break; - } - } - - // Build items - std::vector items; - items.reserve(filtered_indices.size()); - for (int idx : filtered_indices) - { - items.push_back(virtual_cameras[idx].c_str()); - } - - if (ImGui::Combo("##virtual_camera_combo", ¤tIndex, items.data(), static_cast(items.size()))) - { - config.virtual_camera_name = virtual_cameras[filtered_indices[currentIndex]]; - config.saveConfig(); - capture_method_changed.store(true); - } - } - else - { - ImGui::TextDisabled("No matching virtual cameras"); - } - - ImGui::SameLine(); - if (ImGui::Button("Refresh")) - { - VirtualCameraCapture::ClearCachedCameraList(); - virtual_cameras = VirtualCameraCapture::GetAvailableVirtualCameras(true); - virtual_camera_filter_buf[0] = '\0'; - } - - if (ImGui::SliderInt("Virtual camera width", &config.virtual_camera_width, 128, 3840)) - { - config.saveConfig(); - capture_method_changed.store(true); - } - - if (ImGui::SliderInt("Virtual camera heigth", &config.virtual_camera_heigth, 128, 2160)) - { - config.saveConfig(); - capture_method_changed.store(true); - } - } -} diff --git a/sunone_aimbot_cpp/overlay/draw_game_overlay.cpp b/sunone_aimbot_cpp/overlay/draw_game_overlay.cpp deleted file mode 100644 index 28d7ebde..00000000 --- a/sunone_aimbot_cpp/overlay/draw_game_overlay.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#define _WINSOCKAPI_ -#include -#include - -#include "imgui/imgui.h" -#include "config.h" -#include "sunone_aimbot_cpp.h" - -#include -#include - -extern Config config; - -extern std::string g_iconLastError; - -void draw_game_overlay_settings() -{ - ImGui::Checkbox("Enable", &config.game_overlay_enabled); - ImGui::SliderInt("Overlay Max FPS (0 = uncapped)", &config.game_overlay_max_fps, 0, 256); - - ImGui::Checkbox("Draw Detection Boxes", &config.game_overlay_draw_boxes); - ImGui::Checkbox("Draw Future Positions", &config.game_overlay_draw_future); - - ImGui::Separator(); - ImGui::Text("Box Color (ARGB 0-255)"); - bool changed = false; - changed |= ImGui::SliderInt("A##go_box_a", &config.game_overlay_box_a, 0, 255); - changed |= ImGui::SliderInt("R##go_box_r", &config.game_overlay_box_r, 0, 255); - changed |= ImGui::SliderInt("G##go_box_g", &config.game_overlay_box_g, 0, 255); - changed |= ImGui::SliderInt("B##go_box_b", &config.game_overlay_box_b, 0, 255); - ImGui::SliderFloat("Box Thickness", &config.game_overlay_box_thickness, 0.5f, 10.0f, "%.1f"); - - ImGui::Separator(); - ImGui::Text("Future Point Style"); - ImGui::SliderFloat("Point Radius", &config.game_overlay_future_point_radius, 1.0f, 20.0f, "%.1f"); - ImGui::SliderFloat("Point Step Alpha Falloff", &config.game_overlay_future_alpha_falloff, 0.1f, 5.0f, "%.2f"); - - if (changed) - { - config.clampGameOverlayColor(); - } - - ImGui::Separator(); - ImGui::Text("Icon Overlay"); - ImGui::Checkbox("Enable Icon Overlay", &config.game_overlay_icon_enabled); - - static bool pathInit = false; - static char iconPathBuf[512]; - if (!pathInit) - { - pathInit = true; - memset(iconPathBuf, 0, sizeof(iconPathBuf)); - std::string p = config.game_overlay_icon_path; - if (p.size() >= sizeof(iconPathBuf)) p = p.substr(0, sizeof(iconPathBuf) - 1); - memcpy(iconPathBuf, p.c_str(), p.size()); - } - - ImGui::InputText("Icon Path", iconPathBuf, IM_ARRAYSIZE(iconPathBuf)); - ImGui::SliderInt("Icon Width", &config.game_overlay_icon_width, 4, 512); - ImGui::SliderInt("Icon Height", &config.game_overlay_icon_height, 4, 512); - ImGui::SliderFloat("Icon Offset X", &config.game_overlay_icon_offset_x, -500.0f, 500.0f, "%.1f"); - ImGui::SliderFloat("Icon Offset Y", &config.game_overlay_icon_offset_y, -500.0f, 500.0f, "%.1f"); - - const char* anchors[] = { "center", "top", "bottom", "head" }; - int currentAnchor = 0; - for (int i = 0; i < (int)(sizeof(anchors) / sizeof(anchors[0])); ++i) - { - if (config.game_overlay_icon_anchor == anchors[i]) - { - currentAnchor = i; - break; - } - } - if (ImGui::Combo("Icon Anchor", ¤tAnchor, anchors, IM_ARRAYSIZE(anchors))) - { - config.game_overlay_icon_anchor = anchors[currentAnchor]; - } - - if (!g_iconLastError.empty()) - { - ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 100, 100, 255)); - ImGui::TextWrapped("%s", g_iconLastError.c_str()); - ImGui::PopStyleColor(); - } - - if (ImGui::Button("Save Game Overlay Config")) - { - config.game_overlay_icon_path = iconPathBuf; - config.saveConfig("config.ini"); - } - -} \ No newline at end of file diff --git a/sunone_aimbot_cpp/overlay/draw_overlay.cpp b/sunone_aimbot_cpp/overlay/draw_overlay.cpp deleted file mode 100644 index 7e7d6284..00000000 --- a/sunone_aimbot_cpp/overlay/draw_overlay.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#define _WINSOCKAPI_ -#include -#include - -#include "imgui/imgui.h" -#include "sunone_aimbot_cpp.h" -#include "overlay.h" - -void draw_overlay() -{ - ImGui::SliderInt("Overlay Opacity", &config.overlay_opacity, 40, 255); - - static float ui_scale = config.overlay_ui_scale; - - if (ImGui::SliderFloat("UI Scale", &ui_scale, 0.5f, 3.0f, "%.2f")) - { - ImGui::GetIO().FontGlobalScale = ui_scale; - - config.overlay_ui_scale = ui_scale; - config.saveConfig("config.ini"); - - extern const int BASE_OVERLAY_WIDTH; - extern const int BASE_OVERLAY_HEIGHT; - overlayWidth = static_cast(BASE_OVERLAY_WIDTH * ui_scale); - overlayHeight = static_cast(BASE_OVERLAY_HEIGHT * ui_scale); - - SetWindowPos(g_hwnd, NULL, 0, 0, overlayWidth, overlayHeight, SWP_NOMOVE | SWP_NOZORDER); - } -} \ No newline at end of file diff --git a/sunone_aimbot_cpp/overlay/draw_stats.cpp b/sunone_aimbot_cpp/overlay/draw_stats.cpp deleted file mode 100644 index fe749877..00000000 --- a/sunone_aimbot_cpp/overlay/draw_stats.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#define _WINSOCKAPI_ -#include -#include - -#include "imgui/imgui.h" -#include "sunone_aimbot_cpp.h" -#include "overlay.h" -#include "capture.h" - -void draw_stats() -{ - // all stages - static float preprocess_times[120] = {}; - static float inference_times[120] = {}; - static float copy_times[120] = {}; - static float postprocess_times[120] = {}; - static float nms_times[120] = {}; - static int index_inf = 0; - - float current_preprocess = 0.0f; - float current_inference = 0.0f; - float current_copy = 0.0f; - float current_post = 0.0f; - float current_nms = 0.0f; - - if (config.backend == "DML" && dml_detector) - { - //current_preprocess = static_cast(dml_detector->lastPreprocessTimeDML.count()); - //current_inference = static_cast(dml_detector->lastInferenceTimeDML.count()); - //current_copy = static_cast(dml_detector->lastCopyTimeDML.count()); - //current_post = static_cast(dml_detector->lastPostprocessTimeDML.count()); - //current_nms = static_cast(dml_detector->lastNmsTimeDML.count()); - } -#ifdef USE_CUDA - else - { - current_preprocess = static_cast(trt_detector.lastPreprocessTime.count()); - current_inference = static_cast(trt_detector.lastInferenceTime.count()); - current_copy = static_cast(trt_detector.lastCopyTime.count()); - current_post = static_cast(trt_detector.lastPostprocessTime.count()); - current_nms = static_cast(trt_detector.lastNmsTime.count()); - } -#endif - preprocess_times[index_inf] = current_preprocess; - inference_times[index_inf] = current_inference; - copy_times[index_inf] = current_copy; - postprocess_times[index_inf] = current_post; - nms_times[index_inf] = current_nms; - index_inf = (index_inf + 1) % IM_ARRAYSIZE(inference_times); - - auto avg = [](const float* arr, int n) -> float { - float sum = 0.0f; int cnt = 0; - for (int i = 0; i < n; ++i) if (arr[i] > 0.0f) { sum += arr[i]; ++cnt; } - return cnt ? sum / cnt : 0.0f; - }; - - float avg_preprocess = avg(preprocess_times, IM_ARRAYSIZE(preprocess_times)); - float avg_inference = avg(inference_times, IM_ARRAYSIZE(inference_times)); - float avg_copy = avg(copy_times, IM_ARRAYSIZE(copy_times)); - float avg_post = avg(postprocess_times, IM_ARRAYSIZE(postprocess_times)); - float avg_nms = avg(nms_times, IM_ARRAYSIZE(nms_times)); - - ImGui::SeparatorText("Time Breakdown"); - - ImGui::PlotLines("Preprocess", preprocess_times, IM_ARRAYSIZE(preprocess_times), index_inf, nullptr, 0.0f, 20.0f, ImVec2(0, 40)); - ImGui::SameLine(); ImGui::Text("%.2f | Avg: %.2f", current_preprocess, avg_preprocess); - - ImGui::PlotLines("Inference", inference_times, IM_ARRAYSIZE(inference_times), index_inf, nullptr, 0.0f, 20.0f, ImVec2(0, 40)); - ImGui::SameLine(); ImGui::Text("%.2f | Avg: %.2f", current_inference, avg_inference); - - ImGui::PlotLines("Copy", copy_times, IM_ARRAYSIZE(copy_times), index_inf, nullptr, 0.0f, 10.0f, ImVec2(0, 40)); - ImGui::SameLine(); ImGui::Text("%.2f | Avg: %.2f", current_copy, avg_copy); - - ImGui::PlotLines("Postprocess", postprocess_times, IM_ARRAYSIZE(postprocess_times), index_inf, nullptr, 0.0f, 10.0f, ImVec2(0, 40)); - ImGui::SameLine(); ImGui::Text("%.2f | Avg: %.2f", current_post, avg_post); - - ImGui::PlotLines("NMS", nms_times, IM_ARRAYSIZE(nms_times), index_inf, nullptr, 0.0f, 5.0f, ImVec2(0, 40)); - ImGui::SameLine(); ImGui::Text("%.2f | Avg: %.2f", current_nms, avg_nms); - - // Capture FPS - static float capture_fps_vals[120] = {}; - static int index_fps = 0; - - float current_fps = static_cast(captureFps.load()); - capture_fps_vals[index_fps] = current_fps; - index_fps = (index_fps + 1) % IM_ARRAYSIZE(capture_fps_vals); - - float sum_fps = 0.0f; - int count_fps = 0; - for (float f : capture_fps_vals) - { - if (f > 0.0f) { sum_fps += f; ++count_fps; } - } - float avg_fps = (count_fps > 0) ? (sum_fps / count_fps) : 0.0f; - - ImGui::SeparatorText("Capture FPS"); - ImGui::PlotLines("##fps_plot", capture_fps_vals, IM_ARRAYSIZE(capture_fps_vals), index_fps, nullptr, 0.0f, 144.0f, ImVec2(0, 60)); - ImGui::SameLine(); - ImGui::Text("Now: %.1f | Avg: %.1f", current_fps, avg_fps); -} diff --git a/sunone_aimbot_cpp/overlay/draw_target.cpp b/sunone_aimbot_cpp/overlay/draw_target.cpp deleted file mode 100644 index 4361c3d8..00000000 --- a/sunone_aimbot_cpp/overlay/draw_target.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#define _WINSOCKAPI_ -#include -#include - -#include "d3d11.h" -#include "imgui/imgui.h" - -#include "overlay.h" -#include "draw_settings.h" -#include "sunone_aimbot_cpp.h" -#include "other_tools.h" -#include "memory_images.h" - -ID3D11ShaderResourceView* bodyTexture = nullptr; -ImVec2 bodyImageSize; - -bool prev_disable_headshot = config.disable_headshot; -float prev_body_y_offset = config.body_y_offset; -float prev_head_y_offset = config.head_y_offset; -bool prev_ignore_third_person = config.ignore_third_person; -bool prev_shooting_range_targets = config.shooting_range_targets; -bool prev_focuse_target = config.focusTarget; -bool prev_auto_aim = config.auto_aim; -bool prev_target_lock_enabled = config.target_lock_enabled; -float prev_target_lock_distance = config.target_lock_distance; -float prev_target_lock_reacquire_time = config.target_lock_reacquire_time; -bool prev_easynorecoil = config.easynorecoil; -float prev_easynorecoilstrength = config.easynorecoilstrength; - -void draw_target() -{ - ImGui::Checkbox("Disable Headshot", &config.disable_headshot); - - ImGui::Separator(); - - ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Arrow keys: Adjust body offset"); - ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Shift+Arrow keys: Adjust head offset"); - - ImGui::SliderFloat("Approximate Body Y Offset", &config.body_y_offset, 0.0f, 1.0f, "%.2f"); - ImGui::SliderFloat("Approximate Head Y Offset", &config.head_y_offset, 0.0f, 1.0f, "%.2f"); - - if (bodyTexture) - { - ImGui::Image((void*)bodyTexture, bodyImageSize); - - ImVec2 image_pos = ImGui::GetItemRectMin(); - ImVec2 image_size = ImGui::GetItemRectSize(); - - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - - float normalized_body_value = (config.body_y_offset - 1.0f) / 1.0f; - float body_line_y = image_pos.y + (1.0f + normalized_body_value) * image_size.y; - ImVec2 body_line_start = ImVec2(image_pos.x, body_line_y); - ImVec2 body_line_end = ImVec2(image_pos.x + image_size.x, body_line_y); - draw_list->AddLine(body_line_start, body_line_end, IM_COL32(255, 0, 0, 255), 2.0f); - - float body_y_pos_at_015 = image_pos.y + (1.0f + (0.15f - 1.0f) / 1.0f) * image_size.y; - float head_top_pos = image_pos.y; - float head_line_y = head_top_pos + (config.head_y_offset * (body_y_pos_at_015 - head_top_pos)); - - ImVec2 head_line_start = ImVec2(image_pos.x, head_line_y); - ImVec2 head_line_end = ImVec2(image_pos.x + image_size.x, head_line_y); - draw_list->AddLine(head_line_start, head_line_end, IM_COL32(0, 255, 0, 255), 2.0f); - - draw_list->AddText(ImVec2(body_line_end.x + 5, body_line_y - 7), IM_COL32(255, 0, 0, 255), "Body"); - draw_list->AddText(ImVec2(head_line_end.x + 5, head_line_y - 7), IM_COL32(0, 255, 0, 255), "Head"); - } - else - { - ImGui::Text("Image not found!"); - } - ImGui::Text("Note: There is a different value for each game, as the sizes of the player models may vary."); - ImGui::Separator(); - ImGui::Checkbox("Ignore Third Person", &config.ignore_third_person); - ImGui::Checkbox("Shooting range targets", &config.shooting_range_targets); - ImGui::Checkbox("Focuse Target", &config.focusTarget); - ImGui::Checkbox("Auto Aim", &config.auto_aim); - ImGui::Checkbox("Smart Target Lock", &config.target_lock_enabled); - if (config.target_lock_enabled) - { - ImGui::SliderFloat("Lock Distance", &config.target_lock_distance, 20.0f, 400.0f, "%.1f"); - ImGui::SliderFloat("Reacquire Time (s)", &config.target_lock_reacquire_time, 0.05f, 2.0f, "%.2f"); - } - - if (prev_disable_headshot != config.disable_headshot || - prev_body_y_offset != config.body_y_offset || - prev_head_y_offset != config.head_y_offset || - prev_ignore_third_person != config.ignore_third_person || - prev_shooting_range_targets != config.shooting_range_targets || - prev_focuse_target != config.focusTarget || - prev_auto_aim != config.auto_aim || - prev_target_lock_enabled != config.target_lock_enabled || - prev_target_lock_distance != config.target_lock_distance || - prev_target_lock_reacquire_time != config.target_lock_reacquire_time || - prev_easynorecoil != config.easynorecoil || - prev_easynorecoilstrength != config.easynorecoilstrength) - { - prev_disable_headshot = config.disable_headshot; - prev_body_y_offset = config.body_y_offset; - prev_head_y_offset = config.head_y_offset; - prev_ignore_third_person = config.ignore_third_person; - prev_shooting_range_targets = config.shooting_range_targets; - prev_focuse_target = config.focusTarget; - prev_auto_aim = config.auto_aim; - prev_target_lock_enabled = config.target_lock_enabled; - prev_target_lock_distance = config.target_lock_distance; - prev_target_lock_reacquire_time = config.target_lock_reacquire_time; - prev_easynorecoil = config.easynorecoil; - prev_easynorecoilstrength = config.easynorecoilstrength; - config.saveConfig(); - } -} - -void load_body_texture() -{ - int image_width = 0; - int image_height = 0; - - std::string body_image = std::string(bodyImageBase64_1) + std::string(bodyImageBase64_2) + std::string(bodyImageBase64_3); - - bool ret = LoadTextureFromMemory(body_image, g_pd3dDevice, &bodyTexture, &image_width, &image_height); - if (!ret) - { - std::cerr << "[Overlay] Can't load image!" << std::endl; - } - else - { - bodyImageSize = ImVec2((float)image_width, (float)image_height); - } -} - -void release_body_texture() -{ - if (bodyTexture) - { - bodyTexture->Release(); - bodyTexture = nullptr; - } -} diff --git a/sunone_aimbot_cpp/overlay/overlay.cpp b/sunone_aimbot_cpp/overlay/overlay.cpp deleted file mode 100644 index 6d3097a1..00000000 --- a/sunone_aimbot_cpp/overlay/overlay.cpp +++ /dev/null @@ -1,432 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#define _WINSOCKAPI_ -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "overlay.h" -#include "overlay/draw_settings.h" -#include "config.h" -#include "keycodes.h" -#include "sunone_aimbot_cpp.h" -#include "capture.h" -#include "keyboard_listener.h" -#include "other_tools.h" -#include "virtual_camera.h" -#ifdef USE_CUDA -#include "trt_detector.h" -#endif - -ID3D11Device* g_pd3dDevice = NULL; -ID3D11DeviceContext* g_pd3dDeviceContext = NULL; -IDXGISwapChain* g_pSwapChain = NULL; -ID3D11RenderTargetView* g_mainRenderTargetView = NULL; -HWND g_hwnd = NULL; - -extern Config config; -extern std::mutex configMutex; -extern std::atomic shouldExit; - -bool CreateDeviceD3D(HWND hWnd); -void CleanupDeviceD3D(); -void CreateRenderTarget(); -void CleanupRenderTarget(); - -ID3D11BlendState* g_pBlendState = nullptr; -LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); -IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - -const int BASE_OVERLAY_WIDTH = 680; -const int BASE_OVERLAY_HEIGHT = 480; -int overlayWidth = 0; -int overlayHeight = 0; - -std::vector availableModels; -std::vector key_names; -std::vector key_names_cstrs; - -ID3D11ShaderResourceView* body_texture = nullptr; - -bool InitializeBlendState() -{ - D3D11_BLEND_DESC blendDesc; - ZeroMemory(&blendDesc, sizeof(blendDesc)); - - blendDesc.AlphaToCoverageEnable = FALSE; - blendDesc.RenderTarget[0].BlendEnable = TRUE; - blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; - blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - - HRESULT hr = g_pd3dDevice->CreateBlendState(&blendDesc, &g_pBlendState); - if (FAILED(hr)) - { - return false; - } - - float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f }; - g_pd3dDeviceContext->OMSetBlendState(g_pBlendState, blendFactor, 0xffffffff); - - return true; -} - -bool CreateDeviceD3D(HWND hWnd) -{ - DXGI_SWAP_CHAIN_DESC sd; - ZeroMemory(&sd, sizeof(sd)); - sd.BufferCount = 2; - sd.BufferDesc.Width = overlayWidth; - sd.BufferDesc.Height = overlayHeight; - sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - sd.BufferDesc.RefreshRate.Numerator = 0; - sd.BufferDesc.RefreshRate.Denominator = 0; - sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - sd.OutputWindow = hWnd; - sd.SampleDesc.Count = 1; - sd.SampleDesc.Quality = 0; - sd.Windowed = TRUE; - sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; - - UINT createDeviceFlags = 0; - - D3D_FEATURE_LEVEL featureLevel; - const D3D_FEATURE_LEVEL featureLevelArray[2] = - { - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_0, - }; - - HRESULT res = D3D11CreateDeviceAndSwapChain(NULL, - D3D_DRIVER_TYPE_HARDWARE, - NULL, - createDeviceFlags, - featureLevelArray, - 2, - D3D11_SDK_VERSION, - &sd, - &g_pSwapChain, - &g_pd3dDevice, - &featureLevel, - &g_pd3dDeviceContext); - if (res != S_OK) - return false; - - if (!InitializeBlendState()) - return false; - - CreateRenderTarget(); - return true; -} - -void CreateRenderTarget() -{ - ID3D11Texture2D* pBackBuffer = NULL; - g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); - g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_mainRenderTargetView); - pBackBuffer->Release(); -} - -void CleanupRenderTarget() -{ - if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = NULL; } -} - -void CleanupDeviceD3D() -{ - CleanupRenderTarget(); - if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = NULL; } - if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; } - if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; } - if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = nullptr; } -} - -LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) - return true; - - switch (msg) - { - case WM_SIZE: - if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED) - { - RECT rect; - GetWindowRect(hWnd, &rect); - UINT width = rect.right - rect.left; - UINT height = rect.bottom - rect.top; - - CleanupRenderTarget(); - g_pSwapChain->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0); - CreateRenderTarget(); - } - return 0; - case WM_DESTROY: - shouldExit = true; - ::PostQuitMessage(0); - return 0; - default: - return ::DefWindowProc(hWnd, msg, wParam, lParam); - } -} - -void SetupImGui() -{ - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - - ImGuiIO& io = ImGui::GetIO(); - io.FontGlobalScale = config.overlay_ui_scale; - - ImGui_ImplWin32_Init(g_hwnd); - ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); - - ImGui::StyleColorsDark(); - - load_body_texture(); -} - -bool CreateOverlayWindow() -{ - overlayWidth = static_cast(BASE_OVERLAY_WIDTH * config.overlay_ui_scale); - overlayHeight = static_cast(BASE_OVERLAY_HEIGHT * config.overlay_ui_scale); - - WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, - GetModuleHandle(NULL), NULL, NULL, NULL, NULL, - _T("Edge"), NULL }; - ::RegisterClassEx(&wc); - - g_hwnd = ::CreateWindowEx( - WS_EX_TOPMOST | WS_EX_LAYERED, - wc.lpszClassName, _T("Chrome"), - WS_POPUP, 0, 0, overlayWidth, overlayHeight, - NULL, NULL, wc.hInstance, NULL); - - if (g_hwnd == NULL) - return false; - - if (config.overlay_opacity <= 20) - { - config.overlay_opacity = 20; - config.saveConfig("config.ini"); - } - - if (config.overlay_opacity >= 256) - { - config.overlay_opacity = 255; - config.saveConfig("config.ini"); - } - - BYTE opacity = config.overlay_opacity; - - SetLayeredWindowAttributes(g_hwnd, 0, opacity, LWA_ALPHA); - - if (!CreateDeviceD3D(g_hwnd)) - { - CleanupDeviceD3D(); - ::UnregisterClass(wc.lpszClassName, wc.hInstance); - return false; - } - - return true; -} - -void OverlayThread() -{ - if (!CreateOverlayWindow()) - { - std::cout << "[Overlay] Can't create overlay window!" << std::endl; - return; - } - - SetupImGui(); - - bool show_overlay = false; - int prev_opacity = config.overlay_opacity; - - for (const auto& pair : KeyCodes::key_code_map) - { - key_names.push_back(pair.first); - } - std::sort(key_names.begin(), key_names.end()); - - key_names_cstrs.reserve(key_names.size()); - for (const auto& name : key_names) - { - key_names_cstrs.push_back(name.c_str()); - } - - std::vector availableModels = getAvailableModels(); - - MSG msg; - ZeroMemory(&msg, sizeof(msg)); - while (!shouldExit) - { - while (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) - { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - if (msg.message == WM_QUIT) - { - shouldExit = true; - return; - } - } - - if (isAnyKeyPressed(config.button_open_overlay) & 0x1) - { - show_overlay = !show_overlay; - - if (show_overlay) - { - ShowWindow(g_hwnd, SW_SHOW); - SetForegroundWindow(g_hwnd); - } - else - { - ShowWindow(g_hwnd, SW_HIDE); - } - - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - } - - if (show_overlay) - { - ImGui_ImplDX11_NewFrame(); - ImGui_ImplWin32_NewFrame(); - ImGui::NewFrame(); - - ImGui::SetNextWindowPos(ImVec2(0, 0)); - ImGui::SetNextWindowSize(ImVec2((float)overlayWidth, (float)overlayHeight)); - - ImGui::Begin("Options", &show_overlay, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar); - { - std::lock_guard lock(configMutex); - - if (ImGui::BeginTabBar("Options tab bar")) - { - if (ImGui::BeginTabItem("Capture")) - { - draw_capture_settings(); - - ImGui::EndTabItem(); - } - - if (ImGui::BeginTabItem("Target")) - { - draw_target(); - - ImGui::EndTabItem(); - } - - if (ImGui::BeginTabItem("Mouse")) - { - draw_mouse(); - - ImGui::EndTabItem(); - } - - if (ImGui::BeginTabItem("AI")) - { - draw_ai(); - - ImGui::EndTabItem(); - } - - if (ImGui::BeginTabItem("Buttons")) - { - draw_buttons(); - - ImGui::EndTabItem(); - } - - if (ImGui::BeginTabItem("Overlay")) - { - draw_overlay(); - - ImGui::EndTabItem(); - } - - if (ImGui::BeginTabItem("Stats")) - { - draw_stats(); - - ImGui::EndTabItem(); - } - - if (ImGui::BeginTabItem("Debug")) - { - draw_debug(); - - ImGui::EndTabItem(); - } - - if (prev_opacity != config.overlay_opacity) - { - BYTE opacity = config.overlay_opacity; - SetLayeredWindowAttributes(g_hwnd, 0, opacity, LWA_ALPHA); - config.saveConfig(); - } - - ImGui::EndTabBar(); - } - } - - ImGui::End(); - ImGui::Render(); - - const float clear_color_with_alpha[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL); - g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); - ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); - - HRESULT result = g_pSwapChain->Present(0, 0); - - if (result == DXGI_STATUS_OCCLUDED || result == DXGI_ERROR_ACCESS_LOST) - { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - else - { - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - } - } - - release_body_texture(); - - ImGui_ImplDX11_Shutdown(); - ImGui_ImplWin32_Shutdown(); - ImGui::DestroyContext(); - - CleanupDeviceD3D(); - ::DestroyWindow(g_hwnd); - ::UnregisterClass(_T("Edge"), GetModuleHandle(NULL)); -} - -int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ LPTSTR lpCmdLine, - _In_ int nCmdShow) -{ - std::thread overlay(OverlayThread); - overlay.join(); - return 0; -} diff --git a/sunone_aimbot_cpp/sunone_aimbot_cpp.cpp b/sunone_aimbot_cpp/sunone_aimbot_cpp.cpp deleted file mode 100644 index cda19ab8..00000000 --- a/sunone_aimbot_cpp/sunone_aimbot_cpp.cpp +++ /dev/null @@ -1,802 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#define _WINSOCKAPI_ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "capture.h" -#include "mouse.h" -#include "sunone_aimbot_cpp.h" -#include "keyboard_listener.h" -#include "overlay.h" -#include "other_tools.h" -#include "virtual_camera.h" - -std::condition_variable frameCV; -std::atomic shouldExit(false); -std::atomic aiming(false); -std::atomic detectionPaused(false); -std::mutex configMutex; - -#ifdef USE_CUDA -TrtDetector trt_detector; -#endif - - -DirectMLDetector* dml_detector = nullptr; -MouseThread* globalMouseThread = nullptr; -Config config; - -ColorDetector* color_detector = nullptr; -std::thread color_detThread; - -SerialConnection* arduinoSerial = nullptr; -KmboxConnection* kmboxSerial = nullptr; -KmboxNetConnection* kmboxNetSerial = nullptr; -MakcuConnection* makcu = nullptr; - -std::atomic detection_resolution_changed(false); -std::atomic capture_method_changed(false); -std::atomic capture_cursor_changed(false); -std::atomic capture_borders_changed(false); -std::atomic capture_fps_changed(false); -std::atomic capture_window_changed(false); -std::atomic detector_model_changed(false); -std::atomic show_window_changed(false); -std::atomic input_method_changed(false); - -std::atomic zooming(false); -std::atomic shooting(false); -std::atomic triggerbot_button(false); - - -//ERRORS: '(': illegal token on right side of '::' -//'exists': identifier not found -//'exists' : identifier not found -//'exists' : is not a member of 'std::filesystem' -//'exists' : is not a member of 'std::filesystem' -//'modelPath' uses undefined class 'std::filesystem::path' -// namespace "std::filesystem" has no member "exists" -//namespace "std::filesystem" has no member "exists" -//syntax error : ')' -//use of undefined type 'std::filesystem::path' -void createInputDevices() -{ - if (arduinoSerial) - { - delete arduinoSerial; - arduinoSerial = nullptr; - } - - if (kmboxSerial) - { - delete kmboxSerial; - kmboxSerial = nullptr; - } - - if (makcu) - { - delete makcu; - makcu = nullptr; - } - - if (kmboxNetSerial) - { - delete kmboxNetSerial; - kmboxNetSerial = nullptr; - } - - if (config.input_method == "ARDUINO") - { - std::cout << "[Mouse] Using Arduino method input." << std::endl; - arduinoSerial = new SerialConnection(config.arduino_port, config.arduino_baudrate); - } - else if (config.input_method == "KMBOX_B") - { - std::cout << "[Mouse] Using KMBOX_B method input." << std::endl; - kmboxSerial = new KmboxConnection(config.kmbox_b_port, config.kmbox_b_baudrate); - if (!kmboxSerial->isOpen()) - { - std::cerr << "[Kmbox] Error connecting to Kmbox serial." << std::endl; - delete kmboxSerial; - kmboxSerial = nullptr; - } - } - else if (config.input_method == "KMBOX_NET") - { - std::cout << "[Mouse] Using KMBOX_NET input." << std::endl; - kmboxNetSerial = new KmboxNetConnection(config.kmbox_net_ip, config.kmbox_net_port, config.kmbox_net_uuid); - if (!kmboxNetSerial->isOpen()) - { - std::cerr << "[KmboxNet] Error connecting." << std::endl; - delete kmboxNetSerial; kmboxNetSerial = nullptr; - } - } - else if (config.input_method == "MAKCU") - { - std::cout << "[Mouse] Using Makcu method input." << std::endl; - makcu = new MakcuConnection(config.makcu_port, config.makcu_baudrate); - if (!makcu->isOpen()) - { - std::cerr << "[Makcu] Error connecting to Makcu." << std::endl; - delete makcu; - makcu = nullptr; - } - } - else - { - std::cout << "[Mouse] Using default Win32 method input." << std::endl; - } -} - - -void assignInputDevices() -{ - if (globalMouseThread) - { - globalMouseThread->setSerialConnection(arduinoSerial); - globalMouseThread->setKmboxConnection(kmboxSerial); - globalMouseThread->setKmboxNetConnection(kmboxNetSerial); - globalMouseThread->setMakcuConnection(makcu); - } -} - -void handleEasyNoRecoil(MouseThread& mouseThread) -{ - if (config.easynorecoil && shooting.load() && zooming.load()) - { - std::lock_guard lock(mouseThread.input_method_mutex); - int recoil_compensation = static_cast(config.easynorecoilstrength); - - if (makcu) - { - makcu->move(0, recoil_compensation); - } - else if (arduinoSerial) - { - arduinoSerial->move(0, recoil_compensation); - } - else if (kmboxSerial) - { - kmboxSerial->move(0, recoil_compensation); - } - else if (kmboxNetSerial) - { - kmboxNetSerial->move(0, recoil_compensation); - } - else - { - INPUT input = { 0 }; - input.type = INPUT_MOUSE; - input.mi.dx = 0; - input.mi.dy = recoil_compensation; - input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK; - SendInput(1, &input, sizeof(INPUT)); - } - } -} - -void mouseThreadFunction(MouseThread& mouseThread) -{ - int lastVersion = -1; - - // Храним ID последней цели, чтобы не дёргался на нескольких - static cv::Rect lastTargetBox; - static bool hasLastTarget = false; - - // Булевое значение для выбора фиксированной или обычной наводки - bool fixTarget = config.focusTarget; // Это значение можно изменять в конфиге или вручную - - while (!shouldExit) - { - std::vector boxes; - std::vector classes; - - { - std::unique_lock lock(detectionBuffer.mutex); - detectionBuffer.cv.wait(lock, [&] { - return detectionBuffer.version > lastVersion || shouldExit; - }); - if (shouldExit) break; - boxes = detectionBuffer.boxes; - classes = detectionBuffer.classes; - lastVersion = detectionBuffer.version; - } - - if (input_method_changed.load()) - { - createInputDevices(); - assignInputDevices(); - input_method_changed.store(false); - } - - if (detection_resolution_changed.load()) - { - { - std::lock_guard cfgLock(configMutex); - mouseThread.updateConfig( - config.detection_resolution, - config.fovX, - config.fovY, - config.minSpeedMultiplier, - config.maxSpeedMultiplier, - config.predictionInterval, - config.auto_shoot, - config.bScope_multiplier, - config.triggerbot_bScope_multiplier - ); - mouseThread.setUseSmoothing(config.use_smoothing); - mouseThread.setUseKalman(config.use_kalman); - mouseThread.setSmoothnessValue(config.smoothness); - } - detection_resolution_changed.store(false); - } - - // Центр экрана - int screenCenterX = config.detection_resolution / 2; - int screenCenterY = config.detection_resolution / 2; - - struct TargetLockState - { - bool active{ false }; - uint64_t id{ 0 }; - cv::Point2d center{ 0.0, 0.0 }; - std::chrono::steady_clock::time_point lost_time{}; - }; - - static TargetLockState target_lock_state; - - auto reset_target_lock = [&]() - { - target_lock_state = TargetLockState{}; - }; - - if (!config.target_lock_enabled || (!aiming.load() && !config.auto_aim)) - { - reset_target_lock(); - } - - auto make_target_id = [](const cv::Rect& box, int grid) -> uint64_t - { - int x1 = (box.x / grid) * grid; - int y1 = (box.y / grid) * grid; - int x2 = ((box.x + box.width) / grid) * grid; - int y2 = ((box.y + box.height) / grid) * grid; - - uint64_t id = 0; - id |= (static_cast(x1) & 0xFFFF); - id |= (static_cast(y1) & 0xFFFF) << 16; - id |= (static_cast(x2) & 0xFFFF) << 32; - id |= (static_cast(y2) & 0xFFFF) << 48; - return id; - }; - - auto is_valid_target_class = [&](int cls) - { - if (config.disable_headshot && cls == config.class_head) - return false; - - return cls == config.class_player || - cls == config.class_bot || - (cls == config.class_hideout_target_human && config.shooting_range_targets) || - (cls == config.class_hideout_target_balls && config.shooting_range_targets) || - (cls == config.class_third_person && !config.ignore_third_person) || - cls == config.class_head; - }; - - bool lock_blocking = false; - int locked_idx = -1; - - if (config.target_lock_enabled) - { - const int lock_grid = 10; - const double lock_distance = std::max(1.0, static_cast(config.target_lock_distance)); - const double reacquire_time = std::max(0.0, static_cast(config.target_lock_reacquire_time)); - auto now = std::chrono::steady_clock::now(); - - if (boxes.empty() && target_lock_state.active) - { - if (target_lock_state.lost_time.time_since_epoch().count() == 0) - target_lock_state.lost_time = now; - - double lost_for = std::chrono::duration(now - target_lock_state.lost_time).count(); - if (lost_for >= reacquire_time) - reset_target_lock(); - else - lock_blocking = true; - } - else if (target_lock_state.active) - { - for (size_t i = 0; i < boxes.size(); ++i) - { - if (i >= classes.size() || !is_valid_target_class(classes[i])) - continue; - - if (make_target_id(boxes[i], lock_grid) == target_lock_state.id) - { - locked_idx = static_cast(i); - break; - } - } - - if (locked_idx == -1) - { - double best_dist = std::numeric_limits::max(); - for (size_t i = 0; i < boxes.size(); ++i) - { - if (i >= classes.size() || !is_valid_target_class(classes[i])) - continue; - - double cx = boxes[i].x + boxes[i].width * 0.5; - double cy = boxes[i].y + boxes[i].height * 0.5; - double dist = std::hypot(cx - target_lock_state.center.x, cy - target_lock_state.center.y); - if (dist < best_dist) - { - best_dist = dist; - locked_idx = static_cast(i); - } - } - - if (locked_idx != -1 && best_dist > lock_distance) - locked_idx = -1; - } - - if (locked_idx != -1) - { - double cx = boxes[locked_idx].x + boxes[locked_idx].width * 0.5; - double cy = boxes[locked_idx].y + boxes[locked_idx].height * 0.5; - target_lock_state.center = { cx, cy }; - target_lock_state.id = make_target_id(boxes[locked_idx], lock_grid); - target_lock_state.lost_time = std::chrono::steady_clock::time_point{}; - } - else - { - if (target_lock_state.lost_time.time_since_epoch().count() == 0) - target_lock_state.lost_time = now; - - double lost_for = std::chrono::duration(now - target_lock_state.lost_time).count(); - if (lost_for >= reacquire_time) - reset_target_lock(); - else - lock_blocking = true; - } - } - } - - // Если fixTarget включен и нет последней цели, фиксируем ближайшую к центру - if (!config.target_lock_enabled && fixTarget && !hasLastTarget && !boxes.empty()) - { - cv::Rect best = boxes[0]; - double bestDist = std::hypot(best.x + best.width / 2 - screenCenterX, best.y + best.height / 2 - screenCenterY); - - // Ищем ближайшую цель к центру экрана - for (auto& box : boxes) - { - double dist = std::hypot(box.x + box.width / 2 - screenCenterX, box.y + box.height / 2 - screenCenterY); - if (dist < bestDist) - { - bestDist = dist; - best = box; - } - } - - // Сохраняем выбранную цель как последнюю и фиксируем её - lastTargetBox = best; - hasLastTarget = true; - boxes.clear(); - boxes.push_back(best); - - std::cout << "[LOG] First target locked on center." << std::endl; - } - - // Если fixTarget включен и уже есть последняя цель, зафиксируем ближайшую к предыдущей, чтобы не дергался - if (!config.target_lock_enabled && fixTarget && boxes.size() > 1 && hasLastTarget) - { - cv::Rect best = boxes[0]; - double bestDist = std::hypot(best.x - lastTargetBox.x, best.y - lastTargetBox.y); - for (auto& box : boxes) - { - double dist = std::hypot(box.x - lastTargetBox.x, box.y - lastTargetBox.y); - if (dist < bestDist) - { - bestDist = dist; - best = box; - } - } - boxes.clear(); - boxes.push_back(best); - std::cout << "[LOG] Target locked on previous one." << std::endl; - } - - std::vector locked_boxes; - std::vector locked_classes; - const std::vector* boxes_ptr = &boxes; - const std::vector* classes_ptr = &classes; - - if (config.target_lock_enabled) - { - if (locked_idx != -1) - { - locked_boxes = { boxes[locked_idx] }; - locked_classes = { classes[locked_idx] }; - boxes_ptr = &locked_boxes; - classes_ptr = &locked_classes; - } - else if (lock_blocking) - { - boxes_ptr = nullptr; - classes_ptr = nullptr; - } - } - - // Стандартный выбор цели (если fixTarget выключен, выбираем любую цель) - AimbotTarget* target = nullptr; - if (boxes_ptr && classes_ptr) - { - target = sortTargets( - *boxes_ptr, - *classes_ptr, - config.detection_resolution, - config.detection_resolution, - config.disable_headshot - ); - } - - if (target) - { - mouseThread.setLastTargetTime(std::chrono::steady_clock::now()); - mouseThread.setTargetDetected(true); - - // сохраняем как «последнюю» цель - lastTargetBox = cv::Rect((int)target->x, (int)target->y, (int)target->w, (int)target->h); - hasLastTarget = true; - - if (config.target_lock_enabled) - { - const int lock_grid = 10; - target_lock_state.active = true; - target_lock_state.id = make_target_id(lastTargetBox, lock_grid); - target_lock_state.center = { target->pivotX, target->pivotY }; - target_lock_state.lost_time = std::chrono::steady_clock::time_point{}; - } - - auto futurePositions = mouseThread.predictFuturePositions( - target->pivotX, - target->pivotY, - config.prediction_futurePositions - ); - mouseThread.storeFuturePositions(futurePositions); - } - else - { - mouseThread.clearFuturePositions(); - mouseThread.setTargetDetected(false); - hasLastTarget = false; - } - - bool shouldPressAuto = false; - bool shouldPressTrigger = false; - bool triggerbotActive = config.triggerbot && triggerbot_button.load(); - static auto lastTriggerShot = std::chrono::steady_clock::now() - std::chrono::milliseconds(500); - static bool prev_has_target = false; - static cv::Point2d prev_center{ 0.0, 0.0 }; - static cv::Point2d vel{ 0.0, 0.0 }; - static auto prev_time = std::chrono::steady_clock::now(); - - bool triggerbotInScope = false; - if (target) - { - double cx = target->x + target->w * 0.5; - double cy = target->y + target->h * 0.5; - - auto now = std::chrono::steady_clock::now(); - double dt = prev_has_target ? std::chrono::duration(now - prev_time).count() : 0.0; - - double px = cx; - double py = cy; - if (config.triggerbot_predict_ms > 0.0 && prev_has_target && dt > 0.0) - { - double vx = (cx - prev_center.x) / dt; - double vy = (cy - prev_center.y) / dt; - double alpha = std::clamp(config.triggerbot_predict_alpha, 0.0, 1.0); - vel.x = vel.x + (vx - vel.x) * alpha; - vel.y = vel.y + (vy - vel.y) * alpha; - double lead_s = config.triggerbot_predict_ms / 1000.0; - px = cx + vel.x * lead_s; - py = cy + vel.y * lead_s; - } - else - { - vel = { 0.0, 0.0 }; - } - - prev_center = { cx, cy }; - prev_time = std::chrono::steady_clock::now(); - prev_has_target = true; - - double pred_x = px - target->w * 0.5; - double pred_y = py - target->h * 0.5; - triggerbotInScope = mouseThread.check_target_in_scope(pred_x, pred_y, target->w, target->h, config.triggerbot_bScope_multiplier); - } - else { - prev_has_target = false; - vel = { 0.0, 0.0 }; - } - - if (aiming && target) - { - mouseThread.moveMousePivot(target->pivotX, target->pivotY); - if (config.auto_shoot) - shouldPressAuto = true; - } - - if (triggerbotActive && triggerbotInScope) - { - auto now = std::chrono::steady_clock::now(); - double interval = config.triggerbot_interval; - if (interval <= 0.0 || now - lastTriggerShot >= std::chrono::duration(interval)) - { - shouldPressTrigger = true; - lastTriggerShot = now; - } - } - - if (target && (shouldPressAuto || shouldPressTrigger)) - { - if (shouldPressTrigger) - mouseThread.pressMouse(*target, config.triggerbot_bScope_multiplier); - else - mouseThread.pressMouse(*target); - } - else - { - mouseThread.releaseMouse(); - } - - handleEasyNoRecoil(mouseThread); - mouseThread.checkAndResetPredictions(); - - delete target; - } -} - - -int main() -{ - try - { -#ifdef USE_CUDA - int cuda_devices = 0; - if (cudaGetDeviceCount(&cuda_devices) != cudaSuccess || cuda_devices == 0) - { - std::cerr << "[MAIN] CUDA required but no devices found." << std::endl; - std::cin.get(); - return -1; - } -#endif - - SetConsoleOutputCP(CP_UTF8); - cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_FATAL); - - if (!CreateDirectory(L"screenshots", NULL) && GetLastError() != ERROR_ALREADY_EXISTS) - { - std::cout << "[MAIN] Error with screenshoot folder" << std::endl; - std::cin.get(); - return -1; - } - - if (!CreateDirectory(L"models", NULL) && GetLastError() != ERROR_ALREADY_EXISTS) - { - std::cout << "[MAIN] Error with models folder" << std::endl; - std::cin.get(); - return -1; - } - - if (!config.loadConfig()) - { - std::cerr << "[Config] Error with loading config!" << std::endl; - std::cin.get(); - return -1; - } - - if (config.capture_method == "virtual_camera") - { - auto cams = VirtualCameraCapture::GetAvailableVirtualCameras(); - if (!cams.empty()) - { - if (config.virtual_camera_name == "None" || - std::find(cams.begin(), cams.end(), config.virtual_camera_name) == cams.end()) - { - config.virtual_camera_name = cams[0]; - config.saveConfig("config.ini"); - std::cout << "[MAIN] Set virtual_camera_name = " << config.virtual_camera_name << std::endl; - } - std::cout << "[MAIN] Virtual cameras loaded: " << cams.size() << std::endl; - } - else - { - std::cerr << "[MAIN] No virtual cameras found" << std::endl; - } - } - - std::string modelPath = "models/" + config.ai_model; - - if (!std::filesystem::exists(modelPath)) - { - std::cerr << "[MAIN] Specified model does not exist: " << modelPath << std::endl; - - std::vector modelFiles = getModelFiles(); - - if (!modelFiles.empty()) - { - config.ai_model = modelFiles[0]; - config.saveConfig(); - std::cout << "[MAIN] Loaded first available model: " << config.ai_model << std::endl; - } - else - { - std::cerr << "[MAIN] No models found in 'models' directory." << std::endl; - std::cin.get(); - return -1; - } - } - - createInputDevices(); - - MouseThread mouseThread( - config.detection_resolution, - config.fovX, - config.fovY, - config.minSpeedMultiplier, - config.maxSpeedMultiplier, - config.predictionInterval, - config.auto_shoot, - config.bScope_multiplier, - config.triggerbot_bScope_multiplier, - arduinoSerial, - kmboxSerial, - kmboxNetSerial, - makcu - ); - - mouseThread.setUseSmoothing(config.use_smoothing); - mouseThread.setSmoothnessValue(config.smoothness); - mouseThread.setUseKalman(config.use_kalman); - - globalMouseThread = &mouseThread; - assignInputDevices(); - - std::vector availableModels = getAvailableModels(); - - if (!config.ai_model.empty()) - { - std::string modelPath = "models/" + config.ai_model; - if (!std::filesystem::exists(modelPath)) - { - std::cerr << "[MAIN] Specified model does not exist: " << modelPath << std::endl; - - if (!availableModels.empty()) - { - config.ai_model = availableModels[0]; - config.saveConfig("config.ini"); - std::cout << "[MAIN] Loaded first available model: " << config.ai_model << std::endl; - } - else - { - std::cerr << "[MAIN] No models found in 'models' directory." << std::endl; - std::cin.get(); - return -1; - } - } - } - else - { - if (!availableModels.empty()) - { - config.ai_model = availableModels[0]; - config.saveConfig(); - std::cout << "[MAIN] No AI model specified in config. Loaded first available model: " << config.ai_model << std::endl; - } - else - { - std::cerr << "[MAIN] No AI models found in 'models' directory." << std::endl; - std::cin.get(); - return -1; - } - } - - std::thread dml_detThread; - - if (config.backend == "DML") - { - dml_detector = new DirectMLDetector("models/" + config.ai_model); - std::cout << "[MAIN] DML detector initialized." << std::endl; - dml_detThread = std::thread(&DirectMLDetector::dmlInferenceThread, dml_detector); - } - else if (config.backend == "COLOR") - { - color_detector = new ColorDetector(); - std::cout << "[Capture] backend=" << config.backend << std::endl; - color_detector->initializeFromConfig(config); - std::cout << "[MAIN] Color detector initialized." << std::endl; - color_detThread = std::thread(&ColorDetector::inferenceThread, color_detector); - } -#ifdef USE_CUDA - else - { - trt_detector.initialize("models/" + config.ai_model); - } -#endif - - detection_resolution_changed.store(true); - - std::thread keyThread(keyboardListener); - std::thread capThread(captureThread, config.detection_resolution, config.detection_resolution); - -#ifdef USE_CUDA - std::thread trt_detThread(&TrtDetector::inferenceThread, &trt_detector); -#endif - std::thread mouseMovThread(mouseThreadFunction, std::ref(mouseThread)); - std::thread overlayThread(OverlayThread); - - welcome_message(); - - keyThread.join(); - capThread.join(); - if (dml_detThread.joinable()) - { - dml_detector->shouldExit = true; - dml_detector->inferenceCV.notify_all(); - dml_detThread.join(); - } - - if (color_detThread.joinable()) - { - color_detector->stop(); - color_detThread.join(); - delete color_detector; - color_detector = nullptr; - } - - -#ifdef USE_CUDA - trt_detThread.join(); -#endif - mouseMovThread.join(); - overlayThread.join(); - - if (arduinoSerial) - { - delete arduinoSerial; - } - - if (makcu) - { - delete makcu; - makcu = nullptr; - } - - if (dml_detector) - { - delete dml_detector; - dml_detector = nullptr; - } - - return 0; - } - catch (const std::exception& e) - { - std::cerr << "[MAIN] An error has occurred in the main stream: " << e.what() << std::endl; - std::cout << "Press Enter to exit..."; - std::cin.get(); - return -1; - } -}