From 07f7ae263db402b28d6479079640fddc89e05c39 Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Sun, 22 Jan 2017 00:31:51 +0100 Subject: [PATCH] Add support for multiple processes per module Add ATS support --- Artemis/Artemis/Managers/LoopManager.cs | 530 +++++++++--------- Artemis/Artemis/Managers/MainManager.cs | 6 +- .../Artemis/Modules/Abstract/ModuleModel.cs | 4 +- .../Games/CounterStrike/CounterStrikeModel.cs | 2 +- .../CounterStrike/CounterStrikeView.xaml | 2 +- .../Artemis/Modules/Games/Dota2/Dota2Model.cs | 2 +- .../Modules/Games/Dota2/Dota2View.xaml | 2 +- .../EurotruckSimulator2Model.cs | 57 +- .../EurotruckSimulator2Settings.cs | 3 +- .../EurotruckSimulator2View.xaml | 52 +- .../EurotruckSimulator2ViewModel.cs | 32 +- .../Artemis/Modules/Games/GtaV/GtaVModel.cs | 2 +- .../Modules/Games/LightFx/LightFxModel.cs | 6 +- .../Modules/Games/Overwatch/OverwatchModel.cs | 2 +- .../Games/Overwatch/OverwatchView.xaml | 2 +- .../Games/ProjectCars/ProjectCarsModel.cs | 2 +- .../Games/RocketLeague/RocketLeagueModel.cs | 4 +- .../RocketLeague/RocketLeagueViewModel.cs | 2 - .../Games/TheDivision/TheDivisionModel.cs | 2 +- .../UnrealTournament/UnrealTournamentModel.cs | 2 +- .../UnrealTournamentView.xaml | 2 +- .../Modules/Games/Witcher3/Witcher3Model.cs | 2 +- Artemis/Artemis/Modules/Games/WoW/WoWModel.cs | 4 +- Artemis/Artemis/Utilities/ImageUtilities.cs | 1 + 24 files changed, 396 insertions(+), 329 deletions(-) diff --git a/Artemis/Artemis/Managers/LoopManager.cs b/Artemis/Artemis/Managers/LoopManager.cs index 85e66818f..b747a8512 100644 --- a/Artemis/Artemis/Managers/LoopManager.cs +++ b/Artemis/Artemis/Managers/LoopManager.cs @@ -1,271 +1,271 @@ -using System; -using System.Drawing; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Artemis.DeviceProviders; -using Artemis.ViewModels; -using Ninject.Extensions.Logging; -using Color = System.Drawing.Color; - -namespace Artemis.Managers -{ - /// - /// Manages the main programn loop - /// - public class LoopManager : IDisposable - { - private readonly DebugViewModel _debugViewModel; - private readonly DeviceManager _deviceManager; - private readonly ILogger _logger; - //private readonly Timer _loopTimer; - private readonly Task _loopTask; - private readonly ModuleManager _moduleManager; - - public LoopManager(ILogger logger, ModuleManager moduleManager, DeviceManager deviceManager, - DebugViewModel debugViewModel) - { - _logger = logger; - _moduleManager = moduleManager; - _deviceManager = deviceManager; - _debugViewModel = debugViewModel; - - // Setup timers - _loopTask = Task.Factory.StartNew(ProcessLoop); - _logger.Info("Intialized LoopManager"); - } - - public DebugViewModel DebugViewModel { get; set; } - - /// - /// Gets whether the loop is running - /// - public bool Running { get; private set; } - - public void Dispose() - { - _loopTask.Dispose(); - } - - private void ProcessLoop() - { - //TODO DarthAffe 14.01.2017: A stop-condition and a real cleanup instead of just aborting might be better - while (true) - { - try - { - long preUpdateTicks = DateTime.Now.Ticks; - - Render(); - - int sleep = (int)(40f - ((DateTime.Now.Ticks - preUpdateTicks) / 10000f)); - if (sleep > 0) - Thread.Sleep(sleep); - } - catch (Exception e) - { - _logger.Warn(e, "Exception in render loop"); - } - } - // ReSharper disable once FunctionNeverReturns - } - - public Task StartAsync() - { - return Task.Run(() => Start()); - } - - private void Start() - { - if (Running) - return; - - _logger.Debug("Starting LoopManager"); - - if (_deviceManager.ActiveKeyboard == null) - _deviceManager.EnableLastKeyboard(); - - while (_deviceManager.ChangingKeyboard) - Thread.Sleep(200); - - // If still null, no last keyboard, so stop. - if (_deviceManager.ActiveKeyboard == null) - { - _logger.Debug("Cancel LoopManager start, no keyboard"); - return; - } - - if (_moduleManager.ActiveModule == null) - { - var lastModule = _moduleManager.GetLastModule(); - if (lastModule == null) - { - _logger.Debug("Cancel LoopManager start, no module"); - return; - } - _moduleManager.ChangeActiveModule(lastModule); - } - - Running = true; - } - - public void Stop() - { - if (!Running) - return; - - _logger.Debug("Stopping LoopManager"); - Running = false; - - _deviceManager.ReleaseActiveKeyboard(); - } - - private void Render() - { - if (!Running || _deviceManager.ChangingKeyboard) - return; - - // Stop if no active module - if (_moduleManager.ActiveModule == null) - { - _logger.Debug("No active module, stopping"); - Stop(); - return; - } - var renderModule = _moduleManager.ActiveModule; - - // Stop if no active keyboard - if (_deviceManager.ActiveKeyboard == null) - { - _logger.Debug("No active keyboard, stopping"); - Stop(); - return; - } - - lock (_deviceManager.ActiveKeyboard) - { - // Skip frame if module is still initializing - if (renderModule.IsInitialized == false) - return; - - // ApplyProperties the current module - if (renderModule.IsInitialized) - renderModule.Update(); - - // Get the devices that must be rendered to - var mice = _deviceManager.MiceProviders.Where(m => m.CanUse).ToList(); - var headsets = _deviceManager.HeadsetProviders.Where(m => m.CanUse).ToList(); - var generics = _deviceManager.GenericProviders.Where(m => m.CanUse).ToList(); - var mousemats = _deviceManager.MousematProviders.Where(m => m.CanUse).ToList(); - - var keyboardOnly = !mice.Any() && !headsets.Any() && !generics.Any() && !mousemats.Any(); - - // Setup the frame for this tick - using (var frame = new RenderFrame(_deviceManager.ActiveKeyboard, mice.Any(), headsets.Any(), generics.Any(), mousemats.Any())) - { - if (renderModule.IsInitialized) - renderModule.Render(frame, keyboardOnly); - - // Draw enabled overlays on top of the renderModule - foreach (var overlayModel in _moduleManager.OverlayModules.Where(o => o.Settings.IsEnabled)) - { - overlayModel.Update(); - overlayModel.Render(frame, keyboardOnly); - } - - // Update the keyboard - _deviceManager.ActiveKeyboard?.DrawBitmap(frame.KeyboardBitmap); - - // Update the other devices - foreach (var mouse in mice) - mouse.UpdateDevice(frame.MouseBitmap); - foreach (var headset in headsets) - headset.UpdateDevice(frame.HeadsetBitmap); - foreach (var generic in generics) - generic.UpdateDevice(frame.GenericBitmap); - foreach (var mousemat in mousemats) - mousemat.UpdateDevice(frame.MousematBitmap); - - _debugViewModel.DrawFrame(frame); - - OnRenderCompleted(); - } - } - } - - public event EventHandler RenderCompleted; - - protected virtual void OnRenderCompleted() - { - RenderCompleted?.Invoke(this, EventArgs.Empty); - } - } - - public class RenderFrame : IDisposable - { - public RenderFrame(KeyboardProvider keyboard, bool renderMice, bool renderHeadsets, bool renderGenerics, bool renderMousemats) +using System; +using System.Drawing; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Artemis.DeviceProviders; +using Artemis.ViewModels; +using Ninject.Extensions.Logging; +using Color = System.Drawing.Color; + +namespace Artemis.Managers +{ + /// + /// Manages the main programn loop + /// + public class LoopManager : IDisposable + { + private readonly DebugViewModel _debugViewModel; + private readonly DeviceManager _deviceManager; + private readonly ILogger _logger; + //private readonly Timer _loopTimer; + private readonly Task _loopTask; + private readonly ModuleManager _moduleManager; + + public LoopManager(ILogger logger, ModuleManager moduleManager, DeviceManager deviceManager, + DebugViewModel debugViewModel) { - if (keyboard == null) - return; - - KeyboardBitmap = keyboard.KeyboardBitmap(); + _logger = logger; + _moduleManager = moduleManager; + _deviceManager = deviceManager; + _debugViewModel = debugViewModel; + + // Setup timers + _loopTask = Task.Factory.StartNew(ProcessLoop); + _logger.Info("Intialized LoopManager"); + } + + public DebugViewModel DebugViewModel { get; set; } + + /// + /// Gets whether the loop is running + /// + public bool Running { get; private set; } + + public void Dispose() + { + _loopTask.Dispose(); + } + + private void ProcessLoop() + { + //TODO DarthAffe 14.01.2017: A stop-condition and a real cleanup instead of just aborting might be better + while (true) + { + try + { + long preUpdateTicks = DateTime.Now.Ticks; + + Render(); + + int sleep = (int)(40f - ((DateTime.Now.Ticks - preUpdateTicks) / 10000f)); + if (sleep > 0) + Thread.Sleep(sleep); + } + catch (Exception e) + { + _logger.Warn(e, "Exception in render loop"); + } + } + // ReSharper disable once FunctionNeverReturns + } + + public Task StartAsync() + { + return Task.Run(() => Start()); + } + + private void Start() + { + if (Running) + return; + + _logger.Debug("Starting LoopManager"); + + if (_deviceManager.ActiveKeyboard == null) + _deviceManager.EnableLastKeyboard(); + + while (_deviceManager.ChangingKeyboard) + Thread.Sleep(200); + + // If still null, no last keyboard, so stop. + if (_deviceManager.ActiveKeyboard == null) + { + _logger.Debug("Cancel LoopManager start, no keyboard"); + return; + } + + if (_moduleManager.ActiveModule == null) + { + var lastModule = _moduleManager.GetLastModule(); + if (lastModule == null) + { + _logger.Debug("Cancel LoopManager start, no module"); + return; + } + _moduleManager.ChangeActiveModule(lastModule); + } + + Running = true; + } + + public void Stop() + { + if (!Running) + return; + + _logger.Debug("Stopping LoopManager"); + Running = false; + + _deviceManager.ReleaseActiveKeyboard(); + } + + private void Render() + { + if (!Running || _deviceManager.ChangingKeyboard) + return; + + // Stop if no active module + if (_moduleManager.ActiveModule == null) + { + _logger.Debug("No active module, stopping"); + Stop(); + return; + } + var renderModule = _moduleManager.ActiveModule; + + // Stop if no active keyboard + if (_deviceManager.ActiveKeyboard == null) + { + _logger.Debug("No active keyboard, stopping"); + Stop(); + return; + } + + lock (_deviceManager.ActiveKeyboard) + { + // Skip frame if module is still initializing + if (renderModule.IsInitialized == false) + return; + + // ApplyProperties the current module + if (renderModule.IsInitialized) + renderModule.Update(); + + // Get the devices that must be rendered to + var mice = _deviceManager.MiceProviders.Where(m => m.CanUse).ToList(); + var headsets = _deviceManager.HeadsetProviders.Where(m => m.CanUse).ToList(); + var generics = _deviceManager.GenericProviders.Where(m => m.CanUse).ToList(); + var mousemats = _deviceManager.MousematProviders.Where(m => m.CanUse).ToList(); + + var keyboardOnly = !mice.Any() && !headsets.Any() && !generics.Any() && !mousemats.Any(); + + // Setup the frame for this tick + using (var frame = new RenderFrame(_deviceManager.ActiveKeyboard, mice.Any(), headsets.Any(), generics.Any(), mousemats.Any())) + { + if (renderModule.IsInitialized) + renderModule.Render(frame, keyboardOnly); + + // Draw enabled overlays on top of the renderModule + foreach (var overlayModel in _moduleManager.OverlayModules.Where(o => o.Settings.IsEnabled)) + { + overlayModel.Update(); + overlayModel.Render(frame, keyboardOnly); + } + + // Update the keyboard + _deviceManager.ActiveKeyboard?.DrawBitmap(frame.KeyboardBitmap); + + // Update the other devices + foreach (var mouse in mice) + mouse.UpdateDevice(frame.MouseBitmap); + foreach (var headset in headsets) + headset.UpdateDevice(frame.HeadsetBitmap); + foreach (var generic in generics) + generic.UpdateDevice(frame.GenericBitmap); + foreach (var mousemat in mousemats) + mousemat.UpdateDevice(frame.MousematBitmap); + + _debugViewModel.DrawFrame(frame); + + OnRenderCompleted(); + } + } + } + + public event EventHandler RenderCompleted; + + protected virtual void OnRenderCompleted() + { + RenderCompleted?.Invoke(this, EventArgs.Empty); + } + } + + public class RenderFrame : IDisposable + { + public RenderFrame(KeyboardProvider keyboard, bool renderMice, bool renderHeadsets, bool renderGenerics, bool renderMousemats) + { + if (keyboard == null) + return; + + KeyboardBitmap = keyboard.KeyboardBitmap(); KeyboardBitmap.SetResolution(96, 96); - using (var g = Graphics.FromImage(KeyboardBitmap)) - { - g.Clear(Color.Black); - } - - if (renderMice) - { - MouseBitmap = new Bitmap(10, 10); - MouseBitmap.SetResolution(96, 96); - using (var g = Graphics.FromImage(MouseBitmap)) - { - g.Clear(Color.Black); - } - } - if (renderHeadsets) - { - HeadsetBitmap = new Bitmap(10, 10); - HeadsetBitmap.SetResolution(96, 96); - using (var g = Graphics.FromImage(HeadsetBitmap)) - { - g.Clear(Color.Black); - } - } - if (renderGenerics) - { - GenericBitmap = new Bitmap(10, 10); - GenericBitmap.SetResolution(96, 96); - using (var g = Graphics.FromImage(GenericBitmap)) - { - g.Clear(Color.Black); - } - } - if (renderMousemats) - { - MousematBitmap = new Bitmap(10, 10); - MousematBitmap.SetResolution(96, 96); + using (var g = Graphics.FromImage(KeyboardBitmap)) + { + g.Clear(Color.Black); + } + + if (renderMice) + { + MouseBitmap = new Bitmap(10, 10); + MouseBitmap.SetResolution(96, 96); + using (var g = Graphics.FromImage(MouseBitmap)) + { + g.Clear(Color.Black); + } + } + if (renderHeadsets) + { + HeadsetBitmap = new Bitmap(10, 10); + HeadsetBitmap.SetResolution(96, 96); + using (var g = Graphics.FromImage(HeadsetBitmap)) + { + g.Clear(Color.Black); + } + } + if (renderGenerics) + { + GenericBitmap = new Bitmap(10, 10); + GenericBitmap.SetResolution(96, 96); + using (var g = Graphics.FromImage(GenericBitmap)) + { + g.Clear(Color.Black); + } + } + if (renderMousemats) + { + MousematBitmap = new Bitmap(10, 10); + MousematBitmap.SetResolution(96, 96); using (var g = Graphics.FromImage(MousematBitmap)) { g.Clear(Color.Black); - } - } - } - - public Bitmap KeyboardBitmap { get; set; } - public Bitmap MouseBitmap { get; set; } - public Bitmap HeadsetBitmap { get; set; } - public Bitmap GenericBitmap { get; set; } - public Bitmap MousematBitmap { get; set; } - - public void Dispose() - { - KeyboardBitmap?.Dispose(); - MouseBitmap?.Dispose(); - HeadsetBitmap?.Dispose(); - GenericBitmap?.Dispose(); - MousematBitmap?.Dispose(); - } - } + } + } + } + + public Bitmap KeyboardBitmap { get; set; } + public Bitmap MouseBitmap { get; set; } + public Bitmap HeadsetBitmap { get; set; } + public Bitmap GenericBitmap { get; set; } + public Bitmap MousematBitmap { get; set; } + + public void Dispose() + { + KeyboardBitmap?.Dispose(); + MouseBitmap?.Dispose(); + HeadsetBitmap?.Dispose(); + GenericBitmap?.Dispose(); + MousematBitmap?.Dispose(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Managers/MainManager.cs b/Artemis/Artemis/Managers/MainManager.cs index 7a3fc7635..bd4c4b00f 100644 --- a/Artemis/Artemis/Managers/MainManager.cs +++ b/Artemis/Artemis/Managers/MainManager.cs @@ -144,7 +144,7 @@ namespace Artemis.Managers if (!ProgramEnabled) return; - var processes = System.Diagnostics.Process.GetProcesses(); + var processes = System.Diagnostics.Process.GetProcesses().Where(p => !p.HasExited).ToList(); var module = ModuleManager.ActiveModule; // If the current active module is in preview-mode, leave it alone @@ -158,7 +158,7 @@ namespace Artemis.Managers ModuleManager.DisableProcessBoundModule(); // If the currently active effect is a no longer running game, get rid of it. - if (!processes.Any(p => p.ProcessName == module.ProcessName && p.HasExited == false)) + if (!processes.Any(p => module.ProcessNames.Contains(p.ProcessName))) { Logger.Info("Disabling process bound module because process stopped: {0}", module.Name); ModuleManager.DisableProcessBoundModule(); @@ -167,7 +167,7 @@ namespace Artemis.Managers // Look for running games, stopping on the first one that's found. var newModule = ModuleManager.ProcessModules.Where(g => g.Settings.IsEnabled && g.Settings.IsEnabled) - .FirstOrDefault(g => processes.Any(p => p.ProcessName == g.ProcessName && p.HasExited == false)); + .FirstOrDefault(g => processes.Any(p => g.ProcessNames.Contains(p.ProcessName))); if (newModule == null || module == newModule) return; diff --git a/Artemis/Artemis/Modules/Abstract/ModuleModel.cs b/Artemis/Artemis/Modules/Abstract/ModuleModel.cs index 299421c01..13776b9ab 100644 --- a/Artemis/Artemis/Modules/Abstract/ModuleModel.cs +++ b/Artemis/Artemis/Modules/Abstract/ModuleModel.cs @@ -79,9 +79,9 @@ namespace Artemis.Modules.Abstract public List PreviewLayers { get; set; } /// - /// The process the module is bound to + /// The processes the module is bound to /// - public string ProcessName { get; protected set; } + public List ProcessNames { get; protected set; } = new List(); /// /// The currently active profile of the module diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs index 284436c60..dd80b03d7 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs @@ -28,7 +28,7 @@ namespace Artemis.Modules.Games.CounterStrike Settings = SettingsProvider.Load(); DataModel = new CounterStrikeDataModel(); - ProcessName = "csgo"; + ProcessNames.Add("csgo"); FindGameDir(); PlaceConfigFile(); diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeView.xaml b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeView.xaml index fe03c3f47..1bdbd9807 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeView.xaml +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeView.xaml @@ -48,7 +48,7 @@ cal:Message.Attach="[Event LostFocus] = [Action PlaceConfigFile]" />