diff --git a/.gitignore b/.gitignore index 0922ac1a4..a6e8a9467 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ x64/ x86/ build/ +debug/ bld/ [Bb]in/ [Oo]bj/ @@ -190,4 +191,4 @@ FakesAssemblies/ # Visual Studio 6 workspace options file *.opt -*.opendb +*.opendb diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index b56f3704b..6ee49f2d7 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -191,9 +191,6 @@ ..\packages\MahApps.Metro.1.3.0\lib\net45\MahApps.Metro.dll True - - False - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll True @@ -339,11 +336,9 @@ + - - - @@ -357,6 +352,7 @@ + @@ -382,6 +378,14 @@ GtaVView.xaml + + + + + + LightFxView.xaml + + @@ -499,22 +503,25 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -837,6 +844,10 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + Designer MSBuild:Compile diff --git a/Artemis/Artemis/ArtemisBootstrapper.cs b/Artemis/Artemis/ArtemisBootstrapper.cs index 754eed3cc..e15174d44 100644 --- a/Artemis/Artemis/ArtemisBootstrapper.cs +++ b/Artemis/Artemis/ArtemisBootstrapper.cs @@ -77,8 +77,7 @@ namespace Artemis protected override void Configure() { - _kernel = new StandardKernel(new BaseModules(), new ManagerModules(), new DeviceModules(), - new EffectModules(), new ProfileModules()); + _kernel = new StandardKernel(new BaseModules(), new ManagerModules()); _kernel.Bind().To().InSingletonScope(); _kernel.Bind().To().InSingletonScope(); diff --git a/Artemis/Artemis/DAL/ProfileProvider.cs b/Artemis/Artemis/DAL/ProfileProvider.cs index 1e0a61dca..5b757726e 100644 --- a/Artemis/Artemis/DAL/ProfileProvider.cs +++ b/Artemis/Artemis/DAL/ProfileProvider.cs @@ -67,7 +67,7 @@ namespace Artemis.DAL lock (prof) { // Store the file - if (!(prof.GameName?.Length > 1) || !(prof.KeyboardSlug?.Length > 1) || !(prof.Name?.Length > 1)) + if (!(prof.GameName?.Length > 1) || !(prof.KeyboardSlug?.Length > 1) || !(prof.Slug?.Length > 1)) throw new ArgumentException("Profile is invalid. Name, GameName and KeyboardSlug are required"); var path = ProfileFolder + $@"\{prof.KeyboardSlug}\{prof.GameName}"; @@ -84,11 +84,11 @@ namespace Artemis.DAL } catch (Exception e) { - Logger.Error(e, "Couldn't save profile '{0}.json'", prof.Name); + Logger.Error(e, "Couldn't save profile '{0}.json'", prof.Slug); return; } - File.WriteAllText(path + $@"\{prof.Name}.json", json); + File.WriteAllText(path + $@"\{prof.Slug}.json", json); Logger.Debug("Saved profile {0}/{1}/{2}", prof.KeyboardSlug, prof.GameName, prof.Name); } } @@ -114,7 +114,7 @@ namespace Artemis.DAL public static void DeleteProfile(ProfileModel prof) { // Remove the file - var path = ProfileFolder + $@"\{prof.KeyboardSlug}\{prof.GameName}\{prof.Name}.json"; + var path = ProfileFolder + $@"\{prof.KeyboardSlug}\{prof.GameName}\{prof.Slug}.json"; if (File.Exists(path)) File.Delete(path); } diff --git a/Artemis/Artemis/DeviceProviders/Corsair/CorsairHeadset.cs b/Artemis/Artemis/DeviceProviders/Corsair/CorsairHeadset.cs index 503c7e16f..908d4ae07 100644 --- a/Artemis/Artemis/DeviceProviders/Corsair/CorsairHeadset.cs +++ b/Artemis/Artemis/DeviceProviders/Corsair/CorsairHeadset.cs @@ -8,7 +8,7 @@ using Ninject.Extensions.Logging; namespace Artemis.DeviceProviders.Corsair { - internal class CorsairHeadset : DeviceProvider + public class CorsairHeadset : DeviceProvider { public CorsairHeadset(ILogger logger) { @@ -22,7 +22,7 @@ namespace Artemis.DeviceProviders.Corsair { CanUse = CanInitializeSdk(); if (CanUse && !CueSDK.IsInitialized) - CueSDK.Initialize(true); + CueSDK.Initialize(); Logger.Debug("Attempted to enable Corsair headset. CanUse: {0}", CanUse); diff --git a/Artemis/Artemis/DeviceProviders/Corsair/CorsairKeyboard.cs b/Artemis/Artemis/DeviceProviders/Corsair/CorsairKeyboard.cs index 3b8f30b7a..0dd0f2f32 100644 --- a/Artemis/Artemis/DeviceProviders/Corsair/CorsairKeyboard.cs +++ b/Artemis/Artemis/DeviceProviders/Corsair/CorsairKeyboard.cs @@ -1,150 +1,160 @@ -using System; -using System.Drawing; -using System.Linq; -using System.Windows; -using System.Windows.Forms; -using Artemis.DeviceProviders.Corsair.Utilities; -using Artemis.Properties; -using Artemis.Utilities; -using CUE.NET; -using CUE.NET.Brushes; -using CUE.NET.Devices.Generic; -using CUE.NET.Devices.Generic.Enums; -using CUE.NET.Helper; -using Ninject.Extensions.Logging; -using Point = System.Drawing.Point; - -namespace Artemis.DeviceProviders.Corsair -{ - public class CorsairKeyboard : KeyboardProvider - { - private CUE.NET.Devices.Keyboard.CorsairKeyboard _keyboard; - private ImageBrush _keyboardBrush; - - public CorsairKeyboard(ILogger logger) - { - Logger = logger; - Name = "Corsair RGB Keyboard"; - CantEnableText = "Couldn't connect to your Corsair keyboard.\n" + - "Please check your cables and/or drivers (could be outdated) and that Corsair Utility Engine is running.\n" + - "In CUE, make sure \"Enable SDK\" is checked under Global Settings.\n\n" + - "If needed, you can select a different keyboard in Artemis under settings."; - } - - public ILogger Logger { get; set; } - - public override bool CanEnable() - { - return CueSDK.IsSDKAvailable(CorsairDeviceType.Keyboard); - } - - /// - /// Enables the SDK and sets updatemode to manual as well as the color of the background to black. - /// - public override void Enable() - { - if (!CueSDK.IsInitialized) - CueSDK.Initialize(true); - - CueSDK.UpdateMode = UpdateMode.Manual; - _keyboard = CueSDK.KeyboardSDK; - switch (_keyboard.DeviceInfo.Model) - { - case "K95 RGB": - Height = 7; - Width = 25; - Slug = "corsair-k95-rgb"; - PreviewSettings = new PreviewSettings(676, 190, new Thickness(0, -15, 0, 0), Resources.k95); - break; - case "K70 RGB": - case "K70 RGB RAPIDFIRE": - case "K70 LUX RGB": - Height = 7; - Width = 21; - Slug = "corsair-k70-rgb"; - PreviewSettings = new PreviewSettings(676, 210, new Thickness(0, -25, 0, 0), Resources.k70); - break; - case "K65 RGB": - case "CGK65 RGB": - case "K65 LUX RGB": - case "K65 RGB RAPIDFIRE": - Height = 7; - Width = 18; - Slug = "corsair-k65-rgb"; - PreviewSettings = new PreviewSettings(610, 240, new Thickness(0, -30, 0, 0), Resources.k65); - break; - case "STRAFE RGB": - Height = 7; - Width = 22; - Slug = "corsair-strafe-rgb"; - PreviewSettings = new PreviewSettings(665, 215, new Thickness(0, -5, 0, 0), Resources.strafe); - break; - } - - Logger.Debug("Corsair SDK reported device as: {0}", _keyboard.DeviceInfo.Model); - _keyboard.Brush = _keyboardBrush ?? (_keyboardBrush = new ImageBrush()); - } - - public override void Disable() - { - if (CueSDK.IsInitialized) - CueSDK.Reinitialize(); - } - - /// - /// Properly resizes any size bitmap to the keyboard by creating a rectangle whose size is dependent on the bitmap - /// size. - /// - /// - public override void DrawBitmap(Bitmap bitmap) - { - using (var image = ImageUtilities.ResizeImage(bitmap, Width, Height)) - { - // For STRAFE, stretch the image on row 2. - if (_keyboard.DeviceInfo.Model == "STRAFE RGB") - { - using (var strafeBitmap = new Bitmap(22, 8)) - { - using (var g = Graphics.FromImage(strafeBitmap)) - { - g.DrawImage(image, new Point(0, 0)); - g.DrawImage(image, new Rectangle(0, 3, 22, 7), new Rectangle(0, 2, 22, 7), - GraphicsUnit.Pixel); - - _keyboardBrush.Image = strafeBitmap; - _keyboard.Update(); - } - } - } - else - { - _keyboardBrush.Image = image; - _keyboard.Update(); - } - } - } - - public override KeyMatch? GetKeyPosition(Keys keyCode) - { - var widthMultiplier = Width/_keyboard.Brush.RenderedRectangle.Width; - var heightMultiplier = Height/_keyboard.Brush.RenderedRectangle.Height; - - CorsairLed cueLed = null; - try - { - cueLed = _keyboard.Leds.FirstOrDefault(k => k.Id.ToString() == keyCode.ToString()) ?? - _keyboard.Leds.FirstOrDefault(k => k.Id == KeyMap.FormsKeys[keyCode]); - } - catch (Exception) - { - // ignored - } - - if (cueLed == null) - return null; - - var center = cueLed.LedRectangle.GetCenter(); - return new KeyMatch(keyCode, (int) (center.X*widthMultiplier), (int) (center.Y*heightMultiplier)); - } - } +using System; +using System.Drawing; +using System.Linq; +using System.Windows; +using System.Windows.Forms; +using Artemis.DeviceProviders.Corsair.Utilities; +using Artemis.Properties; +using Artemis.Utilities; +using CUE.NET; +using CUE.NET.Brushes; +using CUE.NET.Devices.Generic; +using CUE.NET.Devices.Generic.Enums; +using CUE.NET.Exceptions; +using CUE.NET.Helper; +using Ninject.Extensions.Logging; +using Point = System.Drawing.Point; + +namespace Artemis.DeviceProviders.Corsair +{ + public class CorsairKeyboard : KeyboardProvider + { + private CUE.NET.Devices.Keyboard.CorsairKeyboard _keyboard; + private ImageBrush _keyboardBrush; + + public CorsairKeyboard(ILogger logger) + { + Logger = logger; + Name = "Corsair RGB Keyboard"; + CantEnableText = "Couldn't connect to your Corsair keyboard.\n" + + "Please check your cables and/or drivers (could be outdated) and that Corsair Utility Engine is running.\n" + + "In CUE, make sure \"Enable SDK\" is checked under Global Settings.\n\n" + + "If needed, you can select a different keyboard in Artemis under settings."; + } + + public ILogger Logger { get; set; } + + public override bool CanEnable() + { + return CueSDK.IsSDKAvailable(CorsairDeviceType.Keyboard); + } + + /// + /// Enables the SDK and sets updatemode to manual as well as the color of the background to black. + /// + public override void Enable() + { + if (!CueSDK.IsInitialized) + CueSDK.Initialize(); + + CueSDK.UpdateMode = UpdateMode.Manual; + _keyboard = CueSDK.KeyboardSDK; + switch (_keyboard.DeviceInfo.Model) + { + case "K95 RGB": + Height = 7; + Width = 25; + Slug = "corsair-k95-rgb"; + PreviewSettings = new PreviewSettings(676, 190, new Thickness(0, -15, 0, 0), Resources.k95); + break; + case "K70 RGB": + case "K70 RGB RAPIDFIRE": + case "K70 LUX RGB": + Height = 7; + Width = 21; + Slug = "corsair-k70-rgb"; + PreviewSettings = new PreviewSettings(676, 210, new Thickness(0, -25, 0, 0), Resources.k70); + break; + case "K65 RGB": + case "CGK65 RGB": + case "K65 LUX RGB": + case "K65 RGB RAPIDFIRE": + Height = 7; + Width = 18; + Slug = "corsair-k65-rgb"; + PreviewSettings = new PreviewSettings(610, 240, new Thickness(0, -30, 0, 0), Resources.k65); + break; + case "STRAFE RGB": + Height = 7; + Width = 22; + Slug = "corsair-strafe-rgb"; + PreviewSettings = new PreviewSettings(665, 215, new Thickness(0, -5, 0, 0), Resources.strafe); + break; + } + + Logger.Debug("Corsair SDK reported device as: {0}", _keyboard.DeviceInfo.Model); + _keyboard.Brush = _keyboardBrush ?? (_keyboardBrush = new ImageBrush()); + } + + public override void Disable() + { + try + { + if (CueSDK.IsInitialized) + CueSDK.Reinitialize(); + } + catch (WrapperException e) + { + // This occurs when releasing the SDK after sleep, ignore it + if (e.Message != "The previously loaded Keyboard got disconnected.") + throw; + } + } + + /// + /// Properly resizes any size bitmap to the keyboard by creating a rectangle whose size is dependent on the bitmap + /// size. + /// + /// + public override void DrawBitmap(Bitmap bitmap) + { + using (var image = ImageUtilities.ResizeImage(bitmap, Width, Height)) + { + // For STRAFE, stretch the image on row 2. + if (_keyboard.DeviceInfo.Model == "STRAFE RGB") + { + using (var strafeBitmap = new Bitmap(22, 8)) + { + using (var g = Graphics.FromImage(strafeBitmap)) + { + g.DrawImage(image, new Point(0, 0)); + g.DrawImage(image, new Rectangle(0, 3, 22, 7), new Rectangle(0, 2, 22, 7), + GraphicsUnit.Pixel); + + _keyboardBrush.Image = strafeBitmap; + _keyboard.Update(); + } + } + } + else + { + _keyboardBrush.Image = image; + _keyboard.Update(); + } + } + } + + public override KeyMatch? GetKeyPosition(Keys keyCode) + { + var widthMultiplier = Width/_keyboard.Brush.RenderedRectangle.Width; + var heightMultiplier = Height/_keyboard.Brush.RenderedRectangle.Height; + + CorsairLed cueLed = null; + try + { + cueLed = _keyboard.Leds.FirstOrDefault(k => k.Id.ToString() == keyCode.ToString()) ?? + _keyboard.Leds.FirstOrDefault(k => k.Id == KeyMap.FormsKeys[keyCode]); + } + catch (Exception) + { + // ignored + } + + if (cueLed == null) + return null; + + var center = cueLed.LedRectangle.GetCenter(); + return new KeyMatch(keyCode, (int) (center.X*widthMultiplier), (int) (center.Y*heightMultiplier)); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/DeviceProviders/Corsair/CorsairMouse.cs b/Artemis/Artemis/DeviceProviders/Corsair/CorsairMouse.cs index c6586ef31..7e18ba746 100644 --- a/Artemis/Artemis/DeviceProviders/Corsair/CorsairMouse.cs +++ b/Artemis/Artemis/DeviceProviders/Corsair/CorsairMouse.cs @@ -8,7 +8,7 @@ using Ninject.Extensions.Logging; namespace Artemis.DeviceProviders.Corsair { - internal class CorsairMouse : DeviceProvider + public class CorsairMouse : DeviceProvider { public CorsairMouse(ILogger logger) { @@ -22,7 +22,7 @@ namespace Artemis.DeviceProviders.Corsair { CanUse = CanInitializeSdk(); if (CanUse && !CueSDK.IsInitialized) - CueSDK.Initialize(true); + CueSDK.Initialize(); Logger.Debug("Attempted to enable Corsair mice. CanUse: {0}", CanUse); diff --git a/Artemis/Artemis/DeviceProviders/Corsair/CorsairMousemat.cs b/Artemis/Artemis/DeviceProviders/Corsair/CorsairMousemat.cs index d39f50fe2..3062862d5 100644 --- a/Artemis/Artemis/DeviceProviders/Corsair/CorsairMousemat.cs +++ b/Artemis/Artemis/DeviceProviders/Corsair/CorsairMousemat.cs @@ -8,7 +8,7 @@ using Ninject.Extensions.Logging; namespace Artemis.DeviceProviders.Corsair { - internal class CorsairMousemat : DeviceProvider + public class CorsairMousemat : DeviceProvider { public CorsairMousemat(ILogger logger) { @@ -22,7 +22,7 @@ namespace Artemis.DeviceProviders.Corsair { CanUse = CanInitializeSdk(); if (CanUse && !CueSDK.IsInitialized) - CueSDK.Initialize(true); + CueSDK.Initialize(); Logger.Debug("Attempted to enable Corsair mousemat. CanUse: {0}", CanUse); diff --git a/Artemis/Artemis/DeviceProviders/Logitech/G810.cs b/Artemis/Artemis/DeviceProviders/Logitech/G810.cs index e51e0b9a5..aedb226b2 100644 --- a/Artemis/Artemis/DeviceProviders/Logitech/G810.cs +++ b/Artemis/Artemis/DeviceProviders/Logitech/G810.cs @@ -8,7 +8,7 @@ using Artemis.Settings; namespace Artemis.DeviceProviders.Logitech { - internal class G810 : LogitechKeyboard + public class G810 : LogitechKeyboard { private GeneralSettings _generalSettings; diff --git a/Artemis/Artemis/DeviceProviders/Logitech/G910.cs b/Artemis/Artemis/DeviceProviders/Logitech/G910.cs index d79aca306..e6f9ae8ce 100644 --- a/Artemis/Artemis/DeviceProviders/Logitech/G910.cs +++ b/Artemis/Artemis/DeviceProviders/Logitech/G910.cs @@ -10,7 +10,7 @@ using Artemis.Settings; namespace Artemis.DeviceProviders.Logitech { - internal class G910 : LogitechKeyboard + public class G910 : LogitechKeyboard { private readonly GeneralSettings _generalSettings; diff --git a/Artemis/Artemis/Events/ProfileDeviceEventsArg.cs b/Artemis/Artemis/Events/ProfileDeviceEventsArg.cs new file mode 100644 index 000000000..6a988f1bd --- /dev/null +++ b/Artemis/Artemis/Events/ProfileDeviceEventsArg.cs @@ -0,0 +1,22 @@ +using System; +using System.Windows.Media; +using Artemis.Models.Interfaces; + +namespace Artemis.Events +{ + public class ProfileDeviceEventsArg : EventArgs + { + public ProfileDeviceEventsArg(string updateType, IDataModel dataModel, bool preview, DrawingContext drawingContext) + { + UpdateType = updateType; + DataModel = dataModel; + Preview = preview; + DrawingContext = drawingContext; + } + + public string UpdateType { get; } + public IDataModel DataModel { get; } + public bool Preview { get; } + public DrawingContext DrawingContext { get; } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/InjectionModules/BaseModules.cs b/Artemis/Artemis/InjectionModules/BaseModules.cs index cdd51407f..5c975f7f9 100644 --- a/Artemis/Artemis/InjectionModules/BaseModules.cs +++ b/Artemis/Artemis/InjectionModules/BaseModules.cs @@ -1,39 +1,135 @@ -using Artemis.Modules.Effects.ProfilePreview; -using Artemis.Services; -using Artemis.Utilities.DataReaders; -using Artemis.Utilities.GameState; -using Artemis.ViewModels; -using Artemis.ViewModels.Abstract; -using Artemis.ViewModels.Profiles; -using Ninject.Modules; - -namespace Artemis.InjectionModules -{ - internal class BaseModules : NinjectModule - { - public override void Load() - { - // ViewModels - Bind().ToSelf().InSingletonScope(); - Bind().ToSelf(); - Bind().ToSelf(); - Bind().ToSelf().InSingletonScope(); - - Bind().To(); - Bind().To(); - Bind().To(); - Bind().To(); - - // Models - Bind().ToSelf().InSingletonScope(); - - // Services - Bind().ToSelf().InSingletonScope(); - Bind().ToSelf().InSingletonScope(); - - // Servers - Bind().ToSelf().InSingletonScope(); - Bind().ToSelf().InSingletonScope(); - } - } +using Artemis.DeviceProviders; +using Artemis.Models; +using Artemis.Modules.Effects.ProfilePreview; +using Artemis.Profiles.Layers.Interfaces; +using Artemis.Profiles.Layers.Types.AmbientLight; +using Artemis.Profiles.Layers.Types.Audio; +using Artemis.Profiles.Layers.Types.Audio.AudioCapturing; +using Artemis.Profiles.Layers.Types.KeyPress; +using Artemis.Profiles.Lua; +using Artemis.Services; +using Artemis.Utilities.DataReaders; +using Artemis.Utilities.GameState; +using Artemis.ViewModels; +using Artemis.ViewModels.Abstract; +using Artemis.ViewModels.Profiles; +using Ninject.Extensions.Conventions; +using Ninject.Modules; + +namespace Artemis.InjectionModules +{ + public class BaseModules : NinjectModule + { + public override void Load() + { + #region ViewModels + + Bind().ToSelf().InSingletonScope(); + Bind().ToSelf(); + Bind().ToSelf(); + Bind().ToSelf().InSingletonScope(); + Kernel.Bind(x => + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindAllBaseClasses()); + + #endregion + + #region Models + + Bind().ToSelf().InSingletonScope(); + + #endregion + + #region Services + + Bind().ToSelf().InSingletonScope(); + Bind().ToSelf().InSingletonScope(); + + #endregion + + #region Servers + + Bind().ToSelf().InSingletonScope(); + Bind().ToSelf().InSingletonScope(); + + #endregion + + #region Devices + + Kernel.Bind(x => + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindAllBaseClasses()); + + #endregion + + #region Effects + + Kernel.Bind(x => + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindAllBaseClasses() + .Configure((b, c) => b.InSingletonScope().Named(c.Name)) + ); + Kernel.Bind(x => + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindBase()); + Kernel.Bind(x => + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindBase()); + Kernel.Bind(x => + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindBase()); + + #endregion + + #region Profiles + + Kernel.Bind(x => + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindAllInterfaces()); + Kernel.Bind(x => + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindAllInterfaces()); + Kernel.Bind(x => + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindAllInterfaces()); + Kernel.Bind(x => + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindToSelf()); + + // Type helpers + Bind().ToSelf().InSingletonScope(); + + #endregion + + #region Lua + + Kernel.Bind(x => + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindAllBaseClasses()); + + #endregion + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/InjectionModules/DeviceModules.cs b/Artemis/Artemis/InjectionModules/DeviceModules.cs deleted file mode 100644 index de64108ce..000000000 --- a/Artemis/Artemis/InjectionModules/DeviceModules.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Artemis.DeviceProviders; -using Artemis.DeviceProviders.Artemis; -using Artemis.DeviceProviders.CoolerMaster; -using Artemis.DeviceProviders.Corsair; -using Artemis.DeviceProviders.Logitech; -using Artemis.DeviceProviders.Razer; -using Ninject.Modules; - -namespace Artemis.InjectionModules -{ - public class DeviceModules : NinjectModule - { - public override void Load() - { - // Keyboards - Bind().To().InSingletonScope(); - Bind().To().InSingletonScope(); - Bind().To().InSingletonScope(); - Bind().To().InSingletonScope(); - Bind().To().InSingletonScope(); - Bind().To().InSingletonScope(); - Bind().To().InSingletonScope(); - - // Mice - Bind().To().InSingletonScope(); - - // Headsets - Bind().To().InSingletonScope(); - - // Mousemats - Bind().To().InSingletonScope(); - - // Other - Bind().To().InSingletonScope(); - } - } -} \ No newline at end of file diff --git a/Artemis/Artemis/InjectionModules/EffectModules.cs b/Artemis/Artemis/InjectionModules/EffectModules.cs deleted file mode 100644 index 387b85ba7..000000000 --- a/Artemis/Artemis/InjectionModules/EffectModules.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Artemis.Models; -using Artemis.ViewModels.Abstract; -using Ninject.Extensions.Conventions; -using Ninject.Modules; - -namespace Artemis.InjectionModules -{ - public class EffectModules : NinjectModule - { - public override void Load() - { - // Effects - Kernel.Bind(x => - { - x.FromThisAssembly() - .SelectAllClasses() - .InheritedFrom() - .BindBase() - .Configure((b, c) => b.InSingletonScope().Named(c.Name)); - }); - - // View models - Kernel.Bind(x => - { - x.FromThisAssembly() - .SelectAllClasses() - .InheritedFrom() - .BindBase(); - }); - - Kernel.Bind(x => - { - x.FromThisAssembly() - .SelectAllClasses() - .InheritedFrom() - .BindBase(); - }); - Kernel.Bind(x => - { - x.FromThisAssembly() - .SelectAllClasses() - .InheritedFrom() - .BindBase(); - }); - } - } -} \ No newline at end of file diff --git a/Artemis/Artemis/InjectionModules/ManagerModules.cs b/Artemis/Artemis/InjectionModules/ManagerModules.cs index 540e266ef..c90727795 100644 --- a/Artemis/Artemis/InjectionModules/ManagerModules.cs +++ b/Artemis/Artemis/InjectionModules/ManagerModules.cs @@ -3,7 +3,7 @@ using Ninject.Modules; namespace Artemis.InjectionModules { - internal class ManagerModules : NinjectModule + public class ManagerModules : NinjectModule { public override void Load() { @@ -12,6 +12,7 @@ namespace Artemis.InjectionModules Bind().ToSelf().InSingletonScope(); Bind().ToSelf().InSingletonScope(); Bind().ToSelf().InSingletonScope(); + Bind().ToSelf().InSingletonScope(); } } } \ No newline at end of file diff --git a/Artemis/Artemis/InjectionModules/ProfileModules.cs b/Artemis/Artemis/InjectionModules/ProfileModules.cs deleted file mode 100644 index 8e91b68b8..000000000 --- a/Artemis/Artemis/InjectionModules/ProfileModules.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Artemis.Profiles.Layers.Animations; -using Artemis.Profiles.Layers.Conditions; -using Artemis.Profiles.Layers.Interfaces; -using Artemis.Profiles.Layers.Types.AmbientLight; -using Artemis.Profiles.Layers.Types.Audio; -using Artemis.Profiles.Layers.Types.Audio.AudioCapturing; -using Artemis.Profiles.Layers.Types.Folder; -using Artemis.Profiles.Layers.Types.Generic; -using Artemis.Profiles.Layers.Types.Headset; -using Artemis.Profiles.Layers.Types.Keyboard; -using Artemis.Profiles.Layers.Types.KeyboardGif; -using Artemis.Profiles.Layers.Types.KeyPress; -using Artemis.Profiles.Layers.Types.Mouse; -using Artemis.Profiles.Layers.Types.Mousemat; -using Ninject.Modules; - -namespace Artemis.InjectionModules -{ - public class ProfileModules : NinjectModule - { - public override void Load() - { - // Animations - Bind().To(); - Bind().To(); - Bind().To(); - Bind().To(); - Bind().To(); - Bind().To(); - Bind().To(); - - // Conditions - Bind().To(); - Bind().To(); - - // Types - Bind().To(); - Bind().To(); - Bind().To(); - Bind().To(); - Bind().To(); - Bind().To(); - Bind().To(); - Bind().To(); - Bind().To(); - Bind().To(); - - // Bind some Layer Types to self as well in order to allow JSON.NET injection - Bind().ToSelf(); - Bind().ToSelf(); - Bind().ToSelf(); - - // Type helpers - Bind().ToSelf().InSingletonScope(); - } - } -} \ No newline at end of file diff --git a/Artemis/Artemis/Managers/EffectManager.cs b/Artemis/Artemis/Managers/EffectManager.cs index e8ef40679..5936411dd 100644 --- a/Artemis/Artemis/Managers/EffectManager.cs +++ b/Artemis/Artemis/Managers/EffectManager.cs @@ -35,8 +35,8 @@ namespace Artemis.Managers models.AddRange(overlayModels); // Add games, exclude WoW if needed models.AddRange(_generalSettings.GamestatePort != 62575 - ? gameModels.Where(e => e.Name != "WoW") - : gameModels); + ? gameModels.Where(e => e.Name != "WoW").Where(e => e.Name != "LightFX") + : gameModels.Where(e => e.Name != "LightFX")); EffectModels = models; _logger.Info("Intialized EffectManager"); @@ -72,7 +72,7 @@ namespace Artemis.Managers /// public IEnumerable EnabledGames { - get { return EffectModels.OfType().Where(g => g.Enabled); } + get { return EffectModels.OfType().Where(g => g.Enabled && g.Settings.Enabled); } } public event EventHandler OnEffectChangedEvent; @@ -138,14 +138,16 @@ namespace Artemis.Managers { if (!wasNull) ActiveEffect.Dispose(); - - ActiveEffect = effectModel; - ActiveEffect.Enable(); - if (!ActiveEffect.Initialized) + lock (effectModel) { - _logger.Debug("Cancelling effect change, couldn't initialize the effect ({0})", effectModel.Name); - ActiveEffect = null; - return; + ActiveEffect = effectModel; + ActiveEffect.Enable(); + if (!ActiveEffect.Initialized) + { + _logger.Debug("Cancelling effect change, couldn't initialize the effect ({0})", effectModel.Name); + ActiveEffect = null; + return; + } } } diff --git a/Artemis/Artemis/Managers/LoopManager.cs b/Artemis/Artemis/Managers/LoopManager.cs index a7c8e3ccc..b0aefca54 100644 --- a/Artemis/Artemis/Managers/LoopManager.cs +++ b/Artemis/Artemis/Managers/LoopManager.cs @@ -22,7 +22,6 @@ namespace Artemis.Managers private readonly EffectManager _effectManager; private readonly ILogger _logger; private readonly Timer _loopTimer; - private bool _canShowException; public LoopManager(ILogger logger, EffectManager effectManager, DeviceManager deviceManager, DebugViewModel debugViewModel) @@ -31,7 +30,6 @@ namespace Artemis.Managers _effectManager = effectManager; _deviceManager = deviceManager; _debugViewModel = debugViewModel; - _canShowException = true; // Setup timers _loopTimer = new Timer(40); diff --git a/Artemis/Artemis/Managers/LuaManager.cs b/Artemis/Artemis/Managers/LuaManager.cs new file mode 100644 index 000000000..fbd499a8b --- /dev/null +++ b/Artemis/Artemis/Managers/LuaManager.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Artemis.DeviceProviders; +using Artemis.Profiles; +using Artemis.Profiles.Lua; +using Artemis.Profiles.Lua.Modules; +using Castle.Core.Internal; +using MoonSharp.Interpreter; +using Ninject; +using Ninject.Extensions.Logging; + +namespace Artemis.Managers +{ + public class LuaManager + { + private readonly DeviceManager _deviceManager; + private readonly IKernel _kernel; + private readonly ILogger _logger; + private readonly Script _luaScript; + private List _luaModules; + + public LuaManager(IKernel kernel, ILogger logger, DeviceManager deviceManager) + { + _kernel = kernel; + _logger = logger; + _deviceManager = deviceManager; + _luaScript = new Script(CoreModules.Preset_SoftSandbox); + } + + public ProfileModel ProfileModel { get; private set; } + public KeyboardProvider KeyboardProvider { get; private set; } + public LuaProfileModule ProfileModule { get; private set; } + public LuaEventsModule EventsModule { get; private set; } + + public void SetupLua(ProfileModel profileModel) + { + _logger.Debug("Setting up LUA for {0}-{1}.", profileModel?.Name, profileModel?.GameName); + // Clear old state + ClearLua(); + + // Stop after that if no model provided/there is no keyboard + if (profileModel == null || _deviceManager.ActiveKeyboard == null) + return; + + ProfileModel = profileModel; + KeyboardProvider = _deviceManager.ActiveKeyboard; + + // Get new instances of all modules + _luaModules = _kernel.Get>(); + ProfileModule = (LuaProfileModule) _luaModules.First(m => m.ModuleName == "Profile"); + EventsModule = (LuaEventsModule) _luaModules.First(m => m.ModuleName == "Events"); + + // Setup new state + _luaScript.Options.DebugPrint = LuaPrint; + + // Insert each module into the script's globals + foreach (var luaModule in _luaModules) + _luaScript.Globals[luaModule.ModuleName] = luaModule; + + // If there is no LUA script, don't bother executing the string + if (ProfileModel.LuaScript.IsNullOrEmpty()) + return; + + try + { + lock (EventsModule.InvokeLock) + { + lock (_luaScript) + { + _luaScript.DoString(ProfileModel.LuaScript); + } + } + } + catch (InternalErrorException e) + { + _logger.Error("[{0}-LUA]: Error: {1}", ProfileModel.Name, e.DecoratedMessage); + } + catch (SyntaxErrorException e) + { + _logger.Error("[{0}-LUA]: Error: {1}", ProfileModel.Name, e.DecoratedMessage); + } + catch (ScriptRuntimeException e) + { + _logger.Error("[{0}-LUA]: Error: {1}", ProfileModel.Name, e.DecoratedMessage); + } + } + + public void ClearLua() + { + if (_luaModules != null) + { + foreach (var luaModule in _luaModules) + luaModule.Dispose(); + _luaModules.Clear(); + } + + try + { + _luaScript.Globals.Clear(); + _luaScript.Registry.Clear(); + _luaScript.Registry.RegisterConstants(); + _luaScript.Registry.RegisterCoreModules(CoreModules.Preset_SoftSandbox); + _luaScript.Globals.RegisterConstants(); + _luaScript.Globals.RegisterCoreModules(CoreModules.Preset_SoftSandbox); + } + catch (NullReferenceException) + { + // TODO: Ask MoonSharp folks why this is happening + } + + if (EventsModule != null) + lock (EventsModule.InvokeLock) + { + lock (_luaScript) + { + _luaScript.DoString(""); + } + } + else + lock (_luaScript) + { + _luaScript.DoString(""); + } + } + + /// + /// Safely call a function on the active script + /// + /// + /// + public void Call(DynValue function, DynValue[] args = null) + { + if (EventsModule == null) + return; + + try + { + lock (EventsModule.InvokeLock) + { + lock (_luaScript) + { + if (args != null) + _luaScript.Call(function, args); + else + _luaScript.Call(function); + } + } + } + catch (ArgumentException e) + { + _logger.Error("[{0}-LUA]: Error: {1}", ProfileModel.Name, e.Message); + } + catch (InternalErrorException e) + { + _logger.Error("[{0}-LUA]: Error: {1}", ProfileModel.Name, e.DecoratedMessage); + } + catch (SyntaxErrorException e) + { + _logger.Error("[{0}-LUA]: Error: {1}", ProfileModel.Name, e.DecoratedMessage); + } + catch (ScriptRuntimeException e) + { + _logger.Error("[{0}-LUA]: Error: {1}", ProfileModel.Name, e.DecoratedMessage); + } + } + + #region Private lua functions + + private void LuaPrint(string s) + { + _logger.Info("[{0}-LUA]: {1}", ProfileModel?.Name, s); + } + + #endregion + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Managers/MainManager.cs b/Artemis/Artemis/Managers/MainManager.cs index f9a8adb04..68a50fd42 100644 --- a/Artemis/Artemis/Managers/MainManager.cs +++ b/Artemis/Artemis/Managers/MainManager.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Linq; using System.Reflection; using System.Threading.Tasks; @@ -10,6 +9,7 @@ using Artemis.Utilities; using Artemis.Utilities.DataReaders; using Artemis.Utilities.GameState; using Artemis.ViewModels; +using Microsoft.Win32; using Ninject; using Ninject.Extensions.Logging; @@ -51,6 +51,9 @@ namespace Artemis.Managers var updateTask = new Task(Updater.UpdateApp); updateTask.Start(); + // Listen for power mode changes + SystemEvents.PowerModeChanged += OnPowerChange; + Logger.Info("Intialized MainManager"); Logger.Info($"Artemis version {Assembly.GetExecutingAssembly().GetName().Version} is ready!"); } @@ -83,6 +86,23 @@ namespace Artemis.Managers public event EventHandler OnEnabledChangedEvent; + /// + /// Restarts the loop manager when the system resumes + /// + /// + /// + private async void OnPowerChange(object sender, PowerModeChangedEventArgs e) + { + if (e.Mode != PowerModes.Resume) + return; + + Logger.Debug("Restarting for OnPowerChange"); + DisableProgram(); + // Wait an extra while for device providers to be fully ready + await Task.Delay(2000); + EnableProgram(); + } + /// /// Loads the last active effect and starts the program /// @@ -124,13 +144,11 @@ namespace Artemis.Managers // If the currently active effect is a no longer running game, get rid of it. var activeGame = EffectManager.ActiveEffect as GameModel; if (activeGame != null) - { if (!runningProcesses.Any(p => p.ProcessName == activeGame.ProcessName && p.HasExited == false)) { Logger.Info("Disabling game: {0}", activeGame.Name); EffectManager.DisableGame(activeGame); } - } // Look for running games, stopping on the first one that's found. var newGame = EffectManager.EnabledGames diff --git a/Artemis/Artemis/Models/EffectModel.cs b/Artemis/Artemis/Models/EffectModel.cs index eb1552d00..a2dd083df 100644 --- a/Artemis/Artemis/Models/EffectModel.cs +++ b/Artemis/Artemis/Models/EffectModel.cs @@ -23,26 +23,26 @@ namespace Artemis.Models protected DateTime LastTrace; - protected EffectModel(DeviceManager deviceManager, EffectSettings settings, IDataModel dataModel) + protected EffectModel(DeviceManager deviceManager, LuaManager luaManager, EffectSettings settings, + IDataModel dataModel) { DeviceManager = deviceManager; + LuaManager = luaManager; Settings = settings; DataModel = dataModel; - // If set, load the last profile from settings - if (!string.IsNullOrEmpty(Settings?.LastProfile)) - Profile = ProfileProvider.GetProfile(DeviceManager.ActiveKeyboard, this, Settings.LastProfile); - DeviceManager.OnKeyboardChangedEvent += DeviceManagerOnOnKeyboardChangedEvent; } public bool Initialized { get; set; } public DeviceManager DeviceManager { get; set; } + public LuaManager LuaManager { get; } public EffectSettings Settings { get; set; } public string Name { get; set; } public int KeyboardScale { get; set; } = 4; // Used by profile system public IDataModel DataModel { get; set; } + public ProfileModel Profile { get; set; } [Inject] @@ -50,17 +50,34 @@ namespace Artemis.Models public virtual void Dispose() { - Profile?.Deactivate(); + Profile?.Deactivate(LuaManager); + Profile = null; } private void DeviceManagerOnOnKeyboardChangedEvent(object sender, KeyboardChangedEventArgs args) { + if (!Initialized) + return; + if (!string.IsNullOrEmpty(Settings?.LastProfile)) Profile = ProfileProvider.GetProfile(DeviceManager.ActiveKeyboard, this, Settings.LastProfile); + else + Profile = ProfileProvider.GetProfile(DeviceManager.ActiveKeyboard, this, "Default"); + + Profile?.Activate(LuaManager); } // Called on creation - public abstract void Enable(); + public virtual void Enable() + { + // If set, load the last profile from settings + if (!string.IsNullOrEmpty(Settings?.LastProfile)) + Profile = ProfileProvider.GetProfile(DeviceManager.ActiveKeyboard, this, Settings.LastProfile); + else + Profile = ProfileProvider.GetProfile(DeviceManager.ActiveKeyboard, this, "Default"); + + Profile?.Activate(LuaManager); + } // Called every frame public abstract void Update(); @@ -73,9 +90,9 @@ namespace Artemis.Models /// public virtual void Render(RenderFrame frame, bool keyboardOnly) { - if ((Profile == null) || (DataModel == null) || (DeviceManager.ActiveKeyboard == null)) + if (Profile == null || DataModel == null || DeviceManager.ActiveKeyboard == null) return; - + lock (DataModel) { lock (Profile) @@ -85,7 +102,7 @@ namespace Artemis.Models // If the profile has no active LUA wrapper, create one if (!string.IsNullOrEmpty(Profile.LuaScript)) - Profile.Activate(DeviceManager.ActiveKeyboard); + Profile.Activate(LuaManager); // Render the keyboard layer-by-layer var keyboardRect = DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale); diff --git a/Artemis/Artemis/Models/GameModel.cs b/Artemis/Artemis/Models/GameModel.cs index 3d9d02204..402669db8 100644 --- a/Artemis/Artemis/Models/GameModel.cs +++ b/Artemis/Artemis/Models/GameModel.cs @@ -6,7 +6,8 @@ namespace Artemis.Models { public abstract class GameModel : EffectModel { - protected GameModel(DeviceManager deviceManager, GameSettings settings, IDataModel dataModel): base(deviceManager, settings, dataModel) + protected GameModel(DeviceManager deviceManager, LuaManager luaManager, GameSettings settings, + IDataModel dataModel) : base(deviceManager, luaManager, settings, dataModel) { // Override settings to the GameSettings type Settings = settings; diff --git a/Artemis/Artemis/Models/OverlayModel.cs b/Artemis/Artemis/Models/OverlayModel.cs index 3e7d4aba8..9935ab89b 100644 --- a/Artemis/Artemis/Models/OverlayModel.cs +++ b/Artemis/Artemis/Models/OverlayModel.cs @@ -8,7 +8,8 @@ namespace Artemis.Models private bool _enabled; public string ProcessName; - protected OverlayModel(DeviceManager deviceManager, OverlaySettings settings) : base(deviceManager, settings, null) + protected OverlayModel(DeviceManager deviceManager, LuaManager luaManager, OverlaySettings settings) + : base(deviceManager, luaManager, settings, null) { Settings = settings; Enabled = settings.Enabled; diff --git a/Artemis/Artemis/Modules/Effects/Bubbles/BubblesModel.cs b/Artemis/Artemis/Modules/Effects/Bubbles/BubblesModel.cs index fbbfcb1d2..3eb0f1e43 100644 --- a/Artemis/Artemis/Modules/Effects/Bubbles/BubblesModel.cs +++ b/Artemis/Artemis/Modules/Effects/Bubbles/BubblesModel.cs @@ -15,7 +15,8 @@ namespace Artemis.Modules.Effects.Bubbles { #region Constructors - public BubblesModel(DeviceManager deviceManager) : base(deviceManager, SettingsProvider.Load(), null) + public BubblesModel(DeviceManager deviceManager, LuaManager luaManager) + : base(deviceManager, luaManager, SettingsProvider.Load(), null) { Name = "Bubbles"; Initialized = false; @@ -41,7 +42,7 @@ namespace Artemis.Modules.Effects.Bubbles KeyboardScale = Settings.Smoothness; var rect = DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale); - var scaleFactor = Settings.Smoothness/25.0; + var scaleFactor = Settings.Smoothness / 25.0; for (var i = 0; i < Settings.BubbleCount; i++) { @@ -49,16 +50,18 @@ namespace Artemis.Modules.Effects.Bubbles ? ColorHelpers.GetRandomRainbowColor() : ColorHelpers.ToDrawingColor(Settings.BubbleColor); // -Settings.MoveSpeed because we want to spawn at least one move away from borders - var initialPositionX = (rect.Width - Settings.BubbleSize*scaleFactor*2 - Settings.MoveSpeed*scaleFactor)* - _random.NextDouble() + Settings.BubbleSize*scaleFactor; - var initialPositionY = (rect.Height - Settings.BubbleSize*scaleFactor*2 - Settings.MoveSpeed*scaleFactor)* - _random.NextDouble() + Settings.BubbleSize*scaleFactor; - var initialDirectionX = Settings.MoveSpeed*scaleFactor*_random.NextDouble()* + var initialPositionX = (rect.Width - Settings.BubbleSize * scaleFactor * 2 - + Settings.MoveSpeed * scaleFactor) * + _random.NextDouble() + Settings.BubbleSize * scaleFactor; + var initialPositionY = (rect.Height - Settings.BubbleSize * scaleFactor * 2 - + Settings.MoveSpeed * scaleFactor) * + _random.NextDouble() + Settings.BubbleSize * scaleFactor; + var initialDirectionX = Settings.MoveSpeed * scaleFactor * _random.NextDouble() * (_random.Next(1) == 0 ? -1 : 1); - var initialDirectionY = (Settings.MoveSpeed*scaleFactor - Math.Abs(initialDirectionX))* + var initialDirectionY = (Settings.MoveSpeed * scaleFactor - Math.Abs(initialDirectionX)) * (_random.Next(1) == 0 ? -1 : 1); - _bubbles.Add(new Bubble(color, (int) Math.Round(Settings.BubbleSize*scaleFactor), + _bubbles.Add(new Bubble(color, (int) Math.Round(Settings.BubbleSize * scaleFactor), new Point(initialPositionX, initialPositionY), new Vector(initialDirectionX, initialDirectionY))); } @@ -79,7 +82,7 @@ namespace Artemis.Modules.Effects.Bubbles if (Settings.IsShiftColors) bubble.Color = ColorHelpers.ShiftColor(bubble.Color, Settings.IsRandomColors - ? (int) Math.Round(Settings.ShiftColorSpeed*_random.NextDouble()) + ? (int) Math.Round(Settings.ShiftColorSpeed * _random.NextDouble()) : Settings.ShiftColorSpeed); bubble.CheckCollision(keyboardRectangle); diff --git a/Artemis/Artemis/Modules/Effects/ProfilePreview/ProfilePreviewModel.cs b/Artemis/Artemis/Modules/Effects/ProfilePreview/ProfilePreviewModel.cs index 0b258f5fe..d30118099 100644 --- a/Artemis/Artemis/Modules/Effects/ProfilePreview/ProfilePreviewModel.cs +++ b/Artemis/Artemis/Modules/Effects/ProfilePreview/ProfilePreviewModel.cs @@ -16,8 +16,7 @@ namespace Artemis.Modules.Effects.ProfilePreview { public class ProfilePreviewModel : EffectModel { - public ProfilePreviewModel(DeviceManager deviceManager) - : base(deviceManager, null, new ProfilePreviewDataModel()) + public ProfilePreviewModel(DeviceManager deviceManager, LuaManager luaManager): base(deviceManager, luaManager, null, new ProfilePreviewDataModel()) { Name = "Profile Preview"; } @@ -55,8 +54,8 @@ namespace Artemis.Modules.Effects.ProfilePreview var renderLayers = GetRenderLayers(keyboardOnly); // If the profile has no active LUA wrapper, create one - if (!Equals(LuaWrapper.ProfileModel, Profile)) - Profile.Activate(DeviceManager.ActiveKeyboard); + if (!Equals(LuaManager.ProfileModel, Profile)) + Profile.Activate(LuaManager); // Render the keyboard layer-by-layer var keyboardRect = DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale); diff --git a/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileModel.cs b/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileModel.cs index 7a5607c43..6fd367001 100644 --- a/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileModel.cs +++ b/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileModel.cs @@ -1,262 +1,275 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using Artemis.DAL; -using Artemis.Managers; -using Artemis.Models; -using Artemis.Profiles.Layers.Models; -using Artemis.Utilities; -using Newtonsoft.Json; -using SpotifyAPI.Local; - -namespace Artemis.Modules.Effects.WindowsProfile -{ - public class WindowsProfileModel : EffectModel - { - private List _cores; - private int _cpuFrames; - private DateTime _lastMusicUpdate; - private PerformanceCounter _overallCpu; - private SpotifyLocalAPI _spotify; - private bool _spotifySetupBusy; - - public WindowsProfileModel(DeviceManager deviceManager) - : base(deviceManager, SettingsProvider.Load(), new WindowsProfileDataModel()) - { - _lastMusicUpdate = DateTime.Now; - - Name = "WindowsProfile"; - } - - public override void Dispose() - { - Initialized = false; - base.Dispose(); - } - - public override void Enable() - { - SetupCpu(); - SetupSpotify(); - - Initialized = true; - } - - public override void Update() - { - var dataModel = (WindowsProfileDataModel) DataModel; - UpdateCpu(dataModel); - UpdateMusicPlayers(dataModel); - UpdateDay(dataModel); - UpdateKeyStates(dataModel); - UpdateActiveWindow(dataModel); - } - - #region Current Time - - private void UpdateDay(WindowsProfileDataModel dataModel) - { - var now = DateTime.Now; - dataModel.CurrentTime.Hours24 = int.Parse(now.ToString("HH")); - dataModel.CurrentTime.Hours12 = int.Parse(now.ToString("hh")); - dataModel.CurrentTime.Minutes = int.Parse(now.ToString("mm")); - dataModel.CurrentTime.Seconds = int.Parse(now.ToString("ss")); - } - - #endregion - - #region CPU - - private void SetupCpu() - { - try - { - _cores = GetPerformanceCounters(); - var coreCount = _cores.Count; - while (coreCount < 8) - { - _cores.Add(null); - coreCount++; - } - _overallCpu = GetOverallPerformanceCounter(); - } - catch (InvalidOperationException) - { - Logger?.Warn("Failed to setup CPU information, try running \"lodctr /R\" as administrator."); - } - } - - private void UpdateCpu(WindowsProfileDataModel dataModel) - { - if ((_cores == null) || (_overallCpu == null)) - return; - - // CPU is only updated every 15 frames, the performance counter gives 0 if updated too often - _cpuFrames++; - if (_cpuFrames < 16) - return; - - _cpuFrames = 0; - - // Update cores, not ideal but data models don't support lists. - if (_cores[0] != null) - dataModel.Cpu.Core1Usage = (int) _cores[0].NextValue(); - if (_cores[1] != null) - dataModel.Cpu.Core2Usage = (int) _cores[1].NextValue(); - if (_cores[2] != null) - dataModel.Cpu.Core3Usage = (int) _cores[2].NextValue(); - if (_cores[3] != null) - dataModel.Cpu.Core4Usage = (int) _cores[3].NextValue(); - if (_cores[4] != null) - dataModel.Cpu.Core5Usage = (int) _cores[4].NextValue(); - if (_cores[5] != null) - dataModel.Cpu.Core6Usage = (int) _cores[5].NextValue(); - if (_cores[6] != null) - dataModel.Cpu.Core7Usage = (int) _cores[6].NextValue(); - if (_cores[7] != null) - dataModel.Cpu.Core8Usage = (int) _cores[7].NextValue(); - - //From Ted - Let's get overall RAM and CPU usage here - dataModel.Cpu.TotalUsage = (int) _overallCpu.NextValue(); - - var phav = PerformanceInfo.GetPhysicalAvailableMemoryInMiB(); - var tot = PerformanceInfo.GetTotalMemoryInMiB(); - var percentFree = phav/(decimal) tot*100; - var percentOccupied = 100 - percentFree; - - dataModel.Performance.RAMUsage = (int) percentOccupied; - } - - public override List GetRenderLayers(bool keyboardOnly) - { - return Profile.GetRenderLayers(DataModel, keyboardOnly, false); - } - - public static PerformanceCounter GetOverallPerformanceCounter() - { - var cpuCounter = new PerformanceCounter - { - CategoryName = "Processor", - CounterName = "% Processor Time", - InstanceName = "_Total" - }; - - return cpuCounter; - } - - public static List GetPerformanceCounters() - { - var performanceCounters = new List(); - var procCount = Environment.ProcessorCount; - for (var i = 0; i < procCount; i++) - { - var pc = new PerformanceCounter("Processor", "% Processor Time", i.ToString()); - performanceCounters.Add(pc); - } - return performanceCounters; - } - - #endregion - - #region Music - - public void SetupSpotify() - { - if (_spotifySetupBusy) - return; - - _spotifySetupBusy = true; - _spotify = new SpotifyLocalAPI(); - - // Connecting can sometimes use a little bit more conviction - Task.Factory.StartNew(() => - { - var tryCount = 0; - while (tryCount <= 10) - { - tryCount++; - var connected = _spotify.Connect(); - if (connected) - break; - Thread.Sleep(1000); - } - _spotifySetupBusy = false; - }); - } - - public void UpdateMusicPlayers(WindowsProfileDataModel dataModel) - { - // This is quite resource hungry so only update it once every two seconds - if (DateTime.Now - _lastMusicUpdate < TimeSpan.FromSeconds(2)) - return; - _lastMusicUpdate = DateTime.Now; - - UpdateSpotify(dataModel); - UpdateGooglePlayMusic(dataModel); - } - - private void UpdateSpotify(WindowsProfileDataModel dataModel) - { - // Spotify - if (!dataModel.Spotify.Running && SpotifyLocalAPI.IsSpotifyRunning()) - SetupSpotify(); - - var status = _spotify.GetStatus(); - if (status == null) - return; - - dataModel.Spotify.Playing = status.Playing; - dataModel.Spotify.Running = SpotifyLocalAPI.IsSpotifyRunning(); - - if (status.Track != null) - { - dataModel.Spotify.Artist = status.Track.ArtistResource?.Name; - dataModel.Spotify.SongName = status.Track.TrackResource?.Name; - dataModel.Spotify.Album = status.Track.AlbumResource?.Name; - dataModel.Spotify.SongLength = status.Track.Length; - } - - if (dataModel.Spotify.SongLength > 0) - dataModel.Spotify.SongPercentCompleted = - (int) (status.PlayingPosition/dataModel.Spotify.SongLength*100.0); - } - - private void UpdateGooglePlayMusic(WindowsProfileDataModel dataModel) - { - // Google Play Music - var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - var json = appData + @"\Google Play Music Desktop Player\json_store\playback.json"; - if (!File.Exists(json)) - return; - - dataModel.GooglePlayMusic = JsonConvert.DeserializeObject(File.ReadAllText(json)); - } - - #endregion - - #region System - - [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, - CallingConvention = CallingConvention.Winapi)] - public static extern short GetKeyState(int keyCode); - - private void UpdateKeyStates(WindowsProfileDataModel dataModel) - { - dataModel.Keyboard.NumLock = ((ushort)GetKeyState(0x90) & 0xffff) != 0; - dataModel.Keyboard.CapsLock = ((ushort)GetKeyState(0x14) & 0xffff) != 0; - dataModel.Keyboard.ScrollLock = ((ushort)GetKeyState(0x91) & 0xffff) != 0; - } - - private void UpdateActiveWindow(WindowsProfileDataModel dataModel) - { - dataModel.ActiveWindow.ProcessName = ActiveWindowHelper.ActiveWindowProcessName; - dataModel.ActiveWindow.WindowTitle = ActiveWindowHelper.ActiveWindowWindowTitle; - } - - #endregion - } +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Artemis.DAL; +using Artemis.Managers; +using Artemis.Models; +using Artemis.Profiles.Layers.Models; +using Artemis.Utilities; +using Newtonsoft.Json; +using SpotifyAPI.Local; + +namespace Artemis.Modules.Effects.WindowsProfile +{ + public class WindowsProfileModel : EffectModel + { + private List _cores; + private int _cpuFrames; + private DateTime _lastMusicUpdate; + private PerformanceCounter _overallCpu; + private SpotifyLocalAPI _spotify; + private bool _spotifySetupBusy; + + public WindowsProfileModel(DeviceManager deviceManager, LuaManager luaManager) + : base(deviceManager, luaManager, SettingsProvider.Load(), + new WindowsProfileDataModel()) + { + _lastMusicUpdate = DateTime.Now; + + Name = "WindowsProfile"; + } + + public override void Dispose() + { + Initialized = false; + base.Dispose(); + } + + public override void Enable() + { + base.Enable(); + + SetupCpu(); + SetupSpotify(); + + Initialized = true; + } + + public override void Update() + { + var dataModel = (WindowsProfileDataModel) DataModel; + UpdateCpu(dataModel); + UpdateMusicPlayers(dataModel); + UpdateDay(dataModel); + UpdateKeyStates(dataModel); + UpdateActiveWindow(dataModel); + } + + #region Current Time + + private void UpdateDay(WindowsProfileDataModel dataModel) + { + var now = DateTime.Now; + dataModel.CurrentTime.Hours24 = int.Parse(now.ToString("HH")); + dataModel.CurrentTime.Hours12 = int.Parse(now.ToString("hh")); + dataModel.CurrentTime.Minutes = int.Parse(now.ToString("mm")); + dataModel.CurrentTime.Seconds = int.Parse(now.ToString("ss")); + } + + #endregion + + #region CPU + + private void SetupCpu() + { + try + { + _cores = GetPerformanceCounters(); + var coreCount = _cores.Count; + while (coreCount < 8) + { + _cores.Add(null); + coreCount++; + } + _overallCpu = GetOverallPerformanceCounter(); + } + catch (InvalidOperationException) + { + Logger?.Warn("Failed to setup CPU information, try running \"lodctr /R\" as administrator."); + } + } + + private void UpdateCpu(WindowsProfileDataModel dataModel) + { + if ((_cores == null) || (_overallCpu == null)) + return; + + // CPU is only updated every 15 frames, the performance counter gives 0 if updated too often + _cpuFrames++; + if (_cpuFrames < 16) + return; + + _cpuFrames = 0; + + // Update cores, not ideal but data models don't support lists. + if (_cores[0] != null) + dataModel.Cpu.Core1Usage = (int) _cores[0].NextValue(); + if (_cores[1] != null) + dataModel.Cpu.Core2Usage = (int) _cores[1].NextValue(); + if (_cores[2] != null) + dataModel.Cpu.Core3Usage = (int) _cores[2].NextValue(); + if (_cores[3] != null) + dataModel.Cpu.Core4Usage = (int) _cores[3].NextValue(); + if (_cores[4] != null) + dataModel.Cpu.Core5Usage = (int) _cores[4].NextValue(); + if (_cores[5] != null) + dataModel.Cpu.Core6Usage = (int) _cores[5].NextValue(); + if (_cores[6] != null) + dataModel.Cpu.Core7Usage = (int) _cores[6].NextValue(); + if (_cores[7] != null) + dataModel.Cpu.Core8Usage = (int) _cores[7].NextValue(); + + //From Ted - Let's get overall RAM and CPU usage here + dataModel.Cpu.TotalUsage = (int) _overallCpu.NextValue(); + + var phav = PerformanceInfo.GetPhysicalAvailableMemoryInMiB(); + var tot = PerformanceInfo.GetTotalMemoryInMiB(); + var percentFree = phav / (decimal) tot * 100; + var percentOccupied = 100 - percentFree; + + dataModel.Performance.RAMUsage = (int) percentOccupied; + } + + public override List GetRenderLayers(bool keyboardOnly) + { + return Profile.GetRenderLayers(DataModel, keyboardOnly, false); + } + + public static PerformanceCounter GetOverallPerformanceCounter() + { + var cpuCounter = new PerformanceCounter + { + CategoryName = "Processor", + CounterName = "% Processor Time", + InstanceName = "_Total" + }; + + return cpuCounter; + } + + public static List GetPerformanceCounters() + { + var performanceCounters = new List(); + var procCount = Environment.ProcessorCount; + for (var i = 0; i < procCount; i++) + { + var pc = new PerformanceCounter("Processor", "% Processor Time", i.ToString()); + performanceCounters.Add(pc); + } + return performanceCounters; + } + + #endregion + + #region Music + + public void SetupSpotify() + { + if (_spotifySetupBusy) + return; + + _spotifySetupBusy = true; + _spotify = new SpotifyLocalAPI(); + + // Connecting can sometimes use a little bit more conviction + Task.Factory.StartNew(() => + { + var tryCount = 0; + while (tryCount <= 10) + { + // Causes WebException if not internet connection is available + try + { + tryCount++; + var connected = _spotify.Connect(); + if (connected) + break; + Thread.Sleep(1000); + } + catch (WebException) + { + break; + } + + } + _spotifySetupBusy = false; + }); + } + + public void UpdateMusicPlayers(WindowsProfileDataModel dataModel) + { + // This is quite resource hungry so only update it once every two seconds + if (DateTime.Now - _lastMusicUpdate < TimeSpan.FromSeconds(2)) + return; + _lastMusicUpdate = DateTime.Now; + + UpdateSpotify(dataModel); + UpdateGooglePlayMusic(dataModel); + } + + private void UpdateSpotify(WindowsProfileDataModel dataModel) + { + // Spotify + if (!dataModel.Spotify.Running && SpotifyLocalAPI.IsSpotifyRunning()) + SetupSpotify(); + + var status = _spotify.GetStatus(); + if (status == null) + return; + + dataModel.Spotify.Playing = status.Playing; + dataModel.Spotify.Running = SpotifyLocalAPI.IsSpotifyRunning(); + + if (status.Track != null) + { + dataModel.Spotify.Artist = status.Track.ArtistResource?.Name; + dataModel.Spotify.SongName = status.Track.TrackResource?.Name; + dataModel.Spotify.Album = status.Track.AlbumResource?.Name; + dataModel.Spotify.SongLength = status.Track.Length; + } + + if (dataModel.Spotify.SongLength > 0) + dataModel.Spotify.SongPercentCompleted = + (int) (status.PlayingPosition / dataModel.Spotify.SongLength * 100.0); + } + + private void UpdateGooglePlayMusic(WindowsProfileDataModel dataModel) + { + // Google Play Music + var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + var json = appData + @"\Google Play Music Desktop Player\json_store\playback.json"; + if (!File.Exists(json)) + return; + + dataModel.GooglePlayMusic = JsonConvert.DeserializeObject(File.ReadAllText(json)); + } + + #endregion + + #region System + + [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, + CallingConvention = CallingConvention.Winapi)] + public static extern short GetKeyState(int keyCode); + + private void UpdateKeyStates(WindowsProfileDataModel dataModel) + { + dataModel.Keyboard.NumLock = ((ushort) GetKeyState(0x90) & 0xffff) != 0; + dataModel.Keyboard.CapsLock = ((ushort) GetKeyState(0x14) & 0xffff) != 0; + dataModel.Keyboard.ScrollLock = ((ushort) GetKeyState(0x91) & 0xffff) != 0; + } + + private void UpdateActiveWindow(WindowsProfileDataModel dataModel) + { + dataModel.ActiveWindow.ProcessName = ActiveWindowHelper.ActiveWindowProcessName; + dataModel.ActiveWindow.WindowTitle = ActiveWindowHelper.ActiveWindowWindowTitle; + } + + #endregion + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileViewModel.cs b/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileViewModel.cs index e39b96325..1f16bd4b4 100644 --- a/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileViewModel.cs +++ b/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileViewModel.cs @@ -22,7 +22,7 @@ namespace Artemis.Modules.Effects.WindowsProfile IParameter[] args = { new ConstructorArgument("mainManager", main), - new ConstructorArgument("gameModel", (WindowsProfileModel) EffectModel), + new ConstructorArgument("effectModel", (WindowsProfileModel) EffectModel), new ConstructorArgument("lastProfile", ((WindowsProfileSettings) EffectSettings).LastProfile) }; ProfileEditor = kernel.Get(args); diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs index 452f2d51e..cb4ffe5a4 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs @@ -22,9 +22,10 @@ namespace Artemis.Modules.Games.CounterStrike private DateTime _lastKill; private int _lastKills; - public CounterStrikeModel(DeviceManager deviceManager, GameStateWebServer gameStateWebServer, - MetroDialogService dialogService) - : base(deviceManager, SettingsProvider.Load(), new CounterStrikeDataModel()) + public CounterStrikeModel(DeviceManager deviceManager, LuaManager luaManager, + GameStateWebServer gameStateWebServer, MetroDialogService dialogService) + : base(deviceManager, luaManager, SettingsProvider.Load(), + new CounterStrikeDataModel()) { _gameStateWebServer = gameStateWebServer; _dialogService = dialogService; @@ -51,6 +52,8 @@ namespace Artemis.Modules.Games.CounterStrike public override void Enable() { + base.Enable(); + _gameStateWebServer.GameDataReceived += HandleGameData; Initialized = true; } diff --git a/Artemis/Artemis/Modules/Games/Dota2/Dota2Model.cs b/Artemis/Artemis/Modules/Games/Dota2/Dota2Model.cs index 8029a5da3..f482bc71b 100644 --- a/Artemis/Artemis/Modules/Games/Dota2/Dota2Model.cs +++ b/Artemis/Artemis/Modules/Games/Dota2/Dota2Model.cs @@ -17,9 +17,9 @@ namespace Artemis.Modules.Games.Dota2 private readonly MetroDialogService _dialogService; private readonly GameStateWebServer _gameStateWebServer; - public Dota2Model(DeviceManager deviceManager, GameStateWebServer gameStateWebServer, + public Dota2Model(DeviceManager deviceManager, LuaManager luaManager, GameStateWebServer gameStateWebServer, MetroDialogService dialogService) - : base(deviceManager, SettingsProvider.Load(), new Dota2DataModel()) + : base(deviceManager, luaManager, SettingsProvider.Load(), new Dota2DataModel()) { _gameStateWebServer = gameStateWebServer; _dialogService = dialogService; @@ -45,6 +45,8 @@ namespace Artemis.Modules.Games.Dota2 public override void Enable() { + base.Enable(); + _gameStateWebServer.GameDataReceived += HandleGameData; Initialized = true; } @@ -109,8 +111,8 @@ namespace Artemis.Modules.Games.Dota2 if (dataModel?.map?.daytime == null) return; - var timeLeft = 240 - dataModel.map.clock_time%240; - dataModel.map.dayCyclePercentage = (int) (100.00/240*timeLeft); + var timeLeft = 240 - dataModel.map.clock_time % 240; + dataModel.map.dayCyclePercentage = (int) (100.00 / 240 * timeLeft); } public void HandleGameData(object sender, GameDataReceivedEventArgs e) diff --git a/Artemis/Artemis/Modules/Games/Dota2/Dota2Settings.cs b/Artemis/Artemis/Modules/Games/Dota2/Dota2Settings.cs index 771460b2a..af00d84e0 100644 --- a/Artemis/Artemis/Modules/Games/Dota2/Dota2Settings.cs +++ b/Artemis/Artemis/Modules/Games/Dota2/Dota2Settings.cs @@ -2,7 +2,7 @@ namespace Artemis.Modules.Games.Dota2 { - internal class Dota2Settings : GameSettings + public class Dota2Settings : GameSettings { public string GameDirectory { get; set; } } diff --git a/Artemis/Artemis/Modules/Games/EurotruckSimulator2/Data/Ets2TelemetryData.cs b/Artemis/Artemis/Modules/Games/EurotruckSimulator2/Data/Ets2TelemetryData.cs index a98f267cd..307f1b246 100644 --- a/Artemis/Artemis/Modules/Games/EurotruckSimulator2/Data/Ets2TelemetryData.cs +++ b/Artemis/Artemis/Modules/Games/EurotruckSimulator2/Data/Ets2TelemetryData.cs @@ -4,7 +4,7 @@ using Artemis.Modules.Games.EurotruckSimulator2.Data.Reader; namespace Artemis.Modules.Games.EurotruckSimulator2.Data { - internal class Ets2TelemetryData : IEts2TelemetryData + public class Ets2TelemetryData : IEts2TelemetryData { private Box _rawData; @@ -38,7 +38,7 @@ namespace Artemis.Modules.Games.EurotruckSimulator2.Data } } - internal class Ets2Game : IEts2Game + public class Ets2Game : IEts2Game { private readonly Box _rawData; @@ -55,7 +55,7 @@ namespace Artemis.Modules.Games.EurotruckSimulator2.Data public string TelemetryPluginVersion => _rawData.Struct.ets2_telemetry_plugin_revision.ToString(); } - internal class Ets2Vector : IEts2Vector + public class Ets2Vector : IEts2Vector { public Ets2Vector(float x, float y, float z) { @@ -69,7 +69,7 @@ namespace Artemis.Modules.Games.EurotruckSimulator2.Data public float Z { get; } } - internal class Ets2Placement : IEts2Placement + public class Ets2Placement : IEts2Placement { public Ets2Placement(float x, float y, float z, float heading, float pitch, float roll) @@ -90,7 +90,7 @@ namespace Artemis.Modules.Games.EurotruckSimulator2.Data public float Roll { get; } } - internal class Ets2Truck : IEts2Truck + public class Ets2Truck : IEts2Truck { private readonly Box _rawData; @@ -242,7 +242,7 @@ namespace Artemis.Modules.Games.EurotruckSimulator2.Data */ } - internal class Ets2Trailer : IEts2Trailer + public class Ets2Trailer : IEts2Trailer { private readonly Box _rawData; @@ -271,7 +271,7 @@ namespace Artemis.Modules.Games.EurotruckSimulator2.Data _rawData.Struct.trailerRotationZ); } - internal class Ets2Navigation : IEts2Navigation + public class Ets2Navigation : IEts2Navigation { private readonly Box _rawData; @@ -288,7 +288,7 @@ namespace Artemis.Modules.Games.EurotruckSimulator2.Data _rawData.Struct.navigationSpeedLimit > 0 ? (int) Math.Round(_rawData.Struct.navigationSpeedLimit*3.6f) : 0; } - internal class Ets2Job : IEts2Job + public class Ets2Job : IEts2Job { private readonly Box _rawData; @@ -355,7 +355,7 @@ namespace Artemis.Modules.Games.EurotruckSimulator2.Data } */ - internal class Box where T : struct + public class Box where T : struct { public Box(T @struct) { diff --git a/Artemis/Artemis/Modules/Games/EurotruckSimulator2/Data/Reader/Ets2TelemetryStructure.cs b/Artemis/Artemis/Modules/Games/EurotruckSimulator2/Data/Reader/Ets2TelemetryStructure.cs index 89f1edaff..c80678afa 100644 --- a/Artemis/Artemis/Modules/Games/EurotruckSimulator2/Data/Reader/Ets2TelemetryStructure.cs +++ b/Artemis/Artemis/Modules/Games/EurotruckSimulator2/Data/Reader/Ets2TelemetryStructure.cs @@ -3,7 +3,7 @@ using System.Runtime.InteropServices; namespace Artemis.Modules.Games.EurotruckSimulator2.Data.Reader { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal struct Ets2TelemetryStructure + public struct Ets2TelemetryStructure { private const int GeneralStringSize = 64; diff --git a/Artemis/Artemis/Modules/Games/EurotruckSimulator2/Data/Reader/SharedProcessMemory.cs b/Artemis/Artemis/Modules/Games/EurotruckSimulator2/Data/Reader/SharedProcessMemory.cs index 6de2569a4..1bd0ab7b2 100644 --- a/Artemis/Artemis/Modules/Games/EurotruckSimulator2/Data/Reader/SharedProcessMemory.cs +++ b/Artemis/Artemis/Modules/Games/EurotruckSimulator2/Data/Reader/SharedProcessMemory.cs @@ -4,7 +4,7 @@ using System.Runtime.InteropServices; namespace Artemis.Modules.Games.EurotruckSimulator2.Data.Reader { - internal class SharedProcessMemory : IDisposable + public class SharedProcessMemory : IDisposable { private readonly string _mapName; private MemoryMappedViewAccessor _memoryMappedAccessor; diff --git a/Artemis/Artemis/Modules/Games/EurotruckSimulator2/EurotruckSimulator2Model.cs b/Artemis/Artemis/Modules/Games/EurotruckSimulator2/EurotruckSimulator2Model.cs index 2df7313e9..1a9409b1a 100644 --- a/Artemis/Artemis/Modules/Games/EurotruckSimulator2/EurotruckSimulator2Model.cs +++ b/Artemis/Artemis/Modules/Games/EurotruckSimulator2/EurotruckSimulator2Model.cs @@ -18,9 +18,10 @@ namespace Artemis.Modules.Games.EurotruckSimulator2 { private readonly MetroDialogService _dialogService; - public EurotruckSimulator2Model(DeviceManager deviceManager, MetroDialogService dialogService) - : base( - deviceManager, SettingsProvider.Load(), new EurotruckSimulator2DataModel()) + public EurotruckSimulator2Model(DeviceManager deviceManager, LuaManager luaManager, + MetroDialogService dialogService) + : base(deviceManager, luaManager, SettingsProvider.Load(), + new EurotruckSimulator2DataModel()) { _dialogService = dialogService; Name = "EurotruckSimulator2"; @@ -42,6 +43,8 @@ namespace Artemis.Modules.Games.EurotruckSimulator2 public override void Enable() { + base.Enable(); + Initialized = true; } diff --git a/Artemis/Artemis/Modules/Games/GtaV/GtaVModel.cs b/Artemis/Artemis/Modules/Games/GtaV/GtaVModel.cs index 20c185ee9..1dd4293f2 100644 --- a/Artemis/Artemis/Modules/Games/GtaV/GtaVModel.cs +++ b/Artemis/Artemis/Modules/Games/GtaV/GtaVModel.cs @@ -15,8 +15,8 @@ namespace Artemis.Modules.Games.GtaV { private readonly PipeServer _pipeServer; - public GtaVModel(DeviceManager deviceManager, PipeServer pipeServer) - : base(deviceManager, SettingsProvider.Load(), new GtaVDataModel()) + public GtaVModel(DeviceManager deviceManager, LuaManager luaManager, PipeServer pipeServer) + : base(deviceManager, luaManager, SettingsProvider.Load(), new GtaVDataModel()) { _pipeServer = pipeServer; Name = "GTAV"; @@ -27,6 +27,8 @@ namespace Artemis.Modules.Games.GtaV public override void Enable() { + base.Enable(); + DllManager.PlaceLogitechDll(); _pipeServer.PipeMessage += PipeServerOnPipeMessage; Initialized = true; diff --git a/Artemis/Artemis/Modules/Games/LightFx/Data/LightFxState.cs b/Artemis/Artemis/Modules/Games/LightFx/Data/LightFxState.cs new file mode 100644 index 000000000..287b8d075 --- /dev/null +++ b/Artemis/Artemis/Modules/Games/LightFx/Data/LightFxState.cs @@ -0,0 +1,40 @@ +using MoonSharp.Interpreter; + +namespace Artemis.Modules.Games.LightFx.Data +{ + [MoonSharpUserData] + public class LightFxState + { + public Device[] devices { get; set; } + public string game { get; set; } + public Mask mask { get; set; } + } + + [MoonSharpUserData] + public class Device + { + public Light[] lights { get; set; } + } + + [MoonSharpUserData] + public class Mask + { + public Light light { get; set; } + public int location { get; set; } + } + + [MoonSharpUserData] + public class Light + { + public Color color { get; set; } + } + + [MoonSharpUserData] + public class Color + { + public int brightness { get; set; } + public int red { get; set; } + public int green { get; set; } + public int blue { get; set; } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/LightFx/LightFxDataModel.cs b/Artemis/Artemis/Modules/Games/LightFx/LightFxDataModel.cs new file mode 100644 index 000000000..aa86630e2 --- /dev/null +++ b/Artemis/Artemis/Modules/Games/LightFx/LightFxDataModel.cs @@ -0,0 +1,19 @@ +using Artemis.Models.Interfaces; +using Artemis.Modules.Games.LightFx.Data; +using MoonSharp.Interpreter; +using Newtonsoft.Json; + +namespace Artemis.Modules.Games.LightFx +{ + [MoonSharpUserData] + public class LightFxDataModel : IDataModel + { + [JsonProperty(PropertyName = "lightFxState")] + public LightFxState LightFxState { get; set; } + + public LightFxDataModel() + { + LightFxState = new LightFxState(); + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/LightFx/LightFxModel.cs b/Artemis/Artemis/Modules/Games/LightFx/LightFxModel.cs new file mode 100644 index 000000000..3d77bc907 --- /dev/null +++ b/Artemis/Artemis/Modules/Games/LightFx/LightFxModel.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Artemis.DAL; +using Artemis.Managers; +using Artemis.Models; +using Artemis.Profiles.Layers.Models; +using Artemis.Utilities.DataReaders; +using Newtonsoft.Json; + +namespace Artemis.Modules.Games.LightFx +{ + public class LightFxModel : GameModel + { + public LightFxModel(DeviceManager deviceManager, LuaManager luaManager, PipeServer pipeServer) + : base(deviceManager, luaManager, SettingsProvider.Load(), new LightFxDataModel()) + { + Name = "LightFX"; + ProcessName = "LoL"; + Scale = 4; + Enabled = Settings.Enabled; + Initialized = false; + + // This model can enable itself by changing its process name to the currently running Light FX game. + pipeServer.PipeMessage += PipeServerOnPipeMessage; + } + + public int Scale { get; set; } + + private void PipeServerOnPipeMessage(string msg) + { + // Ensure it's Light FX JSON + if (!msg.Contains("lightFxState")) + return; + + // Deserialize and data + try + { + JsonConvert.PopulateObject(msg, DataModel); + } + catch (Exception ex) + { + Logger?.Error(ex, "Failed to deserialize LightFX JSON"); + throw; + } + + // Setup process name + ProcessName = Path.GetFileNameWithoutExtension(((LightFxDataModel) DataModel).LightFxState.game); + } + + public override void Dispose() + { + Initialized = false; + base.Dispose(); + } + + public override void Enable() + { + base.Enable(); + + Initialized = true; + } + + public override void Update() + { + } + + public override List GetRenderLayers(bool keyboardOnly) + { + return Profile.GetRenderLayers(DataModel, keyboardOnly); + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/LightFx/LightFxSettings.cs b/Artemis/Artemis/Modules/Games/LightFx/LightFxSettings.cs new file mode 100644 index 000000000..a1f31124a --- /dev/null +++ b/Artemis/Artemis/Modules/Games/LightFx/LightFxSettings.cs @@ -0,0 +1,8 @@ +using Artemis.Settings; + +namespace Artemis.Modules.Games.LightFx +{ + public class LightFxSettings : GameSettings + { + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/LightFx/LightFxView.xaml b/Artemis/Artemis/Modules/Games/LightFx/LightFxView.xaml new file mode 100644 index 000000000..19e045370 --- /dev/null +++ b/Artemis/Artemis/Modules/Games/LightFx/LightFxView.xaml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +