diff --git a/Artemis/Artemis/App.config b/Artemis/Artemis/App.config index 78fd4a68d..af9997c3f 100644 --- a/Artemis/Artemis/App.config +++ b/Artemis/Artemis/App.config @@ -2,65 +2,26 @@ - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -330,7 +291,7 @@ - + diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index e74a5a795..707d8f05a 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -40,7 +40,7 @@ Artemis Artemis 0 - 1.2.2.0 + 1.2.3.0 false true true @@ -141,8 +141,8 @@ False lib\ColorBox.dll - - ..\packages\Colore.4.0.0\lib\net35\Corale.Colore.dll + + ..\packages\Colore.5.0.0\lib\net35\Corale.Colore.dll True @@ -176,8 +176,8 @@ ..\packages\NAudio.1.7.3\lib\net35\NAudio.dll True - - ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll True @@ -197,7 +197,7 @@ True - ..\packages\NLog.4.3.4\lib\net45\NLog.dll + ..\packages\NLog.4.3.7\lib\net45\NLog.dll True @@ -205,7 +205,7 @@ D:\Downloads\Chome Downloads\Process.NET-master\Process.NET-master\src\Process.NET\bin\Release\Process.NET.dll - ..\packages\SpotifyAPI-NET.2.9.0\lib\SpotifyAPI.dll + ..\packages\SpotifyAPI-NET.2.11.0\lib\SpotifyAPI.dll True @@ -639,6 +639,9 @@ SettingsSingleFileGenerator WoW.Designer.cs + + Designer + @@ -686,9 +689,6 @@ SettingsSingleFileGenerator VolumeDisplay.Designer.cs - - Designer - Designer @@ -878,6 +878,7 @@ PreserveNewest + diff --git a/Artemis/Artemis/DAL/ProfileProvider.cs b/Artemis/Artemis/DAL/ProfileProvider.cs index 6f64cf8dd..0af504d90 100644 --- a/Artemis/Artemis/DAL/ProfileProvider.cs +++ b/Artemis/Artemis/DAL/ProfileProvider.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.IO; using System.IO.Compression; using System.Linq; @@ -19,9 +20,10 @@ namespace Artemis.DAL { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - private static readonly string ProfileFolder = Environment - .GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\profiles"; + private static readonly string ProfileFolder = + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\profiles"; + private static readonly List Profiles = new List(); private static bool _installedDefaults; /// @@ -30,7 +32,15 @@ namespace Artemis.DAL /// All profiles public static List GetAll() { - return ReadProfiles(); + lock (Profiles) + { + if (!Profiles.Any()) + ReadProfiles(); + + // Return a new list, this'll make sure removing/updating the retrieved list doesn't + // affect the datastore + return Profiles.ToList(); + } } /// @@ -59,8 +69,15 @@ namespace Artemis.DAL if (prof == null) throw new ArgumentNullException(nameof(prof)); + lock (Profiles) + { + if (!Profiles.Contains(prof)) + Profiles.Add(prof); + } + lock (prof) { + // Store the file if (!(prof.GameName?.Length > 1) || !(prof.KeyboardSlug?.Length > 1) || !(prof.Name?.Length > 1)) throw new ArgumentException("Profile is invalid. Name, GameName and KeyboardSlug are required"); @@ -86,31 +103,43 @@ namespace Artemis.DAL } } - private static List ReadProfiles() + private static void ReadProfiles() { CheckProfiles(); - InstallDefaults(); - var profiles = new List(); - - // Create the directory structure - var profilePaths = Directory.GetFiles(ProfileFolder, "*.json", SearchOption.AllDirectories); - - // Parse the JSON files into objects and add them if they are valid - foreach (var path in profilePaths) + lock (Profiles) { - try + Profiles.Clear(); + + // Create the directory structure + var profilePaths = Directory.GetFiles(ProfileFolder, "*.json", SearchOption.AllDirectories); + + // Parse the JSON files into objects and add them if they are valid + foreach (var path in profilePaths) { - var prof = LoadProfileIfValid(path); - if (prof != null) - profiles.Add(prof); - } - catch (Exception e) - { - Logger.Error("Failed to load profile: {0} - {1}", path, e.InnerException.Message); + try + { + var prof = LoadProfileIfValid(path); + if (prof == null) + continue; + + // Only add unique profiles + if (Profiles.Any(p => p.GameName == prof.GameName && p.Name == prof.Name && + p.KeyboardSlug == prof.KeyboardSlug)) + { + Logger.Error("Didn't load duplicate profile: {0}", path); + } + else + { + Profiles.Add(prof); + } + } + catch (Exception e) + { + Logger.Error("Failed to load profile: {0} - {1}", path, e.InnerException.Message); + } } } - - return profiles; + InstallDefaults(); } /// @@ -133,23 +162,27 @@ namespace Artemis.DAL var archive = new ZipArchive(stream); archive.ExtractToDirectory(ProfileFolder, true); - // Extract the demo GIF file - var gifPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\demo-gif.gif"; - Resources.demo_gif.Save(gifPath); + var demoProfiles = Profiles.Where(d => d.Name == "Demo (duplicate to keep changes)"); + InsertGif(demoProfiles, "GIF", Resources.demo_gif, "demo-gif"); + } - // Set the GIF path on each demo profile - var demoProfiles = GetAll().Where(d => d.Name == "Demo (Duplicate to keep changes)"); - foreach (var demoProfile in demoProfiles) + public static void InsertGif(IEnumerable profileModels, string layerName, Bitmap gifFile, + string fileName) + { + // Extract the GIF file + var gifDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\gifs"; + Directory.CreateDirectory(gifDir); + var gifPath = gifDir + $"\\{fileName}.gif"; + gifFile.Save(gifPath); + + foreach (var profile in profileModels) { - var gifLayer = demoProfile - .Layers.FirstOrDefault(l => l.Name == "Demo - GIFs")? - .Children.FirstOrDefault(c => c.Name == "GIF"); - + var gifLayer = profile.GetLayers().FirstOrDefault(l => l.Name == layerName); if (gifLayer == null) continue; ((KeyboardPropertiesModel) gifLayer.Properties).GifFile = gifPath; - AddOrUpdate(demoProfile); + AddOrUpdate(profile); } } @@ -208,20 +241,29 @@ namespace Artemis.DAL if (string.IsNullOrEmpty(name)) return; - // Remove the old file - var path = ProfileFolder + $@"\{profile.KeyboardSlug}\{profile.GameName}\{profile.Name}.json"; - if (File.Exists(path)) - File.Delete(path); + // Remove the old profile + DeleteProfile(profile); // Update the profile, creating a new file profile.Name = name; AddOrUpdate(profile); } - public static void DeleteProfile(ProfileModel profile) + public static void DeleteProfile(ProfileModel prof) { + // Remove from datastore + lock (Profiles) + { + // Get the profile from the datastore instead of just the provided value, to be certain it is removed + var dsProfile = Profiles.FirstOrDefault(p => p.GameName == prof.GameName && + p.Name == prof.Name && + p.KeyboardSlug == prof.KeyboardSlug); + if (dsProfile != null) + Profiles.Remove(dsProfile); + } + // Remove the file - var path = ProfileFolder + $@"\{profile.KeyboardSlug}\{profile.GameName}\{profile.Name}.json"; + var path = ProfileFolder + $@"\{prof.KeyboardSlug}\{prof.GameName}\{prof.Name}.json"; if (File.Exists(path)) File.Delete(path); } diff --git a/Artemis/Artemis/DeviceProviders/Razer/BlackWidow.cs b/Artemis/Artemis/DeviceProviders/Razer/BlackWidow.cs index f4eb56cf7..5aa6e9c1e 100644 --- a/Artemis/Artemis/DeviceProviders/Razer/BlackWidow.cs +++ b/Artemis/Artemis/DeviceProviders/Razer/BlackWidow.cs @@ -28,7 +28,7 @@ namespace Artemis.DeviceProviders.Razer public override bool CanEnable() { - if (!Chroma.IsSdkAvailable()) + if (!Chroma.SdkAvailable) return false; // Some people have Synapse installed, but not a Chroma keyboard, deal with this diff --git a/Artemis/Artemis/DeviceProviders/Razer/Utilities/RazerUtilities.cs b/Artemis/Artemis/DeviceProviders/Razer/Utilities/RazerUtilities.cs index b8a380416..2ec0ebd43 100644 --- a/Artemis/Artemis/DeviceProviders/Razer/Utilities/RazerUtilities.cs +++ b/Artemis/Artemis/DeviceProviders/Razer/Utilities/RazerUtilities.cs @@ -1,6 +1,7 @@ using System.Drawing; using Artemis.Utilities; using Corale.Colore.Razer.Keyboard.Effects; +using Color = Corale.Colore.Core.Color; namespace Artemis.DeviceProviders.Razer.Utilities { @@ -13,8 +14,13 @@ namespace Artemis.DeviceProviders.Razer.Utilities b = ImageUtilities.ResizeImage(b, width, height); for (var y = 0; y < b.Height; y++) + { for (var x = 0; x < b.Width; x++) - keyboardGrid[y, x] = b.GetPixel(x, y); + { + var pixel = b.GetPixel(x, y); + keyboardGrid[y, x] = new Color(pixel.R, pixel.G, pixel.B); + } + } return keyboardGrid; } diff --git a/Artemis/Artemis/Modules/Games/UnrealTournament/Resources/redeemer.gif b/Artemis/Artemis/Modules/Games/UnrealTournament/Resources/redeemer.gif new file mode 100644 index 000000000..8b5947845 Binary files /dev/null and b/Artemis/Artemis/Modules/Games/UnrealTournament/Resources/redeemer.gif differ diff --git a/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentDataModel.cs b/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentDataModel.cs index bbebe08cc..aa2deb1b9 100644 --- a/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentDataModel.cs +++ b/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentDataModel.cs @@ -76,8 +76,8 @@ namespace Artemis.Modules.Games.UnrealTournament { Unzoomed = 0, Zoomed = 3, - ZoomingIn = 2, - ZoomingOut = 1 + ZoomingIn = 1, + ZoomingOut = 2 } public class Environment diff --git a/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentModel.cs b/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentModel.cs index 87cee5f9b..a1863c2f9 100644 --- a/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentModel.cs +++ b/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentModel.cs @@ -3,16 +3,12 @@ using System.Collections.Generic; using Artemis.Managers; using Artemis.Models; using Artemis.Profiles.Layers.Models; -using Artemis.Utilities.Memory; using Newtonsoft.Json; namespace Artemis.Modules.Games.UnrealTournament { public class UnrealTournamentModel : GameModel { - private Memory _memory; - private GamePointersCollection _pointer; - public UnrealTournamentModel(MainManager mainManager, UnrealTournamentSettings settings) : base(mainManager, settings, new UnrealTournamentDataModel()) { diff --git a/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentViewModel.cs b/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentViewModel.cs index a14835697..fc19fc0fe 100644 --- a/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentViewModel.cs +++ b/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentViewModel.cs @@ -4,8 +4,10 @@ using System.IO.Compression; using System.Linq; using System.Reflection; using System.Windows.Forms; +using Artemis.DAL; using Artemis.InjectionFactories; using Artemis.Managers; +using Artemis.Properties; using Artemis.Utilities; using Artemis.ViewModels.Abstract; using Caliburn.Micro; @@ -22,6 +24,7 @@ namespace Artemis.Modules.Games.UnrealTournament DisplayName = "Unreal Tournament"; MainManager.EffectManager.EffectModels.Add(GameModel); FindGame(); + InstallGif(); } public UnrealTournamentModel UnrealTournamentModel { get; set; } @@ -112,5 +115,12 @@ namespace Artemis.Modules.Games.UnrealTournament MainManager.Logger.Info("Installed Unreal Tournament plugin in '{0}'", path); } + + private void InstallGif() + { + var gif = Resources.redeemer; + ProfileProvider.InsertGif(ProfileProvider.GetAll() + .Where(p => p.GameName == "UnrealTournament" && p.Name == "Default"), "Redeemer GIF", gif, "redeemer"); + } } } \ No newline at end of file diff --git a/Artemis/Artemis/NLog.xsd b/Artemis/Artemis/NLog.xsd index dc821bc0d..c489255c0 100644 --- a/Artemis/Artemis/NLog.xsd +++ b/Artemis/Artemis/NLog.xsd @@ -232,7 +232,6 @@ - @@ -1020,8 +1019,8 @@ - + @@ -1093,16 +1092,16 @@ Size in bytes above which log files will be automatically archived. Warning: combining this with isn't supported. We cannot create multiple archive files, if they should have the same name. Choose: - - - Maximum number of archive files that should be kept. - - Indicates whether to compress archive files into the zip archive format. + + + Maximum number of archive files that should be kept. + + Gets or set a value indicating whether a managed file stream is forced, instead of used the native implementation. @@ -2238,6 +2237,18 @@ + + + + + + + + + + + + @@ -2334,8 +2345,14 @@ + + + + Option to render the empty object value {} + + Option to suppress the extra spaces in the output json diff --git a/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioType.cs b/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioType.cs index 9f66a28ea..7fd087c40 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioType.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioType.cs @@ -22,16 +22,13 @@ namespace Artemis.Profiles.Layers.Types.Audio { private readonly List _audioLayers = new List(); private readonly MMDevice _device; - private readonly MainManager _mainManager; private readonly SampleAggregator _sampleAggregator = new SampleAggregator(2048); private readonly WasapiLoopbackCapture _waveIn; private int _lines; private AudioPropertiesModel _previousSettings; - private AudioPropertiesModel _properties; public AudioType(MainManager mainManager) { - _mainManager = mainManager; _device = new MMDeviceEnumerator().EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active).FirstOrDefault(); diff --git a/Artemis/Artemis/Properties/Resources.Designer.cs b/Artemis/Artemis/Properties/Resources.Designer.cs index 5e15b7281..99580a00c 100644 --- a/Artemis/Artemis/Properties/Resources.Designer.cs +++ b/Artemis/Artemis/Properties/Resources.Designer.cs @@ -288,6 +288,16 @@ namespace Artemis.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap redeemer { + get { + object obj = ResourceManager.GetObject("redeemer", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Byte[]. /// diff --git a/Artemis/Artemis/Properties/Resources.resx b/Artemis/Artemis/Properties/Resources.resx index ad8bc3f95..4d198f614 100644 --- a/Artemis/Artemis/Properties/Resources.resx +++ b/Artemis/Artemis/Properties/Resources.resx @@ -190,4 +190,7 @@ ..\Modules\Games\Witcher3\Resources\witcher3-mod.zip;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Modules\Games\UnrealTournament\Resources\redeemer.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/Artemis/Artemis/Resources/Keyboards/default-profiles.zip b/Artemis/Artemis/Resources/Keyboards/default-profiles.zip index fc967a61f..dba026291 100644 Binary files a/Artemis/Artemis/Resources/Keyboards/default-profiles.zip and b/Artemis/Artemis/Resources/Keyboards/default-profiles.zip differ diff --git a/Artemis/Artemis/Utilities/Updater.cs b/Artemis/Artemis/Utilities/Updater.cs index 6bd7c6ed9..adb673416 100644 --- a/Artemis/Artemis/Utilities/Updater.cs +++ b/Artemis/Artemis/Utilities/Updater.cs @@ -15,12 +15,12 @@ namespace Artemis.Utilities { public static class Updater { - public static int CurrentVersion = 1220; + public static int CurrentVersion = 1230; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public static async Task CheckForUpdate(MetroDialogService dialogService) { - Logger.Info("Checking for updates - Current version: 1.2.2.0"); + Logger.Info("Checking for updates - Current version: 1.2.3.0"); if (!General.Default.CheckForUpdates) return null; diff --git a/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs index 69ff51984..94f599d50 100644 --- a/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs @@ -518,38 +518,30 @@ namespace Artemis.ViewModels.Profiles { if (SelectedProfile == null) return; - - var oldName = SelectedProfile.Name; - SelectedProfile.Name = await DialogService - .ShowInputDialog("Rename profile", "Please enter a unique new profile name"); + + var name = await DialogService.ShowInputDialog("Rename profile", "Please enter a unique new profile name"); // Null when the user cancelled - if (string.IsNullOrEmpty(SelectedProfile.Name) || SelectedProfile.Name.Length < 2) - { - SelectedProfile.Name = oldName; + if (string.IsNullOrEmpty(name) || name.Length < 2) return; - } // Verify the name - while (ProfileProvider.GetAll().Contains(SelectedProfile)) + while (ProfileProvider.GetAll().Any(p => p.Name == name && p.GameName == SelectedProfile.GameName && + p.KeyboardSlug == SelectedProfile.KeyboardSlug)) { - SelectedProfile.Name = await DialogService. - ShowInputDialog("Name already in use", "Please enter a unique new profile name"); + name = await DialogService.ShowInputDialog("Name already in use", "Please enter a unique new profile name"); // Null when the user cancelled - if (string.IsNullOrEmpty(SelectedProfile.Name) || SelectedProfile.Name.Length < 2) - { - SelectedProfile.Name = oldName; + if (string.IsNullOrEmpty(name) || name.Length < 2) return; - } } - var newName = SelectedProfile.Name; - SelectedProfile.Name = oldName; - ProfileProvider.RenameProfile(SelectedProfile, newName); - + var profile = SelectedProfile; + SelectedProfile = null; + ProfileProvider.RenameProfile(profile, name); + + LastProfile = name; LoadProfiles(); - SelectedProfile = Profiles.FirstOrDefault(p => p.Name == newName); } public async void DuplicateProfile() diff --git a/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml b/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml index c49fedda6..9d98bfff7 100644 --- a/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml +++ b/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml @@ -113,7 +113,7 @@ -