diff --git a/AimmyWPF/AIModel.cs b/AimmyWPF/AIModel.cs index ffa59e4c..b67948dc 100644 --- a/AimmyWPF/AIModel.cs +++ b/AimmyWPF/AIModel.cs @@ -11,6 +11,7 @@ using System.Windows.Forms; using System; using System.Runtime.InteropServices; +using System.Diagnostics; namespace AimmyAimbot { @@ -35,24 +36,46 @@ public class AIModel public AIModel(string modelPath) { - try + _modeloptions = new RunOptions(); + + var sessionOptions = new SessionOptions { - _modeloptions = new RunOptions(); + EnableCpuMemArena = true, + EnableMemoryPattern = true, + GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_ALL, + ExecutionMode = ExecutionMode.ORT_PARALLEL + }; - var sessionOptions = new SessionOptions(); - sessionOptions.EnableCpuMemArena = true; - sessionOptions.EnableMemoryPattern = true; - sessionOptions.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_ALL; - sessionOptions.ExecutionMode = ExecutionMode.ORT_PARALLEL; + try + { sessionOptions.AppendExecutionProvider_DML(); - _onnxModel = new InferenceSession(modelPath, sessionOptions); _outputNames = _onnxModel.OutputMetadata.Keys.ToList(); } catch (Exception ex) { - MessageBox.Show($"There was an error starting the OnnxModel: {ex}"); - System.Windows.Application.Current.Shutdown(); + MessageBox.Show($"There was an error starting the OnnxModel via DirectML: {ex}\n\nProgram will attempt to use CPU only, performance may be poor.", "Model Error"); + try + { + sessionOptions.AppendExecutionProvider_CPU(); + _onnxModel = new InferenceSession(modelPath, sessionOptions); + _outputNames = _onnxModel.OutputMetadata.Keys.ToList(); + } + catch (Exception innerEx) + { + MessageBox.Show($"There was an error starting the model via CPU: {innerEx}", "Model Error"); + System.Windows.Application.Current.Shutdown(); + } + } + + // Checking output shape + foreach (var output in _onnxModel.OutputMetadata) + { + var shape = _onnxModel.OutputMetadata[output.Key].Dimensions; + if (shape.Length != 3 || shape[0] != 1 || shape[1] != 5 || shape[2] != 8400) + { + MessageBox.Show($"Output shape {string.Join("x", shape)} does not match the expected shape of 1x5x8400.\n\nThis model will not work with Aimmy, please use an ONNX V8 model.", "Model Error"); + } } } diff --git a/AimmyWPF/AimmyWPF.csproj b/AimmyWPF/AimmyWPF.csproj index dfe3e764..f5d3065f 100644 --- a/AimmyWPF/AimmyWPF.csproj +++ b/AimmyWPF/AimmyWPF.csproj @@ -32,6 +32,8 @@ + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -65,5 +67,5 @@ Settings.Designer.cs - + diff --git a/AimmyWPF/Class/Bools.cs b/AimmyWPF/Class/Bools.cs index 45a96064..35a52d81 100644 --- a/AimmyWPF/Class/Bools.cs +++ b/AimmyWPF/Class/Bools.cs @@ -9,6 +9,7 @@ namespace AimmyWPF.Class class Bools { public static bool AIAimAligner = false; + public static bool AIPredictions = false; public static bool ThirdPersonAim = false; public static bool Triggerbot = false; public static bool CollectDataWhilePlaying = false; diff --git a/AimmyWPF/MainWindow.xaml.cs b/AimmyWPF/MainWindow.xaml.cs index 44e43d9a..a6a8007e 100644 --- a/AimmyWPF/MainWindow.xaml.cs +++ b/AimmyWPF/MainWindow.xaml.cs @@ -16,19 +16,25 @@ using AimmyAimbot; using Class; using Newtonsoft.Json; +using System.Diagnostics; namespace AimmyWPF { public partial class MainWindow : Window { + private PredictionManager predictionManager; private OverlayWindow FOVOverlay; private FileSystemWatcher fileWatcher; + private FileSystemWatcher ConfigfileWatcher; + private string lastLoadedModel = "N/A"; + private string lastLoadedConfig = "N/A"; private readonly BrushConverter brushcolor = new BrushConverter(); private int TimeSinceLastClick = 0; private DateTime LastClickTime = DateTime.MinValue; + private const uint MOUSEEVENTF_LEFTDOWN = 0x0002; private const uint MOUSEEVENTF_LEFTUP = 0x0004; private const uint MOUSEEVENTF_MOVE = 0x0001; // Movement flag @@ -63,6 +69,7 @@ private enum MenuPosition private Dictionary toggleState = new Dictionary { { "AimbotToggle", false }, + { "PredictionToggle", false }, { "AimViewToggle", false }, { "TriggerBot", false }, { "CollectData", false }, @@ -95,20 +102,20 @@ public MainWindow() RequirementsManager RM = new RequirementsManager(); if (!RM.IsVCRedistInstalled()) { - System.Windows.MessageBox.Show("Visual C++ Redistributables x64 are not installed on this device, please install them before using Aimmy to avoid issues."); + System.Windows.MessageBox.Show("Visual C++ Redistributables x64 are not installed on this device, please install them before using Aimmy to avoid issues.", "Load Error"); System.Diagnostics.Process.Start("https://aka.ms/vs/17/release/vc_redist.x64.exe"); } // Check for required folders string baseDir = AppDomain.CurrentDomain.BaseDirectory; - string[] dirs = { "bin", "bin/models", "bin/images" }; + string[] dirs = { "bin", "bin/models", "bin/images", "bin/configs" }; foreach (string dir in dirs) { string fullPath = Path.Combine(baseDir, dir); if (!Directory.Exists(fullPath)) { - System.Windows.MessageBox.Show($"The '{dir}' folder does not exist, please ensure the folder is in the same directory as the exe."); + System.Windows.MessageBox.Show($"The '{dir}' folder does not exist, please ensure the folder is in the same directory as the exe.", "Load Error"); System.Windows.Application.Current.Shutdown(); } } @@ -145,16 +152,22 @@ public MainWindow() InitializeFileWatcher(); InitializeConfigWatcher(); + // Load PredictionManager + predictionManager = new PredictionManager(); + predictionManager.InitializeKalmanFilter(); + // Load all models into listbox LoadModelsIntoListBox(); LoadConfigsIntoListBox(); - //InitializeModel(); + SelectorListBox.SelectionChanged += new SelectionChangedEventHandler(SelectorListBox_SelectionChanged); ConfigSelectorListBox.SelectionChanged += new SelectionChangedEventHandler(ConfigSelectorListBox_SelectionChanged); + // Create FOV Overlay FOVOverlay = new OverlayWindow(); FOVOverlay.Hide(); FOVOverlay.FovSize = (int)aimmySettings["FOV_Size"]; + // Start the loop that runs the model Task.Run(() => StartModelCaptureLoop()); } @@ -246,7 +259,6 @@ public async Task ModelCapture(bool TriggerOnly = false) if (!TriggerOnly) { - // Scale the coordinates from the 640x640 image to the actual screen size float scaleX = (float)ScreenWidth / 640f; float scaleY = (float)ScreenHeight / 640f; @@ -255,9 +267,19 @@ public async Task ModelCapture(bool TriggerOnly = false) int detectedX = (int)((closestPrediction.Rectangle.X * scaleX) + XOffset); int detectedY = (int)((closestPrediction.Rectangle.Y * scaleY) + YOffset); - MoveCrosshair(detectedX, detectedY); + // Handle Prediction + if (toggleState["PredictionToggle"]) + { + predictionManager.UpdateKalmanFilter(detectedX, detectedY); + var predictedPosition = predictionManager.GetEstimatedPosition(); + MoveCrosshair(predictedPosition.X, predictedPosition.Y); + } + else + { + MoveCrosshair(detectedX, detectedY); + } } - else + else { Task.Run(() => DoTriggerClick()); } @@ -324,7 +346,7 @@ private void SetToggleState(AToggle toggle) // Stop them from turning on anything until model has been selected. if ((toggle.Reader.Name == "AimbotToggle" || toggle.Reader.Name == "TriggerBot" || toggle.Reader.Name == "CollectData") && lastLoadedModel == "N/A") { - System.Windows.MessageBox.Show("Please select a model in the Model Selector before toggling."); + System.Windows.MessageBox.Show("Please select a model in the Model Selector before toggling.", "Toggle Error"); return; } @@ -458,11 +480,6 @@ void LoadAimMenu() SetupToggle(Enable_AIAimAligner, state => Bools.AIAimAligner = state, Bools.AIAimAligner); AimScroller.Children.Add(Enable_AIAimAligner); - /*AToggle ThirdPersonAim = new AToggle("Enable Third Person Aim"); - ThirdPersonAim.Reader.Name = "AimViewToggle"; - SetupToggle(ThirdPersonAim, state => Bools.ThirdPersonAim = state, Bools.ThirdPersonAim); - AimScroller.Children.Add(ThirdPersonAim);*/ - AKeyChanger Change_KeyPress = new AKeyChanger("Change Keybind", "Right"); Change_KeyPress.Reader.Click += (s, x) => { @@ -477,6 +494,12 @@ void LoadAimMenu() AimScroller.Children.Add(Change_KeyPress); + AToggle Enable_AIPredictions = new AToggle(this, "Enable Predictions", + "This will use a KalmanFilter algorithm to predict aim patterns for better tracing of enemies."); + Enable_AIPredictions.Reader.Name = "PredictionToggle"; + SetupToggle(Enable_AIPredictions, state => Bools.AIPredictions = state, Bools.AIPredictions); + AimScroller.Children.Add(Enable_AIPredictions); + AToggle Show_FOV = new AToggle(this, "Show FOV", "This will show a circle around your screen that show what the AI is considering on the screen at a given moment."); Show_FOV.Reader.Name = "ShowFOV"; @@ -626,7 +649,6 @@ private void LoadModelsIntoListBox() SelectorListBox.Items.Add(fileName); } - // Preselect the first file in the ListBox if (SelectorListBox.Items.Count > 0) { if (!SelectorListBox.Items.Contains(lastLoadedModel) && lastLoadedModel != "N/A") @@ -640,11 +662,6 @@ private void LoadModelsIntoListBox() } SelectedModelNotifier.Content = "Loaded Model: " + lastLoadedModel; } - else - { - System.Windows.MessageBox.Show("No models found, please put a .onnx model in bin/models."); - System.Windows.Application.Current.Shutdown(); - } } private void SelectorListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) @@ -652,13 +669,9 @@ private void SelectorListBox_SelectionChanged(object sender, SelectionChangedEve InitializeModel(); } - // nori's config stuff, might need optimization later - - #region N4ri's Config Code (god please fix this) - void LoadConfig(string path) { - if (ConfigSelectorListBox.SelectedItem != null) + if (ConfigSelectorListBox.SelectedItem != null && lastLoadedModel != "N/A") { dynamic AimmyJSON = JsonConvert.DeserializeObject(File.ReadAllText(path)); @@ -666,14 +679,28 @@ void LoadConfig(string path) "\n" + AimmyJSON.Suggested_Model, "Suggested Model - Aimmy"); - aimmySettings["FOV_Size"] = AimmyJSON.FOV_Size; + aimmySettings["FOV_Size"] = (int)AimmyJSON.FOV_Size; + FOVOverlay.FovSize = (int)aimmySettings["FOV_Size"]; + _onnxModel.FovSize = (int)aimmySettings["FOV_Size"]; + aimmySettings["Mouse_Sens"] = AimmyJSON.Mouse_Sensitivity; aimmySettings["Y_Offset"] = AimmyJSON.Y_Offset; aimmySettings["X_Offset"] = AimmyJSON.X_Offset; aimmySettings["Trigger_Delay"] = AimmyJSON.Auto_Trigger_Delay; + aimmySettings["AI_Min_Conf"] = AimmyJSON.AI_Minimum_Confidence; + _onnxModel.ConfidenceThreshold = (float)(aimmySettings["AI_Min_Conf"] / 100.0f); + + lastLoadedConfig = ConfigSelectorListBox.SelectedItem.ToString(); + + // Reload the UI ReloadMenu(); } + else + { + ConfigSelectorListBox.SelectedItem = null; + System.Windows.MessageBox.Show("Please select a model in the Model Selector before loading a config.", "Config Error"); + } } void ReloadMenu() @@ -697,13 +724,13 @@ private void ConfigWatcher_Reload(object sender, FileSystemEventArgs e) private void InitializeConfigWatcher() { - fileWatcher = new FileSystemWatcher(); - fileWatcher.Path = "bin/configs"; - fileWatcher.Filter = "*.json"; - fileWatcher.EnableRaisingEvents = true; - fileWatcher.Created += ConfigWatcher_Reload; - fileWatcher.Deleted += ConfigWatcher_Reload; - fileWatcher.Renamed += ConfigWatcher_Reload; + ConfigfileWatcher = new FileSystemWatcher(); + ConfigfileWatcher.Path = "bin/configs"; + ConfigfileWatcher.Filter = "*.json"; + ConfigfileWatcher.EnableRaisingEvents = true; + ConfigfileWatcher.Created += ConfigWatcher_Reload; + ConfigfileWatcher.Deleted += ConfigWatcher_Reload; + ConfigfileWatcher.Renamed += ConfigWatcher_Reload; } private void LoadConfigsIntoListBox() @@ -717,42 +744,42 @@ private void LoadConfigsIntoListBox() ConfigSelectorListBox.Items.Add(fileName); } - // Preselect the first file in the ListBox if (ConfigSelectorListBox.Items.Count > 0) { - if (!ConfigSelectorListBox.Items.Contains(lastLoadedModel) && lastLoadedModel != "N/A") + if (!ConfigSelectorListBox.Items.Contains(lastLoadedConfig) && lastLoadedConfig != "N/A") { ConfigSelectorListBox.SelectedIndex = 0; - lastLoadedModel = ConfigSelectorListBox.Items[0].ToString(); + lastLoadedConfig = ConfigSelectorListBox.Items[0].ToString(); } else { - SelectorListBox.SelectedItem = lastLoadedModel; + ConfigSelectorListBox.SelectedItem = lastLoadedConfig; } - SelectedModelNotifier.Content = "Loaded Model: " + lastLoadedModel; - } - else - { - System.Windows.MessageBox.Show("No configs found, please put a .json file in bin/configs."); - System.Windows.Application.Current.Shutdown(); + SelectedConfigNotifier.Content = "Loaded Config: " + lastLoadedConfig; } } private void ConfigSelectorListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { - LoadConfig($"bin/configs/{ConfigSelectorListBox.SelectedItem.ToString()}"); + if (ConfigSelectorListBox.SelectedItem != null) + { + LoadConfig($"bin/configs/{ConfigSelectorListBox.SelectedItem.ToString()}"); + } } - #endregion void LoadModelStoreMenu() { if (AvailableModels.Count > 0) { foreach (var entries in AvailableModels) + { ModelStoreScroller.Children.Add(new ADownloadGateway(entries)); + } } else + { LackOfModelsText.Visibility = Visibility.Visible; + } } void LoadSettingsMenu() @@ -786,7 +813,7 @@ void LoadSettingsMenu() // Prevent double messageboxes.. if (AIMinimumConfidence.Slider.Value != aimmySettings["AI_Min_Conf"]) { - System.Windows.MessageBox.Show("Unable to set confidence, please select a model and try again."); + System.Windows.MessageBox.Show("Unable to set confidence, please select a model and try again.", "Slider Error"); AIMinimumConfidence.Slider.Value = aimmySettings["AI_Min_Conf"]; } } diff --git a/AimmyWPF/OverlayWindow.xaml.cs b/AimmyWPF/OverlayWindow.xaml.cs index 43f79f0d..2074c982 100644 --- a/AimmyWPF/OverlayWindow.xaml.cs +++ b/AimmyWPF/OverlayWindow.xaml.cs @@ -1,16 +1,11 @@ using System; using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Text; using System.Windows; using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; using System.Windows.Media; -using System.Windows.Media.Imaging; using System.Windows.Shapes; using System.Windows.Threading; +using static AimmyWPF.MainWindow; namespace AimmyWPF { @@ -25,7 +20,7 @@ public OverlayWindow() { InitializeComponent(); var timer = new DispatcherTimer(); - timer.Interval = TimeSpan.FromMilliseconds(100); + timer.Interval = TimeSpan.FromMilliseconds(250); timer.Tick += Timer_Tick; timer.Start(); } diff --git a/AimmyWPF/PredictionManager.cs b/AimmyWPF/PredictionManager.cs new file mode 100644 index 00000000..a40d7ee3 --- /dev/null +++ b/AimmyWPF/PredictionManager.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Accord.Math; +using Accord.Statistics.Filters; +using Accord.Statistics.Running; +using static Accord.Math.FourierTransform; + +namespace AimmyWPF +{ + internal class PredictionManager + { + public struct Detection + { + public int X; + public int Y; + public DateTime Timestamp; + } + + KalmanFilter2D kalmanFilter; + + public void InitializeKalmanFilter() + { + kalmanFilter = new KalmanFilter2D(); + } + + public void UpdateKalmanFilter(double detectedX, double detectedY) + { + kalmanFilter.Push(detectedX, detectedY); + } + + public Detection GetEstimatedPosition() + { + // Current estimated position + double currentX = kalmanFilter.X; + double currentY = kalmanFilter.Y; + + // Current velocity + double velocityX = kalmanFilter.XAxisVelocity; + double velocityY = kalmanFilter.YAxisVelocity; + + // Predict next position based on current position and velocity + double timeStep = 0.01; + double predictedX = currentX + velocityX * timeStep; + double predictedY = currentY + velocityY * timeStep; + + return new Detection { X = (int)predictedX, Y = (int)predictedY }; + } + } +} diff --git a/AimmyWPF/UserController/AInfoSection.xaml b/AimmyWPF/UserController/AInfoSection.xaml index 40df5785..03569871 100644 --- a/AimmyWPF/UserController/AInfoSection.xaml +++ b/AimmyWPF/UserController/AInfoSection.xaml @@ -91,7 +91,7 @@ materialDesign:ButtonAssist.CornerRadius="5" />