From 5384ddb0efa2c13a7aef852a135f012563b693ad Mon Sep 17 00:00:00 2001 From: Will Bennion Date: Wed, 13 May 2020 10:11:46 +0100 Subject: [PATCH 1/9] Removed IStringProperty. Added FastMember as a replacement. --- .../Project-Aurora/NetworkListener.cs | 2 +- .../Profiles/Desktop/DesktopApplication.cs | 28 +- .../Profiles/Dota 2/GSI/Nodes/Abilities.cs | 5 - .../Profiles/GTA5/GSI/GameState_GTA5.cs | 2 +- .../Project-Aurora/Profiles/GameState.cs | 257 +----------------- .../Profiles/GameState_Wrapper.cs | 6 +- .../Project-Aurora/Profiles/LightEvent.cs | 2 +- .../Profiles/LocalPCInformation.cs | 229 ++++++++++++++++ .../Project-Aurora/Profiles/Node.cs | 104 ++----- .../Project-Aurora/Profiles/StringProperty.cs | 129 --------- .../Project-Aurora/Project-Aurora.csproj | 5 +- .../Project-Aurora/Settings/Layers/Layer.cs | 8 +- .../Settings/Layers/LayerHandler.cs | 46 +++- .../Overrides/Control_OverridesEditor.xaml.cs | 4 +- .../Project-Aurora/Utils/GameStateUtils.cs | 6 +- 15 files changed, 336 insertions(+), 497 deletions(-) create mode 100644 Project-Aurora/Project-Aurora/Profiles/LocalPCInformation.cs delete mode 100644 Project-Aurora/Project-Aurora/Profiles/StringProperty.cs diff --git a/Project-Aurora/Project-Aurora/NetworkListener.cs b/Project-Aurora/Project-Aurora/NetworkListener.cs index ccd69d4e2..c80ca6a90 100644 --- a/Project-Aurora/Project-Aurora/NetworkListener.cs +++ b/Project-Aurora/Project-Aurora/NetworkListener.cs @@ -228,7 +228,7 @@ private void ReceiveGameState(IAsyncResult result) response.ContentLength64 = 0; response.Close(); } - CurrentGameState = new GameState(JSON); + CurrentGameState = new EmptyGameState(JSON); } private void HandleNewIPCGameState(string gs_data) diff --git a/Project-Aurora/Project-Aurora/Profiles/Desktop/DesktopApplication.cs b/Project-Aurora/Project-Aurora/Profiles/Desktop/DesktopApplication.cs index be1628d47..078c99310 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Desktop/DesktopApplication.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Desktop/DesktopApplication.cs @@ -1,19 +1,13 @@ -using Aurora.Settings; -using Newtonsoft.Json; -using System; -using System.IO; -using System.Text; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Media.Imaging; - -namespace Aurora.Profiles.Desktop -{ - public class Desktop : Application - { - public Desktop() - : base(new LightEventConfig { Name = "Desktop", ID = "desktop", ProfileType = typeof(DesktopProfile), OverviewControlType = typeof(Control_Desktop), GameStateType = typeof(GameState), Event = new Event_Desktop(), IconURI= "Resources/desktop_icon.png" }) - { - } +namespace Aurora.Profiles.Desktop { + public class Desktop : Application { + public Desktop() : base(new LightEventConfig { + Name = "Desktop", + ID = "desktop", + ProfileType = typeof(DesktopProfile), + OverviewControlType = typeof(Control_Desktop), + GameStateType = typeof(EmptyGameState), + Event = new Event_Desktop(), + IconURI = "Resources/desktop_icon.png" + }) { } } } diff --git a/Project-Aurora/Project-Aurora/Profiles/Dota 2/GSI/Nodes/Abilities.cs b/Project-Aurora/Project-Aurora/Profiles/Dota 2/GSI/Nodes/Abilities.cs index db2fec10c..915dcf01b 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Dota 2/GSI/Nodes/Abilities.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Dota 2/GSI/Nodes/Abilities.cs @@ -54,11 +54,6 @@ public Ability this[int index] } } - public override string ToString() - { - return json; - } - public IEnumerator GetEnumerator() { return abilities.GetEnumerator(); diff --git a/Project-Aurora/Project-Aurora/Profiles/GTA5/GSI/GameState_GTA5.cs b/Project-Aurora/Project-Aurora/Profiles/GTA5/GSI/GameState_GTA5.cs index f3a2384f3..ce2af985e 100644 --- a/Project-Aurora/Project-Aurora/Profiles/GTA5/GSI/GameState_GTA5.cs +++ b/Project-Aurora/Project-Aurora/Profiles/GTA5/GSI/GameState_GTA5.cs @@ -177,7 +177,7 @@ public GameState_GTA5(string json_data) : base(json_data) /// A copy constructor, creates a GameState_GTA5 instance based on the data from the passed GameState instance. /// /// The passed GameState - public GameState_GTA5(GameState other_state) : base(other_state) + public GameState_GTA5(IGameState other_state) : base(other_state) { GameState_GTA5 gta = other_state as GameState_GTA5; if (gta != null) diff --git a/Project-Aurora/Project-Aurora/Profiles/GameState.cs b/Project-Aurora/Project-Aurora/Profiles/GameState.cs index b520aa1bc..279e099b1 100644 --- a/Project-Aurora/Project-Aurora/Profiles/GameState.cs +++ b/Project-Aurora/Project-Aurora/Profiles/GameState.cs @@ -45,7 +45,7 @@ public interface IGameState string GetNode(string name); } - public class GameState : StringProperty, IGameState where TSelf : GameState + public class GameState : IGameState where TSelf : GameState { private static LocalPCInformation _localpcinfo; @@ -66,7 +66,7 @@ public class GameState : StringProperty, IGameState where TSelf : public GameState() : base() { json = "{}"; - _ParsedData = Newtonsoft.Json.Linq.JObject.Parse(json); + _ParsedData = JObject.Parse(json); } /// @@ -79,7 +79,7 @@ public GameState(string json_data) : base() json_data = "{}"; json = json_data; - _ParsedData = Newtonsoft.Json.Linq.JObject.Parse(json_data); + _ParsedData = JObject.Parse(json_data); } /// @@ -92,260 +92,33 @@ public GameState(IGameState other_state) : base() json = other_state.json; } - [GameStateIgnore] public string GetNode(string name) - { - Newtonsoft.Json.Linq.JToken value; - - if (_ParsedData.TryGetValue(name, StringComparison.OrdinalIgnoreCase, out value)) - return value.ToString(); - else - return ""; - } + /// + /// Gets the JSON for a child node in this GameState. + /// + public string GetNode(string name) => + _ParsedData.TryGetValue(name, StringComparison.OrdinalIgnoreCase, out var value) ? value.ToString() : ""; /// /// Use this method to more-easily lazily return the child node of the given name that exists on this AutoNode. /// - [GameStateIgnore] protected TNode NodeFor(string name) where TNode : Node + protected TNode NodeFor(string name) where TNode : Node => (TNode)(childNodes.TryGetValue(name, out var n) ? n : (childNodes[name] = Instantiator.Create(_ParsedData[name]?.ToString() ?? ""))); /// /// Displays the JSON, representative of the GameState data /// /// JSON String - [GameStateIgnore] public override string ToString() - { - return json; - } + public override string ToString() => json; } - public class GameState : GameState - { - public GameState() : base() { } - public GameState(IGameState gs) : base(gs) { } - public GameState(string json) : base(json) { } - } /// - /// Class representing local computer information + /// An empty gamestate with no child nodes. /// - public class LocalPCInformation : Node { - #region Time Properties - /// - /// The current hour - /// - public int CurrentHour => Utils.Time.GetHours(); - - /// - /// The current minute - /// - public int CurrentMinute => Utils.Time.GetMinutes(); - - /// - /// The current second - /// - public int CurrentSecond => Utils.Time.GetSeconds(); - - /// - /// The current millisecond - /// - public int CurrentMillisecond => Utils.Time.GetMilliSeconds(); - - /// - /// The total number of milliseconds since the epoch - /// - public long MillisecondsSinceEpoch => Utils.Time.GetMillisecondsSinceEpoch(); - #endregion - - #region Audio Properties - private static readonly MMDeviceEnumerator mmDeviceEnumerator = new MMDeviceEnumerator(); - private static readonly NAudio.Wave.WaveInEvent waveInEvent = new NAudio.Wave.WaveInEvent(); - - /// - /// Gets the default endpoint for output (playback) devices e.g. speakers, headphones, etc. - /// This will return null if there are no playback devices available. - /// - private MMDevice DefaultAudioOutDevice { - get { - try { return mmDeviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Console); } - catch { return null; } - } - } - - /// - /// Gets the default endpoint for input (recording) devices e.g. microphones. - /// This will return null if there are no recording devices available. - /// - private MMDevice DefaultAudioInDevice { - get { - try { return mmDeviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Capture, Role.Console); } - catch { return null; } - } - } - - /// - /// Current system volume (as set from the speaker icon) - /// - // Note: Manually checks if muted to return 0 since this is not taken into account with the MasterVolumeLevelScalar. - public float SystemVolume => SystemVolumeIsMuted ? 0 : DefaultAudioOutDevice?.AudioEndpointVolume.MasterVolumeLevelScalar * 100 ?? 0; - - /// - /// Gets whether the system volume is muted. - /// - public bool SystemVolumeIsMuted => DefaultAudioOutDevice?.AudioEndpointVolume.Mute ?? true; - - /// - /// The volume level that is being recorded by the default microphone even when muted. - /// - public float MicrophoneLevel => DefaultAudioInDevice?.AudioMeterInformation.MasterPeakValue * 100 ?? 0; - - /// - /// The volume level that is being emitted by the default speaker even when muted. - /// - public float SpeakerLevel => DefaultAudioOutDevice?.AudioMeterInformation.MasterPeakValue * 100 ?? 0; - - /// - /// The volume level that is being recorded by the default microphone if not muted. - /// - public float MicLevelIfNotMuted => MicrophoneIsMuted ? 0 : DefaultAudioInDevice?.AudioMeterInformation.MasterPeakValue * 100 ?? 0; - - /// - /// Gets whether the default microphone is muted. - /// - public bool MicrophoneIsMuted => DefaultAudioInDevice?.AudioEndpointVolume.Mute ?? true; - #endregion - - #region Device Properties - /// - /// Battery level of a dualshock controller - /// - public int DS4Battery => Global.dev_manager.GetInitializedDevices().OfType().FirstOrDefault()?.Battery ?? 0; - /// - /// Whether or not thr dualshock controller is charging - /// - public bool DS4Charging => Global.dev_manager.GetInitializedDevices().OfType().FirstOrDefault()?.Charging ?? false; - #endregion - - #region CPU Properties - /// - /// Legacy cpu usage prop, DEPRECATED - /// - public float CPUUsage => CPU.Usage; - - private static CPUInfo _cpuInfo; - public CPUInfo CPU => _cpuInfo ?? (_cpuInfo = new CPUInfo()); - #endregion - - #region RAM Properties - /// - /// Used RAM, DEPRECATED - /// - public long MemoryUsed => RAM.Used; - - /// - /// Available RAM, DEPRECATED - /// - public long MemoryFree => RAM.Free; - - /// - /// Total RAM, DEPRECATED - /// - public long MemoryTotal => MemoryFree + MemoryUsed; - - private static RAMInfo _ramInfo; - public RAMInfo RAM => _ramInfo ?? (_ramInfo = new RAMInfo()); - #endregion - - #region GPU Properties - private static GPUInfo _gpuInfo; - public GPUInfo GPU => _gpuInfo ?? (_gpuInfo = new GPUInfo()); - #endregion - - #region NET Properties - private static NETInfo _netInfo; - public NETInfo NET => _netInfo ?? (_netInfo = new NETInfo()); - #endregion - - /// - /// Returns whether or not the device dession is in a locked state. - /// - public bool IsDesktopLocked => Utils.DesktopUtils.IsDesktopLocked; - - static LocalPCInformation() { - void StartStopRecording() { - // We must start recording to be able to capture audio in, but only do this if the user has the option set. Allowing them - // to turn it off will give them piece of mind we're not spying on them and will stop the Windows 10 mic icon appearing. - try { - if (Global.Configuration.EnableAudioCapture) - waveInEvent.StartRecording(); - else - waveInEvent.StopRecording(); - } catch { } - } - - StartStopRecording(); - Global.Configuration.PropertyChanged += (sender, e) => { - if (e.PropertyName == "EnableAudioCapture") - StartStopRecording(); - }; - } - } - - public class CPUInfo : Node - { - /// - /// Represents the CPU usage from 0 to 100 - /// - public float Usage => Utils.HardwareMonitor.CPU.CPUTotalLoad; - - /// - /// Represents the temperature of the cpu die in celsius - /// - public float Temperature => Utils.HardwareMonitor.CPU.CPUDieTemp; - - /// - /// Represents the CPU power draw in watts - /// - public float PowerUsage => Utils.HardwareMonitor.CPU.CPUPower; - } - - public class RAMInfo : Node - { - /// - /// Used system memory in megabytes - /// - public long Used => (long)(Utils.HardwareMonitor.RAM.RAMUsed * 1024f); - - /// - /// Free system memory in megabytes - /// - public long Free => (long)(Utils.HardwareMonitor.RAM.RAMFree * 1024f); - - /// - /// Total system memory in megabytes - /// - public long Total => Free + Used; - } - - public class GPUInfo : Node - { - public float Usage => Utils.HardwareMonitor.GPU.GPUCoreLoad; - public float Temperature => Utils.HardwareMonitor.GPU.GPUCoreTemp; - public float PowerUsage => Utils.HardwareMonitor.GPU.GPUPower; - public float FanRPM => Utils.HardwareMonitor.GPU.GPUFan; - public float CoreClock => Utils.HardwareMonitor.GPU.GPUCoreClock; - public float MemoryClock => Utils.HardwareMonitor.GPU.GPUMemoryClock; - public float ShaderClock => Utils.HardwareMonitor.GPU.GPUShaderClock; - public float MemoryControllerUsage => Utils.HardwareMonitor.GPU.GPUMemoryCLoad; - public float VideoEngineUsage => Utils.HardwareMonitor.GPU.GPUVideoEngineLoad; - public float MemoryUsed => Utils.HardwareMonitor.GPU.GPUMemoryUsed; - public float MemoryFree => MemoryTotal - MemoryUsed; - public float MemoryTotal => Utils.HardwareMonitor.GPU.GPUMemoryTotal; - } - - public class NETInfo : Node + public class EmptyGameState : GameState { - public float Usage => Utils.HardwareMonitor.NET.BandwidthUsed; - public float UploadSpeed => Utils.HardwareMonitor.NET.UploadSpeedBytes; - public float DownloadSpeed => Utils.HardwareMonitor.NET.DownloadSpeedBytes; + public EmptyGameState() : base() { } + public EmptyGameState(IGameState gs) : base(gs) { } + public EmptyGameState(string json) : base(json) { } } } diff --git a/Project-Aurora/Project-Aurora/Profiles/GameState_Wrapper.cs b/Project-Aurora/Project-Aurora/Profiles/GameState_Wrapper.cs index 53b099543..67d6b9357 100644 --- a/Project-Aurora/Project-Aurora/Profiles/GameState_Wrapper.cs +++ b/Project-Aurora/Project-Aurora/Profiles/GameState_Wrapper.cs @@ -7,7 +7,7 @@ namespace Aurora.Profiles /// /// A class representing various lighting information retaining to the wrapper. /// - public class GameState_Wrapper : GameState + public class GameState_Wrapper : GameState { private Provider_Wrapper _Provider; private string _Command; @@ -116,7 +116,7 @@ public Extra_Keys_Wrapper Extra_Keys public GameState_Wrapper() { json = "{}"; - _ParsedData = Newtonsoft.Json.Linq.JObject.Parse(json); + _ParsedData = JObject.Parse(json); } /// @@ -136,7 +136,7 @@ public GameState_Wrapper(string json_data) : base(json_data) /// A copy constructor, creates a GameState_Wrapper instance based on the data from the passed GameState instance. /// /// The passed GameState - public GameState_Wrapper(GameState other_state) : base(other_state) + public GameState_Wrapper(IGameState other_state) : base(other_state) { } } diff --git a/Project-Aurora/Project-Aurora/Profiles/LightEvent.cs b/Project-Aurora/Project-Aurora/Profiles/LightEvent.cs index 55c3ef33c..cf65f0d7c 100644 --- a/Project-Aurora/Project-Aurora/Profiles/LightEvent.cs +++ b/Project-Aurora/Project-Aurora/Profiles/LightEvent.cs @@ -108,7 +108,7 @@ public virtual bool IsEnabled public virtual void ResetGameState() { - _game_state = new GameState(); + _game_state = new EmptyGameState(); } public virtual void OnStart() diff --git a/Project-Aurora/Project-Aurora/Profiles/LocalPCInformation.cs b/Project-Aurora/Project-Aurora/Profiles/LocalPCInformation.cs new file mode 100644 index 000000000..4b7dac6dd --- /dev/null +++ b/Project-Aurora/Project-Aurora/Profiles/LocalPCInformation.cs @@ -0,0 +1,229 @@ +using Aurora.Utils; +using NAudio.CoreAudioApi; +using System.Linq; + +namespace Aurora.Profiles { + /// + /// Class representing local computer information + /// + public class LocalPCInformation : Node { + #region Time Properties + /// + /// The current hour + /// + public int CurrentHour => Time.GetHours(); + + /// + /// The current minute + /// + public int CurrentMinute => Time.GetMinutes(); + + /// + /// The current second + /// + public int CurrentSecond => Time.GetSeconds(); + + /// + /// The current millisecond + /// + public int CurrentMillisecond => Time.GetMilliSeconds(); + + /// + /// The total number of milliseconds since the epoch + /// + public long MillisecondsSinceEpoch => Time.GetMillisecondsSinceEpoch(); + #endregion + + #region Audio Properties + private static readonly MMDeviceEnumerator mmDeviceEnumerator = new MMDeviceEnumerator(); + private static readonly NAudio.Wave.WaveInEvent waveInEvent = new NAudio.Wave.WaveInEvent(); + + /// + /// Gets the default endpoint for output (playback) devices e.g. speakers, headphones, etc. + /// This will return null if there are no playback devices available. + /// + private MMDevice DefaultAudioOutDevice { + get { + try { return mmDeviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Console); } + catch { return null; } + } + } + + /// + /// Gets the default endpoint for input (recording) devices e.g. microphones. + /// This will return null if there are no recording devices available. + /// + private MMDevice DefaultAudioInDevice { + get { + try { return mmDeviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Capture, Role.Console); } + catch { return null; } + } + } + + /// + /// Current system volume (as set from the speaker icon) + /// + // Note: Manually checks if muted to return 0 since this is not taken into account with the MasterVolumeLevelScalar. + public float SystemVolume => SystemVolumeIsMuted ? 0 : DefaultAudioOutDevice?.AudioEndpointVolume.MasterVolumeLevelScalar * 100 ?? 0; + + /// + /// Gets whether the system volume is muted. + /// + public bool SystemVolumeIsMuted => DefaultAudioOutDevice?.AudioEndpointVolume.Mute ?? true; + + /// + /// The volume level that is being recorded by the default microphone even when muted. + /// + public float MicrophoneLevel => DefaultAudioInDevice?.AudioMeterInformation.MasterPeakValue * 100 ?? 0; + + /// + /// The volume level that is being emitted by the default speaker even when muted. + /// + public float SpeakerLevel => DefaultAudioOutDevice?.AudioMeterInformation.MasterPeakValue * 100 ?? 0; + + /// + /// The volume level that is being recorded by the default microphone if not muted. + /// + public float MicLevelIfNotMuted => MicrophoneIsMuted ? 0 : DefaultAudioInDevice?.AudioMeterInformation.MasterPeakValue * 100 ?? 0; + + /// + /// Gets whether the default microphone is muted. + /// + public bool MicrophoneIsMuted => DefaultAudioInDevice?.AudioEndpointVolume.Mute ?? true; + #endregion + + #region Device Properties + /// + /// Battery level of a dualshock controller + /// + public int DS4Battery => Global.dev_manager.GetInitializedDevices().OfType().FirstOrDefault()?.Battery ?? 0; + /// + /// Whether or not thr dualshock controller is charging + /// + public bool DS4Charging => Global.dev_manager.GetInitializedDevices().OfType().FirstOrDefault()?.Charging ?? false; + #endregion + + #region CPU Properties + /// + /// Legacy cpu usage prop, DEPRECATED + /// + public float CPUUsage => CPU.Usage; + + private static CPUInfo _cpuInfo; + public CPUInfo CPU => _cpuInfo ?? (_cpuInfo = new CPUInfo()); + #endregion + + #region RAM Properties + /// + /// Used RAM, DEPRECATED + /// + public long MemoryUsed => RAM.Used; + + /// + /// Available RAM, DEPRECATED + /// + public long MemoryFree => RAM.Free; + + /// + /// Total RAM, DEPRECATED + /// + public long MemoryTotal => MemoryFree + MemoryUsed; + + private static RAMInfo _ramInfo; + public RAMInfo RAM => _ramInfo ?? (_ramInfo = new RAMInfo()); + #endregion + + #region GPU Properties + private static GPUInfo _gpuInfo; + public GPUInfo GPU => _gpuInfo ?? (_gpuInfo = new GPUInfo()); + #endregion + + #region NET Properties + private static NETInfo _netInfo; + public NETInfo NET => _netInfo ?? (_netInfo = new NETInfo()); + #endregion + + /// + /// Returns whether or not the device dession is in a locked state. + /// + public bool IsDesktopLocked => DesktopUtils.IsDesktopLocked; + + static LocalPCInformation() { + void StartStopRecording() { + // We must start recording to be able to capture audio in, but only do this if the user has the option set. Allowing them + // to turn it off will give them piece of mind we're not spying on them and will stop the Windows 10 mic icon appearing. + try { + if (Global.Configuration.EnableAudioCapture) + waveInEvent.StartRecording(); + else + waveInEvent.StopRecording(); + } catch { } + } + + StartStopRecording(); + Global.Configuration.PropertyChanged += (sender, e) => { + if (e.PropertyName == "EnableAudioCapture") + StartStopRecording(); + }; + } + } + + public class CPUInfo : Node + { + /// + /// Represents the CPU usage from 0 to 100 + /// + public float Usage => HardwareMonitor.CPU.CPUTotalLoad; + + /// + /// Represents the temperature of the cpu die in celsius + /// + public float Temperature => HardwareMonitor.CPU.CPUDieTemp; + + /// + /// Represents the CPU power draw in watts + /// + public float PowerUsage => HardwareMonitor.CPU.CPUPower; + } + + public class RAMInfo : Node + { + /// + /// Used system memory in megabytes + /// + public long Used => (long)(HardwareMonitor.RAM.RAMUsed * 1024f); + + /// + /// Free system memory in megabytes + /// + public long Free => (long)(HardwareMonitor.RAM.RAMFree * 1024f); + + /// + /// Total system memory in megabytes + /// + public long Total => Free + Used; + } + + public class GPUInfo : Node + { + public float Usage => HardwareMonitor.GPU.GPUCoreLoad; + public float Temperature => HardwareMonitor.GPU.GPUCoreTemp; + public float PowerUsage => HardwareMonitor.GPU.GPUPower; + public float FanRPM => HardwareMonitor.GPU.GPUFan; + public float CoreClock => HardwareMonitor.GPU.GPUCoreClock; + public float MemoryClock => HardwareMonitor.GPU.GPUMemoryClock; + public float ShaderClock => HardwareMonitor.GPU.GPUShaderClock; + public float MemoryControllerUsage => HardwareMonitor.GPU.GPUMemoryCLoad; + public float VideoEngineUsage => HardwareMonitor.GPU.GPUVideoEngineLoad; + public float MemoryUsed => HardwareMonitor.GPU.GPUMemoryUsed; + public float MemoryFree => MemoryTotal - MemoryUsed; + public float MemoryTotal => HardwareMonitor.GPU.GPUMemoryTotal; + } + + public class NETInfo : Node + { + public float Usage => HardwareMonitor.NET.BandwidthUsed; + public float UploadSpeed => HardwareMonitor.NET.UploadSpeedBytes; + public float DownloadSpeed => HardwareMonitor.NET.DownloadSpeedBytes; + } +} diff --git a/Project-Aurora/Project-Aurora/Profiles/Node.cs b/Project-Aurora/Project-Aurora/Profiles/Node.cs index 97d1698e6..18ffd335b 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Node.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Node.cs @@ -1,87 +1,49 @@ using Aurora.Utils; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.ComponentModel; -using System.Linq.Expressions; -using System.Reflection; namespace Aurora.Profiles { - public class Node : StringProperty where TClass : Node + public class Node { - protected Newtonsoft.Json.Linq.JObject _ParsedData; + protected JObject _ParsedData; // Holds a cache of the child nodes on this node private readonly Dictionary childNodes = new Dictionary(StringComparer.OrdinalIgnoreCase); - public Node() : base() - { - _ParsedData = new Newtonsoft.Json.Linq.JObject(); + public Node() { + _ParsedData = new JObject(); } - public Node(string json_data) : this() - { - if (String.IsNullOrWhiteSpace(json_data)) + public Node(string json_data) { + if (string.IsNullOrWhiteSpace(json_data)) json_data = "{}"; - try - { - _ParsedData = Newtonsoft.Json.Linq.JObject.Parse(json_data); - } - catch(Exception exc) - { + try { + _ParsedData = JObject.Parse(json_data); + } catch (Exception exc) { Global.logger.Error($"Exception during Node parsing. Exception: {exc}"); - - _ParsedData = Newtonsoft.Json.Linq.JObject.Parse("{}"); + _ParsedData = JObject.Parse("{}"); } } - public string GetString(string Name) - { - Newtonsoft.Json.Linq.JToken value; - - if (_ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out value)) - return value.ToString(); - else - return ""; - } - - public int GetInt(string Name) - { - Newtonsoft.Json.Linq.JToken value; + public string GetString(string Name) => + _ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out var value) ? value.ToString() : ""; - if (_ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out value)) - return Convert.ToInt32(value.ToString()); - else - return -1; - } + public int GetInt(string Name) => + _ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out var value) ? Convert.ToInt32(value.ToString()) : -1; - public float GetFloat(string Name) - { - Newtonsoft.Json.Linq.JToken value; + public float GetFloat(string Name) => + _ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out var value) ? Convert.ToSingle(value.ToString()) : -1.0f; - if (_ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out value)) - return Convert.ToSingle(value.ToString()); - else - return -1.0f; - } - - public long GetLong(string Name) - { - Newtonsoft.Json.Linq.JToken value; - - if (_ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out value)) - return Convert.ToInt64(value.ToString()); - else - return -1; - } + public long GetLong(string Name) => + _ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out var value) ? Convert.ToInt64(value.ToString()) : -1l; public T GetEnum(string Name) where T : struct { - Newtonsoft.Json.Linq.JToken value; - - if (_ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out value) && !String.IsNullOrWhiteSpace(value.ToString())) - { + if (_ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out var value) && !string.IsNullOrWhiteSpace(value.ToString())) { var type = typeof(T); if (!type.IsEnum) throw new InvalidOperationException(); @@ -93,32 +55,20 @@ public T GetEnum(string Name) where T : struct foreach (var field in type.GetFields()) if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attribute && attribute.Description.ToLowerInvariant().Equals(value.ToString().ToLowerInvariant())) - return (T)field.GetValue(null); + return (T)field.GetValue(null); } // If there is an "undefined" enum value, return that else just do the default(T). return Enum.TryParse("Undefined", true, out var u) ? u : default(T); } - public bool GetBool(string Name) - { - Newtonsoft.Json.Linq.JToken value; + public bool GetBool(string Name) => + _ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out var value) && value.ToObject() + ? value.ToObject() + : false; - if (_ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out value) && value.ToObject()) - return value.ToObject(); - else - return false; - } - - public T[] GetArray(string Name) - { - Newtonsoft.Json.Linq.JToken value; - - if (_ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out value)) - return value.ToObject(); - else - return new T[] { }; - } + public T[] GetArray(string Name) => + _ParsedData.TryGetValue(Name, StringComparison.OrdinalIgnoreCase, out var value) ? value.ToObject() : (new T[] { }); /// /// Method for accessing and caching a child node. diff --git a/Project-Aurora/Project-Aurora/Profiles/StringProperty.cs b/Project-Aurora/Project-Aurora/Profiles/StringProperty.cs deleted file mode 100644 index 767c4af17..000000000 --- a/Project-Aurora/Project-Aurora/Profiles/StringProperty.cs +++ /dev/null @@ -1,129 +0,0 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace Aurora.Profiles -{ - public interface IStringProperty - { - object GetValueFromString(string name, object input = null); - void SetValueFromString(string name, object value); - IStringProperty Clone(); - } - - public class StringProperty : IStringProperty - { - public static Dictionary, Action, Type>> PropertyLookup { get; set; } = null; - public static object DictLock = new object(); - - public StringProperty() - { - lock (DictLock) - { - if (PropertyLookup != null) - return; - - PropertyLookup = new Dictionary, Action, Type>>(); - - Type typ = typeof(T); - foreach (MemberInfo prop in typ.GetMembers()) - { - ParameterExpression paramExpression = Expression.Parameter(typ); - Func getp; - switch (prop.MemberType) - { - case MemberTypes.Property: - case MemberTypes.Field: - Type t = Expression.GetFuncType(typ, typeof(object)); - - LambdaExpression exp = Expression.Lambda( - t, - Expression.Convert( - Expression.PropertyOrField(paramExpression, prop.Name), - typeof(object) - ), - paramExpression - ); - - getp = (Func)exp.Compile(); - break; - /*case MemberTypes.Property: - getp = (Func)Delegate.CreateDelegate( - typeof(Func), - ((PropertyInfo)prop).GetMethod - ); - - break;*/ - default: - continue; - } - - - - Action setp = null; - if (!(prop.MemberType == MemberTypes.Property && ((PropertyInfo)prop).SetMethod == null)) - { - ParameterExpression paramExpression2 = Expression.Parameter(typeof(object)); - MemberExpression propertyGetterExpression = Expression.PropertyOrField(paramExpression, prop.Name); - - Type var_type; - if (prop is PropertyInfo) - var_type = ((PropertyInfo)prop).PropertyType; - else - var_type = ((FieldInfo)prop).FieldType; - - setp = Expression.Lambda> - ( - Expression.Assign(propertyGetterExpression, Expression.ConvertChecked(paramExpression2, var_type)), paramExpression, paramExpression2 - ).Compile(); - } - if (!PropertyLookup.ContainsKey(prop.Name)) - { - PropertyLookup.Add(prop.Name, new Tuple, Action, Type>(getp, setp, typ)); - } - - } - } - } - - public object GetValueFromString(string name, object input = null) - { - if (PropertyLookup.ContainsKey(name)) - { - return PropertyLookup[name].Item1((T)(object)this); - } - - /*Type t = obj.GetType(); - MemberInfo member; - if ((member = input == null ? t.GetMember(name).FirstOrDefault() : t.GetMethod(name, new[] { input.GetType() })) != null) - { - if (member is FieldInfo) - return ((FieldInfo)member).GetValue(obj); - else if (member is PropertyInfo) - return ((PropertyInfo)member).GetValue(obj); - else if (member is MethodInfo) - return ((MethodInfo)member).Invoke(obj, new[] { input }); - }*/ - - return null; - } - - public void SetValueFromString(string name, object value) - { - if (PropertyLookup.ContainsKey(name)) - { - PropertyLookup[name]?.Item2((T)(object)this, value); - } - } - - public IStringProperty Clone() - { - return (IStringProperty)this.MemberwiseClone(); - } - } -} diff --git a/Project-Aurora/Project-Aurora/Project-Aurora.csproj b/Project-Aurora/Project-Aurora/Project-Aurora.csproj index 155b685c3..23eeed84d 100644 --- a/Project-Aurora/Project-Aurora/Project-Aurora.csproj +++ b/Project-Aurora/Project-Aurora/Project-Aurora.csproj @@ -221,6 +221,7 @@ Control_LoLBackgroundLayer.xaml + @@ -932,7 +933,6 @@ - Control_WormsWMD.xaml @@ -2594,6 +2594,9 @@ 1.13.7 + + 1.5.0 + 6.1.1 runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Project-Aurora/Project-Aurora/Settings/Layers/Layer.cs b/Project-Aurora/Project-Aurora/Settings/Layers/Layer.cs index 59e1c08ae..85d25db62 100644 --- a/Project-Aurora/Project-Aurora/Settings/Layers/Layer.cs +++ b/Project-Aurora/Project-Aurora/Settings/Layers/Layer.cs @@ -2,6 +2,7 @@ using Aurora.Profiles; using Aurora.Settings.Overrides.Logic; using Aurora.Settings.Overrides.Logic.Builder; +using FastMember; using Newtonsoft.Json; using System; using System.Collections.Generic; @@ -235,11 +236,12 @@ public Layer(string name, ILayerHandler handler, OverrideLogicBuilder builder) : public EffectLayer Render(IGameState gs) { - if (_OverrideLogic != null) - // For every property which has an override logic assigned + if (_OverrideLogic != null) { + // For every property which has an override logic assigned foreach (var kvp in _OverrideLogic) // Set the value of the logic evaluation as the override for this property - ((IValueOverridable)_Handler.Properties).Overrides.SetValueFromString(kvp.Key, kvp.Value.Evaluate(gs)); + ((IValueOverridable)_Handler.Properties).SetOverride(kvp.Key, kvp.Value.Evaluate(gs)); + } return ((dynamic)_Handler.Properties).Enabled ? _Handler.PostRenderFX(_Handler.Render(gs)) : new EffectLayer(); } diff --git a/Project-Aurora/Project-Aurora/Settings/Layers/LayerHandler.cs b/Project-Aurora/Project-Aurora/Settings/Layers/LayerHandler.cs index 472c2ad85..a29e74278 100755 --- a/Project-Aurora/Project-Aurora/Settings/Layers/LayerHandler.cs +++ b/Project-Aurora/Project-Aurora/Settings/Layers/LayerHandler.cs @@ -10,23 +10,16 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Controls; +using FastMember; namespace Aurora.Settings.Layers { - public interface IValueOverridable + public abstract class LayerHandlerProperties : IValueOverridable where TProperty : LayerHandlerProperties { - IStringProperty Overrides { get; set; } - } + private static readonly Lazy accessor = new Lazy(() => TypeAccessor.Create(typeof(TProperty))); - public abstract class LayerHandlerProperties : StringProperty, IValueOverridable where TProperty : LayerHandlerProperties - { - [GameStateIgnoreAttribute] - [JsonIgnore] + [GameStateIgnore, JsonIgnore] public TProperty Logic { get; set; } - IStringProperty IValueOverridable.Overrides { - get => (IStringProperty)Logic; - set => Logic = value as TProperty; - } [LogicOverridable("Primary Color")] public virtual Color? _PrimaryColor { get; set; } @@ -79,6 +72,20 @@ public virtual void Default() _PrimaryColor = Utils.ColorUtils.GenerateRandomColor(); _Sequence = new KeySequence(); } + + public object GetOverride(string propertyName) { + try { + return accessor.Value[Logic, propertyName]; + } catch { + return null; + } + } + + public void SetOverride(string propertyName, object value) { + try { + accessor.Value[Logic, propertyName] = value; + } catch { } + } } public class LayerHandlerProperties2Color : LayerHandlerProperties where TProperty : LayerHandlerProperties2Color @@ -108,7 +115,7 @@ public interface ILayerHandler : IDisposable { UserControl Control { get; } - IStringProperty Properties { get; set; } + object Properties { get; set; } bool EnableSmoothing { get; set; } @@ -143,7 +150,7 @@ public abstract class LayerHandler : ILayerHandler where TProperty : public TProperty Properties { get; set; } = Activator.CreateInstance(); - IStringProperty ILayerHandler.Properties { + object ILayerHandler.Properties { get => Properties; set => Properties = value as TProperty; } @@ -247,4 +254,17 @@ public class LayerHandler : LayerHandler { } + + + public interface IValueOverridable { + /// + /// Gets the overriden value of the speicifed property. + /// + object GetOverride(string propertyName); + + /// + /// Sets the overriden value of the speicifed property to the given value. + /// + void SetOverride(string propertyName, object value); + } } diff --git a/Project-Aurora/Project-Aurora/Settings/Overrides/Control_OverridesEditor.xaml.cs b/Project-Aurora/Project-Aurora/Settings/Overrides/Control_OverridesEditor.xaml.cs index f7e49f558..a0a96f0c0 100644 --- a/Project-Aurora/Project-Aurora/Settings/Overrides/Control_OverridesEditor.xaml.cs +++ b/Project-Aurora/Project-Aurora/Settings/Overrides/Control_OverridesEditor.xaml.cs @@ -1,6 +1,7 @@ using Aurora.Settings.Layers; using Aurora.Settings.Overrides.Logic; using Aurora.Utils; +using FastMember; using PropertyChanged; using System; using System.Collections.Generic; @@ -102,7 +103,8 @@ public Type SelectedLogicType { if (_selectedProperty != null && SelectedLogic?.GetType() != value) { if (value == null) { // If the value is null, that means the user selected the "None" option, so remove the override for this property. Also force reset the override to null so that it doesn't persist after removing the logic. Layer.OverrideLogic.Remove(_selectedProperty.Item1); - ((IValueOverridable)Layer.Handler.Properties).Overrides.SetValueFromString(_selectedProperty.Item1, null); + ((IValueOverridable)Layer.Handler.Properties).SetOverride(_selectedProperty.Item1, null); + } else // Else if the user selected a non-"None" option, create a new instance of that OverrideLogic and assign it to this property Layer.OverrideLogic[_selectedProperty.Item1] = (IOverrideLogic)Activator.CreateInstance(value, _selectedProperty.Item3); OnPropertyChanged(nameof(SelectedLogic), nameof(SelectedLogicType), nameof(SelectedLogicControl)); // Raise an event to update the control diff --git a/Project-Aurora/Project-Aurora/Utils/GameStateUtils.cs b/Project-Aurora/Project-Aurora/Utils/GameStateUtils.cs index 40eb6688a..1c5b990c7 100644 --- a/Project-Aurora/Project-Aurora/Utils/GameStateUtils.cs +++ b/Project-Aurora/Project-Aurora/Utils/GameStateUtils.cs @@ -122,7 +122,7 @@ private static object _RetrieveGameStateParameter(IGameState state, string param string[] parameters = parameter_path.Split('/'); object val = null; - IStringProperty property_object = state as IStringProperty; + object property_object = state; int index_pos = 0; for (int x = 0; x < parameters.Count(); x++) @@ -134,7 +134,7 @@ private static object _RetrieveGameStateParameter(IGameState state, string param //Following needs validation //If next param is placeholder then take the appropriate input value from the input_values array - val = property_object.GetValueFromString(param); + val = null;// property_object.GetValueFromString(param); if (val == null) throw new ArgumentNullException($"Failed to get value {parameter_path}, failed at '{param}'"); @@ -156,7 +156,7 @@ private static object _RetrieveGameStateParameter(IGameState state, string param val = Activator.CreateInstance(child_type); } - property_object = val as IStringProperty; + property_object = val; } return val; From d399026511e3ec078d1a1e0c50538ffdbf9faa8f Mon Sep 17 00:00:00 2001 From: Will Bennion Date: Wed, 13 May 2020 10:29:15 +0100 Subject: [PATCH 2/9] Made Layer implement INotifyPropertyChanged instead of using a custom 'AnythingChanged' event. --- .../Project-Aurora/Profiles/Application.cs | 4 +- .../Settings/Control_LayerList.xaml.cs | 2 +- .../Project-Aurora/Settings/Layers/Layer.cs | 268 +++--------------- 3 files changed, 42 insertions(+), 232 deletions(-) diff --git a/Project-Aurora/Project-Aurora/Profiles/Application.cs b/Project-Aurora/Project-Aurora/Profiles/Application.cs index 811ed8c75..571e7bb47 100755 --- a/Project-Aurora/Project-Aurora/Profiles/Application.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Application.cs @@ -307,14 +307,14 @@ void InitialiseLayerCollection(ObservableCollection collection) { continue; } - lyr.AnythingChanged += SaveProfilesEvent; + lyr.PropertyChanged += SaveProfilesEvent; } collection.CollectionChanged += (_, e) => { if (e.NewItems != null) foreach (Layer lyr in e.NewItems) if (lyr != null) - lyr.AnythingChanged += SaveProfilesEvent; + lyr.PropertyChanged += SaveProfilesEvent; SaveProfiles(); }; } diff --git a/Project-Aurora/Project-Aurora/Settings/Control_LayerList.xaml.cs b/Project-Aurora/Project-Aurora/Settings/Control_LayerList.xaml.cs index 4cade1478..f3e323138 100644 --- a/Project-Aurora/Project-Aurora/Settings/Control_LayerList.xaml.cs +++ b/Project-Aurora/Project-Aurora/Settings/Control_LayerList.xaml.cs @@ -145,7 +145,7 @@ public string ListTitle { /// Adds a new layer to the currently active collection. Will also setup the event listener to make the profile save and set the layer's application. /// private void AddLayer(Layer layer) { - layer.AnythingChanged += FocusedApplication.SaveProfilesEvent; + layer.PropertyChanged += FocusedApplication.SaveProfilesEvent; layer.SetProfile(FocusedApplication); ActiveLayerCollection.Insert(0, layer); SelectedLayer = layer; diff --git a/Project-Aurora/Project-Aurora/Settings/Layers/Layer.cs b/Project-Aurora/Project-Aurora/Settings/Layers/Layer.cs index 85d25db62..bf1be2301 100644 --- a/Project-Aurora/Project-Aurora/Settings/Layers/Layer.cs +++ b/Project-Aurora/Project-Aurora/Settings/Layers/Layer.cs @@ -2,277 +2,87 @@ using Aurora.Profiles; using Aurora.Settings.Overrides.Logic; using Aurora.Settings.Overrides.Logic.Builder; -using FastMember; using Newtonsoft.Json; +using PropertyChanged; using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.ComponentModel; using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Controls; namespace Aurora.Settings.Layers { - /// - /// All available layer types. Note: There is a large overhead for generap purpose layers, so there is ample room for adding new layers that apply to all profiles. - /// Each game reserves 50 unique layer types. - /// - /*public enum LayerType - { - [Description("Default Layer")] - Default = 0, - - [Description("Animation Layer")] - Animation = 10, - - [Description("Solid Color Layer")] - Solid = 100, - - [Description("Solid Fill Color Layer")] - SolidFilled = 110, - - [Description("Gradient Layer")] - Gradient = 115, - - [Description("Gradient Fill Layer")] - GradientFill = 116, - - [Description("Breathing Layer")] - Breathing = 120, - - [Description("Blinking Layer")] - Blinking = 121, - - [Description("Image Layer")] - Image = 122, - - [Description("Script Layer")] - Script = 123, - - [Description("Percent Effect Layer")] - Percent = 200, - - [Description("Percent (Gradient) Effect Layer")] - PercentGradient = 201, - - [Description("Interactive Layer")] - Interactive = 300, - - [Description("Shortcut Assistant Layer")] - ShortcutAssistant = 400, - - [Description("Equalizer Layer")] - Equalizer = 500, - - [Description("Ambilight Layer")] - Ambilight = 600, - - [Description("Lock Color Layer")] - LockColor = 700, - - [Description("Dota 2 Background Layer")] - Dota2Background = 800, - - [Description("Dota 2 Respawn Layer")] - Dota2Respawn = 801, - - [Description("Dota 2 Abilies Layer")] - Dota2Abilities = 802, - - [Description("Dota 2 Items Layer")] - Dota2Items = 803, - - [Description("Dota 2 Hero Abiliy Effects Layer")] - Dota2HeroAbilityEffects = 804, - - [Description("Dota 2 Killstreak Layer")] - Dota2Killstreak = 805, - - [Description("CSGO Background Layer")] - CSGOBackground = 850, - - [Description("CSGO Bomb Layer")] - CSGOBomb = 851, - - [Description("CSGO Kills Indicator Layer")] - CSGOKillsIndicator = 852, - - [Description("CSGO Burning Effect Layer")] - CSGOBurning = 853, - - [Description("CSGO Flashbang Effect Layer")] - CSGOFlashbang = 854, - - [Description("CSGO Typing Layer")] - CSGOTyping = 855, - - [Description("GTA 5 Background Layer")] - GTA5Background = 900, - - [Description("GTA 5 Police Siren Layer")] - GTA5PoliceSiren = 901, - - [Description("Rocket League Background Layer")] - RocketLeagueBackground = 950, - - [Description("Payday 2 Background Layer")] - PD2Background = 1000, - - [Description("Payday 2 Flashbang Layer")] - PD2Flashbang = 1001, - - [Description("Payday 2 States Layer")] - PD2States = 1002, - - }*/ /// /// A class representing a default settings layer /// - public class Layer : ICloneable, IDisposable + public class Layer : INotifyPropertyChanged, ICloneable, IDisposable { - private Application _application; + [DoNotNotify, JsonIgnore] + public Application AssociatedApplication { get; private set; } - [JsonIgnore] - public Application AssociatedApplication { get { return _application; } } + public string Name { get; set; } = "New Layer"; - public event EventHandler AnythingChanged; - - protected string _Name = "New Layer"; - - public string Name - { - get { return _Name; } - set - { - _Name = value; - AnythingChanged?.Invoke(this, null); - } - } - - private ILayerHandler _Handler = new DefaultLayerHandler(); - - public ILayerHandler Handler - { - get { return _Handler; } - set - { - _Handler = value; - - if(_application != null) - _Handler.SetApplication(_application); - } - } + [OnChangedMethod(nameof(OnHandlerChanged))] + public ILayerHandler Handler { get; set; } = new DefaultLayerHandler(); [JsonIgnore] - public UserControl Control - { - get - { - return _Handler.Control; - } - } - - protected bool _Enabled = true; + public UserControl Control => Handler.Control; - public bool Enabled - { - get { return _Enabled; } - set - { - _Enabled = value; - AnythingChanged?.Invoke(this, null); - } - } - - /*protected string _Type; - - public string Type - { - get { return _Type; } - set - { - _Type = value; - AnythingChanged?.Invoke(this, null); - } - }*/ + public bool Enabled{ get; set; } - protected Dictionary _OverrideLogic; + public Dictionary OverrideLogic { get; set; } + // private void OnOverrideLogicChanged() => // Make the logic collection changed event trigger a property change to ensure it gets saved? - public Dictionary OverrideLogic - { - get { return _OverrideLogic; } - set - { - _OverrideLogic = value; - AnythingChanged?.Invoke(this, null); - //if (value != null) - // _OverrideLogic.CollectionChanged += (sender, e) => AnythingChanged?.Invoke(this, null); - } - } - - /// - /// - /// - public Layer() - { - } + #region Constructors + public Layer() { } - public Layer(string name, ILayerHandler handler = null) : this() - { + public Layer(string name, ILayerHandler handler = null) : this() { Name = name; - if (handler != null) - _Handler = handler; + Handler = handler ?? Handler; } public Layer(string name, ILayerHandler handler, Dictionary overrideLogic) : this(name, handler) { - _OverrideLogic = overrideLogic; + OverrideLogic = overrideLogic; } public Layer(string name, ILayerHandler handler, OverrideLogicBuilder builder) : this(name, handler, builder.Create()) { } + #endregion - public EffectLayer Render(IGameState gs) - { - if (_OverrideLogic != null) { + public event PropertyChangedEventHandler PropertyChanged; + + private void OnHandlerChanged() { + if (AssociatedApplication != null) + Handler.SetApplication(AssociatedApplication); + } + + public EffectLayer Render(IGameState gs) { + if (OverrideLogic != null) { // For every property which has an override logic assigned - foreach (var kvp in _OverrideLogic) + foreach (var kvp in OverrideLogic) // Set the value of the logic evaluation as the override for this property - ((IValueOverridable)_Handler.Properties).SetOverride(kvp.Key, kvp.Value.Evaluate(gs)); + ((IValueOverridable)Handler.Properties).SetOverride(kvp.Key, kvp.Value.Evaluate(gs)); } - return ((dynamic)_Handler.Properties).Enabled ? _Handler.PostRenderFX(_Handler.Render(gs)) : new EffectLayer(); + return ((dynamic)Handler.Properties).Enabled ? Handler.PostRenderFX(Handler.Render(gs)) : new EffectLayer(); } - public void SetProfile(Application profile) - { - _application = profile; - - _Handler?.SetApplication(_application); + public void SetProfile(Application profile) { + AssociatedApplication = profile; + Handler?.SetApplication(AssociatedApplication); } - public object Clone() - { + public object Clone() { string str = JsonConvert.SerializeObject(this, Formatting.None, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, Binder = Aurora.Utils.JSONUtils.SerializationBinder }); - return JsonConvert.DeserializeObject( - str, - this.GetType(), - new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace, TypeNameHandling = TypeNameHandling.All, Binder = Aurora.Utils.JSONUtils.SerializationBinder } - ); - } - - public void SetGameState(IGameState new_game_state) - { - Handler.SetGameState(new_game_state); + str, + this.GetType(), + new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace, TypeNameHandling = TypeNameHandling.All, Binder = Aurora.Utils.JSONUtils.SerializationBinder } + ); } - public void Dispose() - { - this.Handler.Dispose(); - } + public void SetGameState(IGameState new_game_state) => Handler.SetGameState(new_game_state); + public void Dispose() => Handler.Dispose(); } /// From 040e3d6c7faf583b8f562be895aafc8aa684e55e Mon Sep 17 00:00:00 2001 From: Will Bennion Date: Wed, 13 May 2020 15:34:27 +0100 Subject: [PATCH 3/9] Rewrote the game state reflection into a separate, dedicated class. Removed the IGameState constructor from game states. --- .../Controls/GameStateParameterPicker.xaml | 2 +- .../Controls/GameStateParameterPicker.xaml.cs | 56 +--- .../Project-Aurora/Profiles/Application.cs | 4 +- .../GSI/GameState_Borderlands2.cs | 8 - .../Profiles/CSGO/GSI/GameState_CSGO.cs | 30 +-- .../Profiles/CSGO/GSI/Nodes/AllPlayersNode.cs | 2 - .../CloneHero/GSI/GameState_CloneHero.cs | 8 - .../Profiles/Discord/GSI/GameState_Discord.cs | 21 +- .../Dishonored/GSI/GameState_Dishonored.cs | 24 +- .../Profiles/Dota 2/GSI/GameState_Dota2.cs | 24 +- .../Profiles/Dota 2/GSI/Nodes/Items.cs | 4 - .../Profiles/ETS2/GSI/GameState_ETS2.cs | 6 - .../Profiles/GTA5/GSI/GameState_GTA5.cs | 23 +- .../Project-Aurora/Profiles/GameState.cs | 174 +++++++----- .../Profiles/GameStateParameterLookup.cs | 118 ++++++++ .../Profiles/GameState_Wrapper.cs | 23 +- .../LeagueOfLegends/GSI/GameState_LoL.cs | 5 - .../Profiles/LightingStateManager.cs | 2 +- .../Minecraft/GSI/GameState_Minecraft.cs | 5 - .../Profiles/Osu/GSI/GameState_Osu.cs | 1 - .../Profiles/Payday 2/GSI/GameState_PD2.cs | 29 +- .../GSI/GameState_ResidentEvil2.cs | 8 - .../GSI/GameState_RocketLeague.cs | 6 - .../GSI/GameState_Slime_Rancher.cs | 6 - .../Subnautica/GSI/GameState_Subnautica.cs | 5 - .../Terraria/GSI/GameState_Terraria.cs | 11 +- .../Witcher3/GSI/GameState_Witcher3.cs | 8 - .../Project-Aurora/Project-Aurora.csproj | 3 +- .../Settings/Layers/AnimationLayerHandler.cs | 6 +- .../Layers/BinaryCounterLayerHandler.cs | 2 +- .../Settings/Layers/ComparisonLayerHandler.cs | 8 +- .../Layers/ConditionalLayerHandler.cs | 9 +- .../Layers/Control_AnimationLayer.xaml.cs | 4 +- .../Layers/Control_BinaryCounterLayer.xaml | 2 +- .../Layers/Control_BinaryCounterLayer.xaml.cs | 2 +- .../Layers/Control_ComparisonLayer.xaml.cs | 12 - .../Layers/Control_ConditionalLayer.xaml.cs | 9 - .../Settings/Layers/LayerHandler.cs | 4 +- .../Layers/PercentGradientLayerHandler.cs | 8 +- .../Settings/Layers/PercentLayerHandler.cs | 9 +- .../Logic/Boolean/Boolean_GameState.cs | 16 +- .../Boolean/Control_BooleanGSIEnum.xaml.cs | 4 +- .../Logic/Number/Number_GameState.cs | 4 +- .../Logic/String/String_GameState.cs | 9 +- .../Settings/Window_GSIHttpDebug.xaml.cs | 4 +- .../Project-Aurora/Utils/CollectionUtils.cs | 26 +- .../Utils/FastMemberExtensions.cs | 33 +++ .../Project-Aurora/Utils/GameStateUtils.cs | 253 ------------------ 48 files changed, 356 insertions(+), 684 deletions(-) create mode 100644 Project-Aurora/Project-Aurora/Profiles/GameStateParameterLookup.cs create mode 100644 Project-Aurora/Project-Aurora/Utils/FastMemberExtensions.cs delete mode 100644 Project-Aurora/Project-Aurora/Utils/GameStateUtils.cs diff --git a/Project-Aurora/Project-Aurora/Controls/GameStateParameterPicker.xaml b/Project-Aurora/Project-Aurora/Controls/GameStateParameterPicker.xaml index 7a260238d..8b5caff94 100644 --- a/Project-Aurora/Project-Aurora/Controls/GameStateParameterPicker.xaml +++ b/Project-Aurora/Project-Aurora/Controls/GameStateParameterPicker.xaml @@ -12,7 +12,7 @@ - + diff --git a/Project-Aurora/Project-Aurora/Controls/GameStateParameterPicker.xaml.cs b/Project-Aurora/Project-Aurora/Controls/GameStateParameterPicker.xaml.cs index e0e6e1da3..0411a4e46 100644 --- a/Project-Aurora/Project-Aurora/Controls/GameStateParameterPicker.xaml.cs +++ b/Project-Aurora/Project-Aurora/Controls/GameStateParameterPicker.xaml.cs @@ -21,8 +21,6 @@ public partial class GameStateParameterPicker : UserControl, INotifyPropertyChan public event EventHandler SelectedPathChanged; public event PropertyChangedEventHandler PropertyChanged; - private List parameterList; - public GameStateParameterPicker() { InitializeComponent(); } @@ -33,15 +31,10 @@ public GameStateParameterPicker() { /// private Stack WorkingPath { get; set; } = new Stack(); - /// - /// Lazy-evaluated list of parameters for this application and property type. - /// - public List ParameterList => parameterList ?? (parameterList = Application?.ParameterLookup?.GetParameters(PropertyType).ToList()); - /// /// Gets a list of items that should be displayed in the parameter list (based on the current "parent" variable). /// - public IEnumerable CurrentParameterListItems { + public IEnumerable CurrentParameterListItems { get { // If the application or param lookup is null, we don't know the parameters so do nothing if (Application?.ParameterLookup == null) return null; @@ -50,16 +43,7 @@ public IEnumerable CurrentParameterListItems { if (Application.ParameterLookup.IsValidParameter(WorkingPathStr)) WorkingPath.Pop(); - // Generate the string version of this working path (and cache it) - var _workingPath = WorkingPathStr; - if (_workingPath != "") _workingPath += "/"; // If not at the root directory, add / to the end of the test path. This means it doesn't get confused with things such as `CPU` and `CPUUsage`. - return from path in ParameterList // With all properties in the current param lookup that are of a valid type (e.g. numbers) - where path.StartsWith(_workingPath) // Pick only the ones that start with the same working path - let pathSplit = path.Substring(_workingPath.Length).Split('/') // Get a list of all remaining parts of the path (e.g. if this was A/B/C and current path was A, pathSplit would be 'B', 'C') - let isFolder = pathSplit.Length > 1 // If there is more than one part of the path remaining, this must be a directory - group isFolder by pathSplit[0] into g // Group by the path name so duplicates are removed - orderby !g.First(), g.Key // Order the remaining (distinct) items by folders first, then order by their name - select new PathOption(g.Key, g.First()); // Finally, put them in a POCO so we can bind the UI to these properties. + return Application.ParameterLookup.Children(WorkingPathStr).OrderBy(p => !p.IsFolder).ThenBy(p => p.DisplayName); } } @@ -115,7 +99,7 @@ private static void SelectedPathDPChanged(DependencyObject sender, DependencyPro // For the path to be valid (and to be passed as a param to this method) it will be a path to a variable, not a "directory". We use this assumption. picker.WorkingPath = new Stack(e.NewValue.ToString().Split('/')); picker.WorkingPath.Pop(); // Remove the last one, since the working path should not include the actual var name - picker.NotifyChanged(nameof(WorkingPath), nameof(WorkingPathStr), nameof(ParameterList), nameof(CurrentParameterListItems)); // All these things will be different now, so trigger an update of anything requiring them + picker.NotifyChanged(nameof(WorkingPath), nameof(WorkingPathStr), nameof(CurrentParameterListItems)); // All these things will be different now, so trigger an update of anything requiring them picker.mainListBox.SelectedValue = e.NewValue.ToString().Split('/').Last(); // The selected item in the list will be the last part of the path } @@ -141,18 +125,17 @@ public Application Application { /// /// The types of properties that will be shown to the user. /// - public PropertyType PropertyType { - get => (PropertyType)GetValue(PropertyTypeProperty); + public GSIPropertyType PropertyType { + get => (GSIPropertyType)GetValue(PropertyTypeProperty); set => SetValue(PropertyTypeProperty, value); } public static readonly DependencyProperty PropertyTypeProperty = - DependencyProperty.Register(nameof(PropertyType), typeof(PropertyType), typeof(GameStateParameterPicker), new PropertyMetadata(PropertyType.None, ApplicationOrPropertyTypeChange)); + DependencyProperty.Register(nameof(PropertyType), typeof(GSIPropertyType), typeof(GameStateParameterPicker), new PropertyMetadata(GSIPropertyType.None, ApplicationOrPropertyTypeChange)); public static void ApplicationOrPropertyTypeChange(DependencyObject sender, DependencyPropertyChangedEventArgs e) { var picker = (GameStateParameterPicker)sender; - picker.parameterList = null; - picker.NotifyChanged(nameof(ParameterList), nameof(CurrentParameterListItems)); + picker.NotifyChanged(nameof(CurrentParameterListItems)); if (!picker.ValidatePath(picker.SelectedPath)) picker.SelectedPath = ""; @@ -165,11 +148,11 @@ public static void ApplicationOrPropertyTypeChange(DependencyObject sender, Depe /// private bool ValidatePath(string path) => // If application parameter context doesn't exist or there is no set type, assume non loaded and allow the path - Application?.ParameterLookup == null || PropertyType == PropertyType.None + Application?.ParameterLookup == null || PropertyType == GSIPropertyType.None // An empty path is fine || string.IsNullOrEmpty(path) // If we're in number mode, allow the selected path to be a double - || (PropertyType == PropertyType.Number && double.TryParse(path, out var _)) + || (PropertyType == GSIPropertyType.Number && double.TryParse(path, out var _)) // If not in number mode, must be a valid path and have the same type as the expected property type || Application.ParameterLookup.IsValidParameter(path, PropertyType); @@ -246,7 +229,7 @@ private void MainListBox_PreviewMouseLeftButtonDown(object sender, System.Window auxillaryListbox.ItemsSource = CurrentParameterListItems; // Add the clicked item to the working path (even if it is an end variable, not a "directory") - WorkingPath.Push(((PathOption)item.DataContext).Path); + WorkingPath.Push(((GameStateParameterLookupEntry)item.DataContext).Path); var path = string.Join("/", WorkingPath.Reverse()); if (Application?.ParameterLookup?.IsValidParameter(path) ?? false) { @@ -281,21 +264,6 @@ private void NotifyChanged(params string[] propNames) { foreach (var prop in propNames) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop)); } - - - /// - /// Basic POCO for holding a bit of metadata about a path option. - /// - public class PathOption { - public PathOption(string path, bool isFolder) { - Path = path; - IsFolder = isFolder; - } - - public string DisplayPath => Path.CamelCaseToSpaceCase(); - public string Path { get; } - public bool IsFolder { get; } - } } @@ -325,10 +293,10 @@ public class IsStringNotNullOrWhitespaceConverter : IValueConverter { /// /// Converter that converts a PropertyType enum value to a GridLength. Used for binding onto one of the row definition properties to hide a row when - /// the property type is anything other than . + /// the property type is anything other than . /// public class PropertyTypeToGridLengthConverter : IValueConverter { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => new GridLength(0, (PropertyType)value == PropertyType.Number ? GridUnitType.Auto : GridUnitType.Pixel); + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => new GridLength(0, (GSIPropertyType)value == GSIPropertyType.Number ? GridUnitType.Auto : GridUnitType.Pixel); public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => new NotImplementedException(); } diff --git a/Project-Aurora/Project-Aurora/Profiles/Application.cs b/Project-Aurora/Project-Aurora/Profiles/Application.cs index 571e7bb47..bd92adbfc 100755 --- a/Project-Aurora/Project-Aurora/Profiles/Application.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Application.cs @@ -68,7 +68,7 @@ public class Application : ObjectSettings, IInit, ILightEve public bool Disposed { get; protected set; } = false; public ApplicationProfile Profile { get; set; } public ObservableCollection Profiles { get; set; } - public Dictionary> ParameterLookup { get; set; } //Key = variable path, Value = {Return type, Parameter type} + public GameStateParameterLookup ParameterLookup { get; set; } public bool HasLayers { get; set; } public event EventHandler ProfileChanged; public bool ScriptsLoaded { get; protected set; } @@ -108,7 +108,7 @@ public Application(LightEventConfig config) }; EffectScripts = new Dictionary(); if (config.GameStateType != null) - ParameterLookup = Utils.GameStateUtils.ReflectGameStateParameters(config.GameStateType); + ParameterLookup = new GameStateParameterLookup(config.GameStateType); } public virtual bool Initialize() diff --git a/Project-Aurora/Project-Aurora/Profiles/Borderlands 2/GSI/GameState_Borderlands2.cs b/Project-Aurora/Project-Aurora/Profiles/Borderlands 2/GSI/GameState_Borderlands2.cs index 6a742c84d..74ff7038b 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Borderlands 2/GSI/GameState_Borderlands2.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Borderlands 2/GSI/GameState_Borderlands2.cs @@ -38,13 +38,5 @@ public GameState_Borderlands2() : base() public GameState_Borderlands2(string json_data) : base(json_data) { } - - /// - /// A copy constructor, creates a GameState_Borderlands2 instance based on the data from the passed GameState instance. - /// - /// The passed GameState - public GameState_Borderlands2(IGameState other_state) : base(other_state) - { - } } } diff --git a/Project-Aurora/Project-Aurora/Profiles/CSGO/GSI/GameState_CSGO.cs b/Project-Aurora/Project-Aurora/Profiles/CSGO/GSI/GameState_CSGO.cs index 74a5e6b1b..c415512f1 100644 --- a/Project-Aurora/Project-Aurora/Profiles/CSGO/GSI/GameState_CSGO.cs +++ b/Project-Aurora/Project-Aurora/Profiles/CSGO/GSI/GameState_CSGO.cs @@ -151,34 +151,8 @@ public AuthNode Auth } } - /// - /// Creates a default GameState_CSGO instance. - /// - public GameState_CSGO() - { - json = "{}"; - _ParsedData = Newtonsoft.Json.Linq.JObject.Parse(json); - } - - /// - /// Creates a GameState_CSGO instance based on the passed json data. - /// - /// The passed json data - public GameState_CSGO(string JSONstring) - { - if (String.IsNullOrWhiteSpace(JSONstring)) - JSONstring = "{}"; - - json = JSONstring; - _ParsedData = JObject.Parse(JSONstring); - } - /// - /// A copy constructor, creates a GameState_CSGO instance based on the data from the passed GameState instance. - /// - /// The passed GameState - public GameState_CSGO(IGameState other_state) : base(other_state) - { - } + public GameState_CSGO() : base() { } + public GameState_CSGO(string json_data) : base(json_data) { } } } diff --git a/Project-Aurora/Project-Aurora/Profiles/CSGO/GSI/Nodes/AllPlayersNode.cs b/Project-Aurora/Project-Aurora/Profiles/CSGO/GSI/Nodes/AllPlayersNode.cs index 035d0e2b4..d19a2dd7f 100644 --- a/Project-Aurora/Project-Aurora/Profiles/CSGO/GSI/Nodes/AllPlayersNode.cs +++ b/Project-Aurora/Project-Aurora/Profiles/CSGO/GSI/Nodes/AllPlayersNode.cs @@ -77,7 +77,6 @@ public PlayerNode this[int index] /// Retrieves the enumerator for all players list /// /// The enumerator - [GameStateIgnoreAttribute] public IEnumerator GetEnumerator() { return _Players.GetEnumerator(); @@ -89,7 +88,6 @@ public IEnumerator GetEnumerator() /// The team to lookup /// A list of players //[Range(0, 16)] - [GameStateIgnoreAttribute] public List GetTeam(PlayerTeam Team) { return _Players.FindAll(x => x.Team == Team); diff --git a/Project-Aurora/Project-Aurora/Profiles/CloneHero/GSI/GameState_CloneHero.cs b/Project-Aurora/Project-Aurora/Profiles/CloneHero/GSI/GameState_CloneHero.cs index 568f7264a..13ba4613c 100644 --- a/Project-Aurora/Project-Aurora/Profiles/CloneHero/GSI/GameState_CloneHero.cs +++ b/Project-Aurora/Project-Aurora/Profiles/CloneHero/GSI/GameState_CloneHero.cs @@ -38,13 +38,5 @@ public GameState_CloneHero() : base() public GameState_CloneHero(string json_data) : base(json_data) { } - - /// - /// A copy constructor, creates a GameState_CloneHero instance based on the data from the passed GameState instance. - /// - /// The passed GameState - public GameState_CloneHero(IGameState other_state) : base(other_state) - { - } } } diff --git a/Project-Aurora/Project-Aurora/Profiles/Discord/GSI/GameState_Discord.cs b/Project-Aurora/Project-Aurora/Profiles/Discord/GSI/GameState_Discord.cs index 5fab27c80..5cc540109 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Discord/GSI/GameState_Discord.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Discord/GSI/GameState_Discord.cs @@ -1,11 +1,5 @@ using Aurora.Profiles.Discord.GSI.Nodes; using Aurora.Profiles.Generic.GSI.Nodes; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Aurora.Profiles.Discord.GSI { @@ -21,21 +15,8 @@ public class GameState_Discord : GameState public VoiceNode Voice => NodeFor("voice"); - /// - /// Creates a default GameState_Discord instance. - /// - public GameState_Discord() : base() { } - /// - /// Creates a GameState_Discord instance based on the passed JSON data. - /// - /// + public GameState_Discord() : base() { } public GameState_Discord(string JSONstring) : base(JSONstring) { } - - /// - /// Creates a GameState_Discord instance based on the data from the passed GameState instance. - /// - public GameState_Discord(IGameState other) : base(other) { } - } } diff --git a/Project-Aurora/Project-Aurora/Profiles/Dishonored/GSI/GameState_Dishonored.cs b/Project-Aurora/Project-Aurora/Profiles/Dishonored/GSI/GameState_Dishonored.cs index ec267b79b..6f9a5d87b 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Dishonored/GSI/GameState_Dishonored.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Dishonored/GSI/GameState_Dishonored.cs @@ -1,5 +1,4 @@ using Aurora.Profiles.Dishonored.GSI.Nodes; -using System; namespace Aurora.Profiles.Dishonored.GSI { @@ -24,27 +23,8 @@ public Player_Dishonored Player } } - /// - /// Creates a default GameState_Dishonored instance. - /// - public GameState_Dishonored() : base() - { - } - /// - /// Creates a GameState instance based on the passed json data. - /// - /// The passed json data - public GameState_Dishonored(string json_data) : base(json_data) - { - } - - /// - /// A copy constructor, creates a GameState_Dishonored instance based on the data from the passed GameState instance. - /// - /// The passed GameState - public GameState_Dishonored(IGameState other_state) : base(other_state) - { - } + public GameState_Dishonored() : base() { } + public GameState_Dishonored(string json_data) : base(json_data) { } } } diff --git a/Project-Aurora/Project-Aurora/Profiles/Dota 2/GSI/GameState_Dota2.cs b/Project-Aurora/Project-Aurora/Profiles/Dota 2/GSI/GameState_Dota2.cs index afd43159c..663292b37 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Dota 2/GSI/GameState_Dota2.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Dota 2/GSI/GameState_Dota2.cs @@ -18,28 +18,8 @@ public class GameState_Dota2 : GameState private GameState_Dota2 previously; private GameState_Dota2 added; - /// - /// Creates a default GameState_Dota2 instance. - /// - public GameState_Dota2() : base() - { - } - - /// - /// Creates a GameState instance based on the passed json data. - /// - /// The passed json data - public GameState_Dota2(string json_data) : base(json_data) - { - } - - /// - /// A copy constructor, creates a GameState_Dota2 instance based on the data from the passed GameState instance. - /// - /// The passed GameState - public GameState_Dota2(IGameState other_state) : base(other_state) - { - } + public GameState_Dota2() : base() { } + public GameState_Dota2(string json_data) : base(json_data) { } /// /// Information about GSI authentication diff --git a/Project-Aurora/Project-Aurora/Profiles/Dota 2/GSI/Nodes/Items.cs b/Project-Aurora/Project-Aurora/Profiles/Dota 2/GSI/Nodes/Items.cs index 6f585b59b..2710a2501 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Dota 2/GSI/Nodes/Items.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Dota 2/GSI/Nodes/Items.cs @@ -56,7 +56,6 @@ internal Items_Dota2(string json_data) : base(json_data) /// /// The index /// - [GameStateIgnore] public Item GetInventoryAt(int index) { if (index > inventory.Count - 1) @@ -70,7 +69,6 @@ public Item GetInventoryAt(int index) /// /// The index /// - [GameStateIgnore] public Item GetStashAt(int index) { if (index > stash.Count - 1) @@ -116,7 +114,6 @@ public bool StashContains(string itemname) /// /// The item name /// The first index at which item is found, -1 if not found. - [GameStateIgnore] public int InventoryIndexOf(string itemname) { for (int x = 0; x < this.inventory.Count; x++) @@ -133,7 +130,6 @@ public int InventoryIndexOf(string itemname) /// /// The item name /// The first index at which item is found, -1 if not found. - [GameStateIgnore] public int StashIndexOf(string itemname) { for (int x = 0; x < this.stash.Count; x++) diff --git a/Project-Aurora/Project-Aurora/Profiles/ETS2/GSI/GameState_ETS2.cs b/Project-Aurora/Project-Aurora/Profiles/ETS2/GSI/GameState_ETS2.cs index 2c5968894..62600900d 100644 --- a/Project-Aurora/Project-Aurora/Profiles/ETS2/GSI/GameState_ETS2.cs +++ b/Project-Aurora/Project-Aurora/Profiles/ETS2/GSI/GameState_ETS2.cs @@ -82,12 +82,6 @@ public GameState_ETS2() : base() { } /// The JSON data to parse. public GameState_ETS2(string json_data) : base(json_data) { } - /// - /// Creates a GameState_ETS2 instance based on data from another GateState instance. - /// - /// The GameState to copy. - public GameState_ETS2(IGameState other) : base(other) { } - /// /// Creates a GameState_ETS2 instance based on data that has been read from the MemoryMappedFile /// into a ETS2MemoryStruct. diff --git a/Project-Aurora/Project-Aurora/Profiles/GTA5/GSI/GameState_GTA5.cs b/Project-Aurora/Project-Aurora/Profiles/GTA5/GSI/GameState_GTA5.cs index ce2af985e..cae955cd9 100644 --- a/Project-Aurora/Project-Aurora/Profiles/GTA5/GSI/GameState_GTA5.cs +++ b/Project-Aurora/Project-Aurora/Profiles/GTA5/GSI/GameState_GTA5.cs @@ -130,11 +130,7 @@ public class GameState_GTA5 : GameState_Wrapper /// /// Creates a default GameState_GTA5 instance. /// - public GameState_GTA5() - { - json = "{}"; - _ParsedData = Newtonsoft.Json.Linq.JObject.Parse(json); - } + public GameState_GTA5() { } private byte RoundTo5(byte no) { @@ -173,23 +169,6 @@ public GameState_GTA5(string json_data) : base(json_data) HasCops = LeftSirenColor != RightSirenColor; } - /// - /// A copy constructor, creates a GameState_GTA5 instance based on the data from the passed GameState instance. - /// - /// The passed GameState - public GameState_GTA5(IGameState other_state) : base(other_state) - { - GameState_GTA5 gta = other_state as GameState_GTA5; - if (gta != null) - { - this.HasCops = gta.HasCops; - this.LeftSirenColor = gta.LeftSirenColor; - this.RightSirenColor = gta.RightSirenColor; - this.CurrentState = gta.CurrentState; - this.StateColor = gta.StateColor; - } - } - private Color JSonToColor(byte a, byte r, byte g, byte b) { return Color.FromArgb(a, r, g, b); diff --git a/Project-Aurora/Project-Aurora/Profiles/GameState.cs b/Project-Aurora/Project-Aurora/Profiles/GameState.cs index 279e099b1..d2391a41b 100644 --- a/Project-Aurora/Project-Aurora/Profiles/GameState.cs +++ b/Project-Aurora/Project-Aurora/Profiles/GameState.cs @@ -1,48 +1,33 @@ -using Aurora.Profiles; -using Microsoft.VisualBasic.Devices; +using Aurora.Utils; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json.Linq; -using NAudio.CoreAudioApi; -using Aurora.Utils; namespace Aurora.Profiles { - public class GameStateIgnoreAttribute : Attribute - { } - - public class RangeAttribute : Attribute - { - public int Start { get; set; } - - public int End { get; set; } - - public RangeAttribute(int start, int end) - { - Start = start; - End = end; - } - } /// /// A class representing various information retaining to the game. /// - public interface IGameState - { - /// - /// Information about the local system - /// - //LocalPCInformation LocalPCInfo { get; } - - JObject _ParsedData { get; set; } - string json { get; set; } - + public interface IGameState { + JObject _ParsedData { get; } + string Json { get; } string GetNode(string name); + + /// Attempts to resolve the given path into a numeric value. Returns 0 on failure. + double GetNumber(string path); + + /// Attempts to resolve the given path into a boolean value. Returns false on failure. + bool GetBool(string path); + + /// Attempts to resolve the given path into a string value. Returns an empty string on failure. + string GetString(string path); + + /// Attempts to resolve the given path into a enum value. Returns null on failure. + Enum GetEnum(string path); + + /// Attempts to resolve the given path into a numeric value. Returns default on failure. + TEnum GetEnum(string path) where TEnum : Enum; } public class GameState : IGameState where TSelf : GameState @@ -52,46 +37,31 @@ public class GameState : IGameState where TSelf : GameState // Holds a cache of the child nodes on this gamestate private readonly Dictionary childNodes = new Dictionary(StringComparer.OrdinalIgnoreCase); - /// - /// Information about the local system - /// - public LocalPCInformation LocalPCInfo => _localpcinfo ?? (_localpcinfo = new LocalPCInformation()); + [GameStateIgnore] public JObject _ParsedData { get; } + [GameStateIgnore] public string Json { get; } - [GameStateIgnore] public JObject _ParsedData { get; set; } - [GameStateIgnore] public string json { get; set; } + public LocalPCInformation LocalPCInfo => _localpcinfo ?? (_localpcinfo = new LocalPCInformation()); /// /// Creates a default GameState instance. /// - public GameState() : base() - { - json = "{}"; - _ParsedData = JObject.Parse(json); + public GameState() : base() { + Json = "{}"; + _ParsedData = new JObject(); } /// /// Creates a GameState instance based on the passed json data. /// /// The passed json data - public GameState(string json_data) : base() - { - if (String.IsNullOrWhiteSpace(json_data)) + public GameState(string json_data) : base() { + if (string.IsNullOrWhiteSpace(json_data)) json_data = "{}"; - json = json_data; + Json = json_data; _ParsedData = JObject.Parse(json_data); } - /// - /// A copy constructor, creates a GameState instance based on the data from the passed GameState instance. - /// - /// The passed GameState - public GameState(IGameState other_state) : base() - { - _ParsedData = other_state._ParsedData; - json = other_state.json; - } - /// /// Gets the JSON for a child node in this GameState. /// @@ -104,11 +74,72 @@ public string GetNode(string name) => protected TNode NodeFor(string name) where TNode : Node => (TNode)(childNodes.TryGetValue(name, out var n) ? n : (childNodes[name] = Instantiator.Create(_ParsedData[name]?.ToString() ?? ""))); + #region GameState path resolution + /// + /// Attempts to resolve the given GameState path into a value. + /// Returns whether or not the path resulted in a field or property (true) or was invalid (false). + /// + /// The that the property must match for this to be valid. + /// The current value of the resulting property or field on this instance. + private bool TryResolveGSPath(string path, GSIPropertyType type, out object value) { + value = null; + return !string.IsNullOrEmpty(path) + && (value = this.ResolvePropertyPath(path)) != null + && !GSIPropertyTypeConverter.IsTypePropertyType(value?.GetType(), type); + } + + public double GetNumber(string path) { + if (double.TryParse(path, out var val)) // If the path is a raw number, return that + return val; + if (TryResolveGSPath(path, GSIPropertyType.Number, out var pVal)) // Next, try resolve the path as we would other types + return Convert.ToDouble(pVal); + return 0; + } + + public bool GetBool(string path) => TryResolveGSPath(path, GSIPropertyType.Boolean, out var @bool) ? Convert.ToBoolean(@bool) : false; + public string GetString(string path) => TryResolveGSPath(path, GSIPropertyType.String, out var str) ? str.ToString() : ""; + public Enum GetEnum(string path) => TryResolveGSPath(path, GSIPropertyType.Enum, out var @enum) && @enum is Enum e ? e : null; + public TEnum GetEnum(string path) where TEnum : Enum => TryResolveGSPath(path, GSIPropertyType.Enum, out var @enum) && @enum is TEnum e ? e : default; + #endregion + /// /// Displays the JSON, representative of the GameState data /// /// JSON String - public override string ToString() => json; + public override string ToString() => Json; + } + + + /// The valid types of GSI property. + public enum GSIPropertyType { None, Number, Boolean, String, Enum } + + internal static class GSIPropertyTypeConverter { + /// + /// A set of predicates that determine if the given is of the given + /// + private static Dictionary> predicates = new Dictionary> { + [GSIPropertyType.None] = _ => false, + [GSIPropertyType.Enum] = type => type.IsEnum, // Needs to take priority over number, since enums are stored as numbers as so IsNumericType would be true + [GSIPropertyType.Number] = type => TypeUtils.IsNumericType(type), + [GSIPropertyType.Boolean] = type => Type.GetTypeCode(type) == TypeCode.Boolean, + [GSIPropertyType.String] = type => Type.GetTypeCode(type) == TypeCode.String + }; + + /// + /// Gets the for the given . + /// + public static GSIPropertyType TypeToPropertyType(Type type) { + if (type == null) return GSIPropertyType.None; + foreach (var (propertyType, predicate) in predicates) + if (predicate(type)) + return propertyType; + return GSIPropertyType.None; + } + + /// + /// Determines if the given is valid for the given . + /// + public static bool IsTypePropertyType(Type type, GSIPropertyType propertyType) => type == null ? false : predicates[propertyType](type); } @@ -118,7 +149,28 @@ protected TNode NodeFor(string name) where TNode : Node public class EmptyGameState : GameState { public EmptyGameState() : base() { } - public EmptyGameState(IGameState gs) : base(gs) { } public EmptyGameState(string json) : base(json) { } } + + + /// + /// Attribute that can be applied to properties to indicate they should be excluded from the game state. + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class GameStateIgnoreAttribute : Attribute { } + + /// + /// Attribute that indicates the range of indicies that are valid for an enumerable game state property. + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class RangeAttribute : Attribute { + + public RangeAttribute(int start, int end) { + Start = start; + End = end; + } + + public int Start { get; set; } + public int End { get; set; } + } } diff --git a/Project-Aurora/Project-Aurora/Profiles/GameStateParameterLookup.cs b/Project-Aurora/Project-Aurora/Profiles/GameStateParameterLookup.cs new file mode 100644 index 000000000..8c229e7f7 --- /dev/null +++ b/Project-Aurora/Project-Aurora/Profiles/GameStateParameterLookup.cs @@ -0,0 +1,118 @@ +using Aurora.Utils; +using FastMember; +using Mono.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Aurora.Profiles { + + /// + /// Data structure that holds a record of all game state parameters for a particular type of GameState. + /// + public sealed class GameStateParameterLookup { + + // Internal parameter store. Key = full path, Value = meta + private readonly Dictionary lookup = new Dictionary(); + + /// + /// Creates a new by inspecting all properties on the given type. + /// + public GameStateParameterLookup(Type type) { + // Recursive function for visiting all types on the given type + // Will add relevant entries to lookup + void Visit(string path, string name, Type type) { + // If this is a variable that can be handled (such as a number or bool), add it to the lookup + if (GSIPropertyTypeConverter.TypeToPropertyType(type) != GSIPropertyType.None) + lookup.Add(path, GameStateParameterLookupEntry.Property(name, path, type)); + + else { + // Else if this not a variable, such as a Node, make a folder and visit it's children + if (path != "") // If it's the root folder, don't add it + lookup.Add(path, GameStateParameterLookupEntry.Folder(name, path)); + + var accessor = TypeAccessor.Create(type); + if (!accessor.GetMembersSupported) return; + foreach (var member in accessor.GetMembers()) { + if (member.Type == type) continue; + if (member.GetAttribute(typeof(GameStateIgnoreAttribute), true) is { }) continue; + Visit((path + "/" + member.Name).TrimStart('/'), member.Name, member.Type); + } + } + } + + // Start the recursive function at the root. + Visit("", "", type); + } + + /// + /// Attempts to get the definition for the folder or property at the given path. + /// + public GameStateParameterLookupEntry this[string path] => + lookup.TryGetValue(path, out var entry) ? entry : null; + + /// + /// Gets all the direct/first-level children of the folder at the given path.
+ /// Optionally, only children ones that either are of the given type (in the case of properties) or that contain atleast one property of the given type (in the case of folders). + ///
+ /// Only children that are within the folder at the given path will be returned. + /// If not , only children of this type and only folders that contain atleast one property of this type will be returned. + public IEnumerable Children(string path = "", GSIPropertyType type = GSIPropertyType.None) => + from kvp in lookup + where GetFolderOf(kvp.Key) == path // only include anything in this folder + where type == GSIPropertyType.None // if type is none, don't worry about type filtering + || (kvp.Value.IsFolder && AllChildren(kvp.Key).Any(c => c.Type == type)) // return a folder if it contains atleast one child of type + || (!kvp.Value.IsFolder && kvp.Value.Type == type) // return a property if it is of type + select kvp.Value; + + /// Returns a list of all children of the given path, REGARDLESS of depth. + private IEnumerable AllChildren(string path) { + if (!path.EndsWith("/")) path += '/'; + return from kvp in lookup where kvp.Key.StartsWith(path) select kvp.Value; + } + + /// + /// Determines if the given path results in a property of the given type. + /// + /// The result will only be true if the parameter type is of this type. If None is passed, any parameter type is allowed. + public bool IsValidParameter(string path, GSIPropertyType type = GSIPropertyType.None) => + lookup.TryGetValue(path, out var entry) && !entry.IsFolder && (type == GSIPropertyType.None || entry.Type == type); + + /// + /// Returns the folder that the given path is in. + /// + private string GetFolderOf(string path) => path.Contains('/') ? path.Substring(0, path.LastIndexOf('/')) : ""; + } + + + /// + /// Plain object that holds metadata about a single parameter or folder in the collection. + /// + public sealed class GameStateParameterLookupEntry { + public string Name { get; private set; } + public string Path { get; private set; } + public bool IsFolder { get; private set; } + public Type ClrType { get; private set; } + public GSIPropertyType Type { get; private set; } + + public string DisplayName => Name.CamelCaseToSpaceCase(); + + private GameStateParameterLookupEntry() { } + + internal static GameStateParameterLookupEntry Folder(string name, string path) => new GameStateParameterLookupEntry { + Name = name, + Path = path, + IsFolder = true, + ClrType = null, + Type = GSIPropertyType.None + }; + + internal static GameStateParameterLookupEntry Property(string name, string path, Type type) => new GameStateParameterLookupEntry { + Name = name, + Path = path, + IsFolder = false, + ClrType = type, + Type = GSIPropertyTypeConverter.TypeToPropertyType(type) + }; + } +} diff --git a/Project-Aurora/Project-Aurora/Profiles/GameState_Wrapper.cs b/Project-Aurora/Project-Aurora/Profiles/GameState_Wrapper.cs index 67d6b9357..745e28b5a 100644 --- a/Project-Aurora/Project-Aurora/Profiles/GameState_Wrapper.cs +++ b/Project-Aurora/Project-Aurora/Profiles/GameState_Wrapper.cs @@ -113,32 +113,13 @@ public Extra_Keys_Wrapper Extra_Keys /// /// Creates a default GameState_Wrapper instance. /// - public GameState_Wrapper() - { - json = "{}"; - _ParsedData = JObject.Parse(json); - } + public GameState_Wrapper() { } /// /// Creates a GameState_Wrapper instance based on the passed json data. /// /// The passed json data - public GameState_Wrapper(string json_data) : base(json_data) - { - if (String.IsNullOrWhiteSpace(json_data)) - json_data = "{}"; - - json = json_data; - _ParsedData = JObject.Parse(json_data); - } - - /// - /// A copy constructor, creates a GameState_Wrapper instance based on the data from the passed GameState instance. - /// - /// The passed GameState - public GameState_Wrapper(IGameState other_state) : base(other_state) - { - } + public GameState_Wrapper(string json_data) : base(json_data) { } } /// diff --git a/Project-Aurora/Project-Aurora/Profiles/LeagueOfLegends/GSI/GameState_LoL.cs b/Project-Aurora/Project-Aurora/Profiles/LeagueOfLegends/GSI/GameState_LoL.cs index cd59bad0b..5b44240bb 100644 --- a/Project-Aurora/Project-Aurora/Profiles/LeagueOfLegends/GSI/GameState_LoL.cs +++ b/Project-Aurora/Project-Aurora/Profiles/LeagueOfLegends/GSI/GameState_LoL.cs @@ -24,10 +24,5 @@ public GameState_LoL(string json_data) : base(json_data) { } - - public GameState_LoL(IGameState other_state) : base(other_state) - { - - } } } diff --git a/Project-Aurora/Project-Aurora/Profiles/LightingStateManager.cs b/Project-Aurora/Project-Aurora/Profiles/LightingStateManager.cs index 9c0cd6197..b4f2b84d6 100755 --- a/Project-Aurora/Project-Aurora/Profiles/LightingStateManager.cs +++ b/Project-Aurora/Project-Aurora/Profiles/LightingStateManager.cs @@ -563,7 +563,7 @@ public void GameStateUpdate(IGameState gs) { IGameState gameState = gs; if (profile.Config.GameStateType != null) - gameState = (IGameState)Activator.CreateInstance(profile.Config.GameStateType, gs.json); + gameState = (IGameState)Activator.CreateInstance(profile.Config.GameStateType, gs.Json); profile.SetGameState(gameState); } else if (gs is GameState_Wrapper && Global.Configuration.allow_all_logitech_bitmaps) diff --git a/Project-Aurora/Project-Aurora/Profiles/Minecraft/GSI/GameState_Minecraft.cs b/Project-Aurora/Project-Aurora/Profiles/Minecraft/GSI/GameState_Minecraft.cs index abc1be1c3..93024d302 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Minecraft/GSI/GameState_Minecraft.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Minecraft/GSI/GameState_Minecraft.cs @@ -41,11 +41,6 @@ public GameState_Minecraft() : base() { } /// /// public GameState_Minecraft(string JSONstring) : base(JSONstring) { } - - /// - /// Creates a GameState_Minecraft instance based on the data from the passed GameState instance. - /// - public GameState_Minecraft(IGameState other) : base(other) { } } } diff --git a/Project-Aurora/Project-Aurora/Profiles/Osu/GSI/GameState_Osu.cs b/Project-Aurora/Project-Aurora/Profiles/Osu/GSI/GameState_Osu.cs index e83755d09..6a7541af5 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Osu/GSI/GameState_Osu.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Osu/GSI/GameState_Osu.cs @@ -10,7 +10,6 @@ public class GameState_Osu : GameState { public GameState_Osu() : base() { } public GameState_Osu(string JSONstring) : base(JSONstring) { } - public GameState_Osu(IGameState other) : base(other) { } } public class GameNode : AutoJsonNode { diff --git a/Project-Aurora/Project-Aurora/Profiles/Payday 2/GSI/GameState_PD2.cs b/Project-Aurora/Project-Aurora/Profiles/Payday 2/GSI/GameState_PD2.cs index ff65dc147..48cef1fc9 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Payday 2/GSI/GameState_PD2.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Payday 2/GSI/GameState_PD2.cs @@ -118,34 +118,9 @@ public GameState_PD2 Previously } } - /// - /// Creates a default GameState_PD2 instance. - /// - public GameState_PD2() - { - json = "{}"; - _ParsedData = Newtonsoft.Json.Linq.JObject.Parse(json); - } - /// - /// Creates a GameState_PD2 instance based on the passed json data. - /// - /// The passed json data - public GameState_PD2(string JSONstring) - { - if (String.IsNullOrWhiteSpace(JSONstring)) - JSONstring = "{}"; - json = JSONstring; - _ParsedData = JObject.Parse(JSONstring); - } - - /// - /// A copy constructor, creates a GameState_CSGO instance based on the data from the passed GameState instance. - /// - /// The passed GameState - public GameState_PD2(IGameState other_state) : base(other_state) - { - } + public GameState_PD2() { } + public GameState_PD2(string json) : base(json) { } } } diff --git a/Project-Aurora/Project-Aurora/Profiles/Resident Evil 2/GSI/GameState_ResidentEvil2.cs b/Project-Aurora/Project-Aurora/Profiles/Resident Evil 2/GSI/GameState_ResidentEvil2.cs index 5e86d0033..264c9c753 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Resident Evil 2/GSI/GameState_ResidentEvil2.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Resident Evil 2/GSI/GameState_ResidentEvil2.cs @@ -38,13 +38,5 @@ public GameState_ResidentEvil2() : base() public GameState_ResidentEvil2(string json_data) : base(json_data) { } - - /// - /// A copy constructor, creates a GameState_ResidentEvil2 instance based on the data from the passed GameState instance. - /// - /// The passed GameState - public GameState_ResidentEvil2(IGameState other_state) : base(other_state) - { - } } } diff --git a/Project-Aurora/Project-Aurora/Profiles/RocketLeague/GSI/GameState_RocketLeague.cs b/Project-Aurora/Project-Aurora/Profiles/RocketLeague/GSI/GameState_RocketLeague.cs index 5cf51e160..9f13157ad 100644 --- a/Project-Aurora/Project-Aurora/Profiles/RocketLeague/GSI/GameState_RocketLeague.cs +++ b/Project-Aurora/Project-Aurora/Profiles/RocketLeague/GSI/GameState_RocketLeague.cs @@ -49,12 +49,6 @@ public GameState_RocketLeague() : base() { } /// The passed json data public GameState_RocketLeague(string json_data) : base(json_data) { } - /// - /// A copy constructor, creates a GameState_RocketLeague instance based on the data from the passed GameState instance. - /// - /// The passed GameState - public GameState_RocketLeague(IGameState other_state) : base(other_state) { } - /// /// Returns true if all the color values for both teams are between zero and one. /// diff --git a/Project-Aurora/Project-Aurora/Profiles/Slime Rancher/GSI/GameState_Slime_Rancher.cs b/Project-Aurora/Project-Aurora/Profiles/Slime Rancher/GSI/GameState_Slime_Rancher.cs index 1a080a824..2a5721184 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Slime Rancher/GSI/GameState_Slime_Rancher.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Slime Rancher/GSI/GameState_Slime_Rancher.cs @@ -112,11 +112,5 @@ public GameState_Slime_Rancher() : base() { } ///
/// public GameState_Slime_Rancher(string JSONstring) : base(JSONstring) { } - - /// - /// Creates a GameState_Slime_Rancher instance based on the data from the passed GameState instance. - /// - public GameState_Slime_Rancher(IGameState other) : base(other) { } - } } diff --git a/Project-Aurora/Project-Aurora/Profiles/Subnautica/GSI/GameState_Subnautica.cs b/Project-Aurora/Project-Aurora/Profiles/Subnautica/GSI/GameState_Subnautica.cs index ca40f2b0e..f0cf809af 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Subnautica/GSI/GameState_Subnautica.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Subnautica/GSI/GameState_Subnautica.cs @@ -84,11 +84,6 @@ public GameState_Subnautica() : base() { } /// /// public GameState_Subnautica(string JSONstring) : base(JSONstring) { } - - /// - /// Creates a GameState_Subnautica instance based on the data from the passed GameState instance. - /// - public GameState_Subnautica(IGameState other) : base(other) { } } } diff --git a/Project-Aurora/Project-Aurora/Profiles/Terraria/GSI/GameState_Terraria.cs b/Project-Aurora/Project-Aurora/Profiles/Terraria/GSI/GameState_Terraria.cs index 7680e60a0..78ea1ad23 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Terraria/GSI/GameState_Terraria.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Terraria/GSI/GameState_Terraria.cs @@ -15,17 +15,8 @@ public class GameState_Terraria : GameState { public PlayerNode Player => NodeFor("player"); - public GameState_Terraria() : base() { } - /// - /// Creates a GameState_Terraria instance based on the passed JSON data. - /// - /// + public GameState_Terraria() : base() { } public GameState_Terraria(string JSONstring) : base(JSONstring) { } - - /// - /// Creates a GameState_Terraria instance based on the data from the passed GameState instance. - /// - public GameState_Terraria(IGameState other) : base(other) { } } } diff --git a/Project-Aurora/Project-Aurora/Profiles/Witcher3/GSI/GameState_Witcher3.cs b/Project-Aurora/Project-Aurora/Profiles/Witcher3/GSI/GameState_Witcher3.cs index 05fa7d34c..03eacaf70 100644 --- a/Project-Aurora/Project-Aurora/Profiles/Witcher3/GSI/GameState_Witcher3.cs +++ b/Project-Aurora/Project-Aurora/Profiles/Witcher3/GSI/GameState_Witcher3.cs @@ -35,13 +35,5 @@ public GameState_Witcher3() : base() public GameState_Witcher3(string json_data) : base(json_data) { } - - /// - /// A copy constructor, creates a GameState_Witcher3 instance based on the data from the passed GameState instance. - /// - /// The passed GameState - public GameState_Witcher3(IGameState other_state) : base(other_state) - { - } } } diff --git a/Project-Aurora/Project-Aurora/Project-Aurora.csproj b/Project-Aurora/Project-Aurora/Project-Aurora.csproj index 23eeed84d..6db822163 100644 --- a/Project-Aurora/Project-Aurora/Project-Aurora.csproj +++ b/Project-Aurora/Project-Aurora/Project-Aurora.csproj @@ -205,6 +205,7 @@ + @@ -676,6 +677,7 @@ + @@ -1479,7 +1481,6 @@ - diff --git a/Project-Aurora/Project-Aurora/Settings/Layers/AnimationLayerHandler.cs b/Project-Aurora/Project-Aurora/Settings/Layers/AnimationLayerHandler.cs index d6e87301b..b6c883cd7 100755 --- a/Project-Aurora/Project-Aurora/Settings/Layers/AnimationLayerHandler.cs +++ b/Project-Aurora/Project-Aurora/Settings/Layers/AnimationLayerHandler.cs @@ -216,7 +216,7 @@ private void CheckTriggers(IGameState gamestate) { // Evaluate the evaluatable or the game state path and retrieve the double double resolvedTriggerValue = IsTriggerEvaluatableNumericValueBased(Properties.TriggerMode) ? ((IEvaluatable)Properties.EvaluatableTrigger)?.Evaluate(gamestate) ?? 0 // Evaluatable may be null, so we need to account for that - : GameStateUtils.TryGetDoubleFromState(gamestate, Properties.TriggerPath); + : gamestate.GetNumber(Properties.TriggerPath); // Check to see if a gamestate value change should trigger the animation switch (Properties.TriggerMode) { @@ -243,7 +243,7 @@ private void CheckTriggers(IGameState gamestate) { // Evaluatable the boolean, either as an evaluatable or a game state variable. bool resolvedTriggerValue = IsTriggerEvaluatableBooleanValueBased(Properties.TriggerMode) ? ((IEvaluatable)Properties.EvaluatableTrigger)?.Evaluate(gamestate) ?? false // Evaluatable may be null, so we need to account for that - : GameStateUtils.TryGetBoolFromState(gamestate, Properties.TriggerPath); + : gamestate.GetBool(Properties.TriggerPath); switch (Properties.TriggerMode) { case AnimationTriggerMode.OnTrue: @@ -291,7 +291,7 @@ private void CheckTriggers(IGameState gamestate) { public override void SetApplication(Application profile) { // Check to ensure the property specified actually exists - if (profile != null && !string.IsNullOrWhiteSpace(Properties._TriggerPath) && !profile.ParameterLookup.ContainsKey(Properties._TriggerPath)) + if (profile != null && !string.IsNullOrWhiteSpace(Properties._TriggerPath) && !profile.ParameterLookup.IsValidParameter(Properties._TriggerPath)) Properties._TriggerPath = string.Empty; // Tell the control to update (will update the combobox with the possible variable paths) diff --git a/Project-Aurora/Project-Aurora/Settings/Layers/BinaryCounterLayerHandler.cs b/Project-Aurora/Project-Aurora/Settings/Layers/BinaryCounterLayerHandler.cs index d046afa60..87f5451ed 100644 --- a/Project-Aurora/Project-Aurora/Settings/Layers/BinaryCounterLayerHandler.cs +++ b/Project-Aurora/Project-Aurora/Settings/Layers/BinaryCounterLayerHandler.cs @@ -44,7 +44,7 @@ public override void SetApplication(Application profile) { public override EffectLayer Render(IGameState gamestate) { // Get the current game state value - double value = Properties.Logic._Value ?? Utils.GameStateUtils.TryGetDoubleFromState(gamestate, Properties.VariablePath); + double value = Properties.Logic._Value ?? gamestate.GetNumber(Properties.VariablePath); // Set the active key var layer = new EffectLayer("BinaryCounterCustomLayer"); diff --git a/Project-Aurora/Project-Aurora/Settings/Layers/ComparisonLayerHandler.cs b/Project-Aurora/Project-Aurora/Settings/Layers/ComparisonLayerHandler.cs index 37296c7c3..279794b0b 100644 --- a/Project-Aurora/Project-Aurora/Settings/Layers/ComparisonLayerHandler.cs +++ b/Project-Aurora/Project-Aurora/Settings/Layers/ComparisonLayerHandler.cs @@ -45,8 +45,8 @@ protected override UserControl CreateControl() { public override EffectLayer Render(IGameState gamestate) { // Parse the operands - double op1 = Utils.GameStateUtils.TryGetDoubleFromState(gamestate, Properties.Operand1Path); - double op2 = Utils.GameStateUtils.TryGetDoubleFromState(gamestate, Properties.Operand2Path); + double op1 = gamestate.GetNumber(Properties.Operand1Path); + double op2 = gamestate.GetNumber(Properties.Operand2Path); // Evaluate the operands bool cond = false; @@ -67,9 +67,9 @@ public override EffectLayer Render(IGameState gamestate) { public override void SetApplication(Application profile) { if (profile != null) { - if (!double.TryParse(Properties._Operand1Path, out double value) && !string.IsNullOrWhiteSpace(Properties._Operand1Path) && !profile.ParameterLookup.ContainsKey(Properties._Operand1Path)) + if (!double.TryParse(Properties._Operand1Path, out double value) && !string.IsNullOrWhiteSpace(Properties._Operand1Path) && !profile.ParameterLookup.IsValidParameter(Properties._Operand1Path)) Properties._Operand1Path = string.Empty; - if (!double.TryParse(Properties._Operand2Path, out value) && !string.IsNullOrWhiteSpace(Properties._Operand2Path) && !profile.ParameterLookup.ContainsKey(Properties._Operand2Path)) + if (!double.TryParse(Properties._Operand2Path, out value) && !string.IsNullOrWhiteSpace(Properties._Operand2Path) && !profile.ParameterLookup.IsValidParameter(Properties._Operand2Path)) Properties._Operand2Path = string.Empty; } (Control as Control_ComparisonLayer).SetProfile(profile); diff --git a/Project-Aurora/Project-Aurora/Settings/Layers/ConditionalLayerHandler.cs b/Project-Aurora/Project-Aurora/Settings/Layers/ConditionalLayerHandler.cs index d6381ae5e..eba3de449 100644 --- a/Project-Aurora/Project-Aurora/Settings/Layers/ConditionalLayerHandler.cs +++ b/Project-Aurora/Project-Aurora/Settings/Layers/ConditionalLayerHandler.cs @@ -31,12 +31,7 @@ protected override UserControl CreateControl() { public override EffectLayer Render(IGameState gamestate) { EffectLayer layer = new EffectLayer("Conditional Layer"); - bool result = false; - if (Properties.ConditionPath.Length > 0) - try { - object tmp = Utils.GameStateUtils.RetrieveGameStateParameter(gamestate, Properties.ConditionPath); - result = (bool)Utils.GameStateUtils.RetrieveGameStateParameter(gamestate, Properties.ConditionPath); - } catch { } + bool result = gamestate.GetBool(Properties.ConditionPath); layer.Set(Properties.Sequence, result ? Properties.PrimaryColor : Properties.SecondaryColor); return layer; @@ -44,7 +39,7 @@ public override EffectLayer Render(IGameState gamestate) { public override void SetApplication(Application profile) { if (profile != null) { - if (!string.IsNullOrWhiteSpace(Properties._ConditionPath) && !profile.ParameterLookup.ContainsKey(Properties._ConditionPath)) + if (!string.IsNullOrWhiteSpace(Properties._ConditionPath) && !profile.ParameterLookup.IsValidParameter(Properties._ConditionPath)) Properties._ConditionPath = string.Empty; } (Control as Control_ConditionalLayer).SetProfile(profile); diff --git a/Project-Aurora/Project-Aurora/Settings/Layers/Control_AnimationLayer.xaml.cs b/Project-Aurora/Project-Aurora/Settings/Layers/Control_AnimationLayer.xaml.cs index 10c2b50f8..5f1daa7ec 100644 --- a/Project-Aurora/Project-Aurora/Settings/Layers/Control_AnimationLayer.xaml.cs +++ b/Project-Aurora/Project-Aurora/Settings/Layers/Control_AnimationLayer.xaml.cs @@ -96,13 +96,13 @@ private void UpdatePathCombobox() { triggerPathItemsAreBoolean = isTriggerBoolean; // Get a list of the parameters. If trigger is boolean mode, filters to only boolean values, else does numeric values - triggerPath.ItemsSource = profile?.ParameterLookup? + /*triggerPath.ItemsSource = profile?.ParameterLookup? .Where(kvp => isTriggerBoolean ? kvp.Value.Item1 == typeof(bool) : TypeUtils.IsNumericType(kvp.Value.Item1) ) .Select(kvp => kvp.Key) - .ToList(); + .ToList();*/ } private void btnEditAnimation_Click(object sender, RoutedEventArgs e) { diff --git a/Project-Aurora/Project-Aurora/Settings/Layers/Control_BinaryCounterLayer.xaml b/Project-Aurora/Project-Aurora/Settings/Layers/Control_BinaryCounterLayer.xaml index c8ac1de12..c709d9061 100644 --- a/Project-Aurora/Project-Aurora/Settings/Layers/Control_BinaryCounterLayer.xaml +++ b/Project-Aurora/Project-Aurora/Settings/Layers/Control_BinaryCounterLayer.xaml @@ -32,7 +32,7 @@