diff --git a/Project-Aurora/Project-Aurora/Modules/GameStateListen/AuroraHttpListener.cs b/Project-Aurora/Project-Aurora/Modules/GameStateListen/AuroraHttpListener.cs index 4ad816f74..456518e2d 100644 --- a/Project-Aurora/Project-Aurora/Modules/GameStateListen/AuroraHttpListener.cs +++ b/Project-Aurora/Project-Aurora/Modules/GameStateListen/AuroraHttpListener.cs @@ -1,10 +1,12 @@ using System; using System.IO; using System.Net; +using System.Text.Json; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Windows; +using AuroraRgb.Nodes; using AuroraRgb.Profiles; using Common.Utils; @@ -31,6 +33,9 @@ public sealed partial class AuroraHttpListener private readonly HttpListener _netListener; private readonly int _port; private readonly SingleConcurrentThread _readThread; + private readonly SingleConcurrentThread _readThread2; + + private SingleConcurrentThread _nextReadThread; public IGameState CurrentGameState { @@ -62,7 +67,10 @@ public AuroraHttpListener(int port) _cancellationTokenSource = new CancellationTokenSource(); _cancellationToken = _cancellationTokenSource.Token; - _readThread = new SingleConcurrentThread("Http Read Thread", AsyncRead, ExceptionCallback); + _readThread = new SingleConcurrentThread("Http Read Thread 1", AsyncRead1, ExceptionCallback); + _readThread2 = new SingleConcurrentThread("Http Read Thread 2", AsyncRead2, ExceptionCallback); + + _nextReadThread = _readThread; } private static void ExceptionCallback(object? sender, SingleThreadExceptionEventArgs eventArgs) @@ -100,7 +108,24 @@ public bool Start() return true; } - private async Task AsyncRead() + private async Task AsyncRead1() + { + try + { + var context = await _netListener.GetContextAsync().WaitAsync(_cancellationToken); + if (!_cancellationToken.IsCancellationRequested) + { + _readThread2.Trigger(); + } + ProcessContext(context); + } + catch (TaskCanceledException) + { + // stop + } + } + + private async Task AsyncRead2() { try { @@ -155,6 +180,12 @@ private void ProcessContext(HttpListenerContext context) return null; } + if (path.StartsWith("/variables")) + { + ProcessVariables(json); + return null; + } + if (!path.StartsWith("/gameState/")) { return new NewtonsoftGameState(json); @@ -177,6 +208,39 @@ private void ProcessContext(HttpListenerContext context) return new NewtonsoftGameState(json, false); } + private static void ProcessVariables(string json) + { + var jsonNode = JsonSerializer.Deserialize(json); + switch (jsonNode.ValueKind) + { + case JsonValueKind.Object: + foreach (var property in jsonNode.EnumerateObject()) + { + var key = property.Name; + var value = property.Value; + switch (value.ValueKind) + { + case JsonValueKind.String: + AuroraVariables.Instance.Strings[key] = value.GetString() ?? string.Empty; + break; + case JsonValueKind.Number: + AuroraVariables.Instance.Numbers[key] = value.GetDouble(); + break; + case JsonValueKind.True: + case JsonValueKind.False: + AuroraVariables.Instance.Booleans[key] = value.GetBoolean(); + break; + case JsonValueKind.Null: + AuroraVariables.Instance.Strings.Remove(key); + AuroraVariables.Instance.Numbers.Remove(key); + AuroraVariables.Instance.Booleans.Remove(key); + break; + } + } + break; + } + } + private static string ReadContent(HttpListenerContext context, out string path) { var request = context.Request; diff --git a/Project-Aurora/Project-Aurora/Nodes/AuroraVariables.cs b/Project-Aurora/Project-Aurora/Nodes/AuroraVariables.cs new file mode 100644 index 000000000..5c0c5920b --- /dev/null +++ b/Project-Aurora/Project-Aurora/Nodes/AuroraVariables.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace AuroraRgb.Nodes; + +public class AuroraVariables +{ + public static readonly AuroraVariables Instance = new(); + + public Dictionary Booleans { get; } = new(8); + public Dictionary Numbers { get; } = new(8); + public Dictionary Strings { get; } = new(8); +} diff --git a/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/Boolean/Boolean_Variable.cs b/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/Boolean/Boolean_Variable.cs new file mode 100644 index 000000000..34b7eff98 --- /dev/null +++ b/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/Boolean/Boolean_Variable.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Media; +using AuroraRgb.Nodes; +using AuroraRgb.Profiles; +using AuroraRgb.Utils; + +namespace AuroraRgb.Settings.Overrides.Logic.Boolean; + +[Evaluatable("Boolean Global Variable", category: EvaluatableCategory.Global)] +public class Boolean_Variable : Evaluatable +{ + public Evaluatable DefaultValue { get; set; } = new BooleanConstant(); + public Evaluatable VariableName { get; set; } = new StringConstant(); + + public Boolean_Variable() { } + + public Boolean_Variable(Evaluatable variableName, Evaluatable defaultValue) { + VariableName = variableName; + DefaultValue = defaultValue; + } + + protected override bool Execute(IGameState gameState) + { + var key = VariableName.Evaluate(gameState); + var defaultValue = DefaultValue.Evaluate(gameState); + return AuroraVariables.Instance.Booleans.GetValueOrDefault(key, defaultValue); + } + + public override Visual GetControl() + { + return new StackPanel { Orientation = Orientation.Horizontal } + .WithChild(new TextBlock { Text = "Name", FontWeight = FontWeights.Bold, Margin = new Thickness(2, 0, 6, 0), VerticalAlignment = VerticalAlignment.Center }) + .WithChild(new Control_EvaluatablePresenter { EvalType = typeof(string) } + .WithBinding(Control_EvaluatablePresenter.ExpressionProperty, new Binding(nameof(VariableName)) { Source = this, Mode = BindingMode.TwoWay })) + .WithChild(new TextBlock { Text = "Default Value", FontWeight = FontWeights.Bold, Margin = new Thickness(2, 0, 6, 0), VerticalAlignment = VerticalAlignment.Center }) + .WithChild(new Control_EvaluatablePresenter { EvalType = typeof(bool) } + .WithBinding(Control_EvaluatablePresenter.ExpressionProperty, new Binding(nameof(DefaultValue)) { Source = this, Mode = BindingMode.TwoWay })); + } + + public override Evaluatable Clone() + { + return new Boolean_Variable(VariableName, DefaultValue); + } +} \ No newline at end of file diff --git a/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/EvaluatableAttribute.cs b/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/EvaluatableAttribute.cs index 7497a59ee..09728c909 100644 --- a/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/EvaluatableAttribute.cs +++ b/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/EvaluatableAttribute.cs @@ -26,7 +26,7 @@ public EvaluatableAttribute(string name, EvaluatableCategory category = Evaluata public EvaluatableCategory Category { get; } /// Gets the description of the category as a string. - public string CategoryStr => EnumUtils.GetDescription(Category); + public string CategoryStr => Category.GetDescription(); } public enum EvaluatableCategory { @@ -35,5 +35,6 @@ public enum EvaluatableCategory { [Description("Input")] Input, [Description("Misc.")] Misc, [Description("Maths")] Maths, - [Description("String")] String + [Description("String")] String, + [Description("Global Variable")] Global, } \ No newline at end of file diff --git a/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/Number/Number_Variable.cs b/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/Number/Number_Variable.cs new file mode 100644 index 000000000..4d5bc6af6 --- /dev/null +++ b/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/Number/Number_Variable.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Media; +using AuroraRgb.Nodes; +using AuroraRgb.Profiles; +using AuroraRgb.Utils; + +namespace AuroraRgb.Settings.Overrides.Logic.Number; + +[Evaluatable("Number Global Variable", category: EvaluatableCategory.Global)] +public class Number_Variable : Evaluatable +{ + public Evaluatable DefaultValue { get; set; } = new NumberConstant(); + public Evaluatable VariableName { get; set; } = new StringConstant(); + + public Number_Variable() { } + + public Number_Variable(Evaluatable variableName, Evaluatable defaultValue) { + VariableName = variableName; + DefaultValue = defaultValue; + } + + protected override double Execute(IGameState gameState) + { + var key = VariableName.Evaluate(gameState); + var defaultValue = DefaultValue.Evaluate(gameState); + return AuroraVariables.Instance.Numbers.GetValueOrDefault(key, defaultValue); + } + + public override Visual GetControl() + { + return new StackPanel { Orientation = Orientation.Horizontal } + .WithChild(new TextBlock { Text = "Name", FontWeight = FontWeights.Bold, Margin = new Thickness(2, 0, 6, 0), VerticalAlignment = VerticalAlignment.Center }) + .WithChild(new Control_EvaluatablePresenter { EvalType = typeof(string) } + .WithBinding(Control_EvaluatablePresenter.ExpressionProperty, new Binding(nameof(VariableName)) { Source = this, Mode = BindingMode.TwoWay })) + .WithChild(new TextBlock { Text = "Default Value", FontWeight = FontWeights.Bold, Margin = new Thickness(2, 0, 6, 0), VerticalAlignment = VerticalAlignment.Center }) + .WithChild(new Control_EvaluatablePresenter { EvalType = typeof(double) } + .WithBinding(Control_EvaluatablePresenter.ExpressionProperty, new Binding(nameof(DefaultValue)) { Source = this, Mode = BindingMode.TwoWay })); + } + + public override Evaluatable Clone() + { + return new Number_Variable(VariableName, DefaultValue); + } +} \ No newline at end of file diff --git a/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/String/String_Variable.cs b/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/String/String_Variable.cs new file mode 100644 index 000000000..939601df0 --- /dev/null +++ b/Project-Aurora/Project-Aurora/Settings/Overrides/Logic/String/String_Variable.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Media; +using AuroraRgb.Nodes; +using AuroraRgb.Profiles; +using AuroraRgb.Utils; + +namespace AuroraRgb.Settings.Overrides.Logic; + +[Evaluatable("String Global Variable", category: EvaluatableCategory.Global)] +public class String_Variable : Evaluatable +{ + public Evaluatable DefaultValue { get; set; } = new StringConstant(); + public Evaluatable VariableName { get; set; } = new StringConstant(); + + public String_Variable() { } + + public String_Variable(Evaluatable variableName, Evaluatable defaultValue) + { + VariableName = variableName; + DefaultValue = defaultValue; + } + + protected override string Execute(IGameState gameState) + { + var key = VariableName.Evaluate(gameState); + var defaultValue = DefaultValue.Evaluate(gameState); + return AuroraVariables.Instance.Strings.GetValueOrDefault(key, defaultValue); + } + + public override Visual GetControl() + { + return new StackPanel { Orientation = Orientation.Horizontal } + .WithChild(new TextBlock { Text = "Name", FontWeight = FontWeights.Bold, Margin = new Thickness(2, 0, 6, 0), VerticalAlignment = VerticalAlignment.Center }) + .WithChild(new Control_EvaluatablePresenter { EvalType = typeof(string) } + .WithBinding(Control_EvaluatablePresenter.ExpressionProperty, new Binding(nameof(VariableName)) { Source = this, Mode = BindingMode.TwoWay })) + .WithChild(new TextBlock { Text = "Default Value", FontWeight = FontWeights.Bold, Margin = new Thickness(2, 0, 6, 0), VerticalAlignment = VerticalAlignment.Center }) + .WithChild(new Control_EvaluatablePresenter { EvalType = typeof(string) } + .WithBinding(Control_EvaluatablePresenter.ExpressionProperty, new Binding(nameof(DefaultValue)) { Source = this, Mode = BindingMode.TwoWay })); + } + + public override Evaluatable Clone() + { + return new String_Variable(VariableName, DefaultValue); + } +} \ No newline at end of file