alterNERDtive-base: plugin now fully supports the new configuration approach
This commit is contained in:
parent
ca52c39da3
commit
606f651eb6
4 changed files with 285 additions and 13 deletions
|
@ -122,7 +122,7 @@ namespace RatAttack
|
|||
}
|
||||
|
||||
private static void On_ProfileChanged(Guid? from, Guid? to, string fromName, string toName)
|
||||
=> VA_Exit1(null);
|
||||
=> VA_Exit1(VA);
|
||||
|
||||
/*================\
|
||||
| plugin contexts |
|
||||
|
|
|
@ -4,10 +4,7 @@ using alterNERDtive.util;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.Remoting.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace alterNERDtive
|
||||
{
|
||||
|
@ -22,12 +19,17 @@ namespace alterNERDtive
|
|||
};
|
||||
private static readonly List<string> ActiveProfiles = new List<string>();
|
||||
|
||||
private static readonly Regex ConfigurationVariableRegex = new Regex(@$"(?<id>(alterNERDtive-base|{String.Join("|", Profiles.Values)}))\.(?<name>.+)#");
|
||||
|
||||
private static VoiceAttackLog Log => log ??= new VoiceAttackLog(VA, "alterNERDtive-base");
|
||||
private static VoiceAttackLog? log;
|
||||
|
||||
private static VoiceAttackCommands Commands => commands ??= new VoiceAttackCommands(VA, Log);
|
||||
private static VoiceAttackCommands? commands;
|
||||
|
||||
private static Configuration Config => config ??= new Configuration(VA, Log, "alterNERDtive-base");
|
||||
private static Configuration? config;
|
||||
|
||||
private static void CheckProfiles(dynamic vaProxy)
|
||||
{
|
||||
ActiveProfiles.Clear();
|
||||
|
@ -44,6 +46,24 @@ namespace alterNERDtive
|
|||
| plugin contexts |
|
||||
\================*/
|
||||
|
||||
private static void Context_Config_Setup(dynamic vaProxy)
|
||||
{
|
||||
Log.Debug("Loading default configuration …");
|
||||
Config.ApplyAllDefaults();
|
||||
foreach (System.Type type in new List<System.Type> { typeof(bool), typeof(DateTime), typeof(decimal), typeof(int), typeof(short), typeof(string) })
|
||||
{
|
||||
Config.SetVoiceTriggers(type);
|
||||
}
|
||||
Log.Debug("Finished loading configuration.");
|
||||
}
|
||||
|
||||
private static void Context_Config_SetVariables(dynamic vaProxy)
|
||||
{
|
||||
string trigger = vaProxy.GetText("~trigger");
|
||||
Log.Debug($"Loading variables for trigger '{trigger}' …");
|
||||
Config.SetVariablesForTrigger(vaProxy, trigger);
|
||||
}
|
||||
|
||||
private static void Context_DistanceBetween(dynamic vaProxy)
|
||||
{
|
||||
string fromSystem = vaProxy.GetText("~fromSystem");
|
||||
|
@ -51,7 +71,7 @@ namespace alterNERDtive
|
|||
int roundTo = vaProxy.GetInt("~roundTo") ?? 2;
|
||||
|
||||
string path = $"{vaProxy.GetText("Python.ScriptPath")}\\explorationtools.exe";
|
||||
string arguments = $"distancebetween --roundto {roundTo} \"{fromSystem}\" \"{toSystem}\"";
|
||||
string arguments = $@"distancebetween --roundto {roundTo} ""{fromSystem}"" ""{toSystem}""";
|
||||
|
||||
Process p = PythonProxy.SetupPythonScript(path, arguments);
|
||||
|
||||
|
@ -113,9 +133,10 @@ namespace alterNERDtive
|
|||
{
|
||||
Log.Log(sender, message, (LogLevel)Enum.Parse(typeof(LogLevel), level.ToUpper()));
|
||||
}
|
||||
catch (ArgumentNullException) { throw; }
|
||||
catch (ArgumentException)
|
||||
{
|
||||
Log.Error($"Invalid log level '${level}'.");
|
||||
Log.Error($"Invalid log level '{level}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +144,6 @@ namespace alterNERDtive
|
|||
private static void Context_Startup(dynamic vaProxy)
|
||||
{
|
||||
Log.Notice("Starting up …");
|
||||
VA = vaProxy;
|
||||
CheckProfiles(VA);
|
||||
Commands.RunAll(ActiveProfiles, "startup", logMissing: true);
|
||||
Log.Notice("Finished startup.");
|
||||
|
@ -142,6 +162,35 @@ namespace alterNERDtive
|
|||
}
|
||||
}
|
||||
|
||||
private static void ConfigurationChanged(string name, dynamic? from, dynamic? to, Guid? guid = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Match match = ConfigurationVariableRegex.Match(name);
|
||||
if (match.Success)
|
||||
{
|
||||
string id = match.Groups["id"].Value;
|
||||
string option = match.Groups["name"].Value;
|
||||
Log.Debug($"Configuration has changed, '{id}.{option}': '{from}' → '{to}'");
|
||||
|
||||
// When loaded from profile but not explicitly set, will be null.
|
||||
// Then load default.
|
||||
// Same applies to resetting a saved option (= saving null to the profile).
|
||||
_ = to ?? Config.ApplyDefault(id, option);
|
||||
|
||||
if (name == "alterNERDtive-base.eddi.quietMode#" && VA!.GetText("EDDI version") != null) // if null, EDDI isn’t up yet
|
||||
{
|
||||
Log.Debug($"Resetting speech responder ({(to ?? false ? "off" : "on")}) …");
|
||||
Commands.Run("alterNERDtive-base.setEDDISpeechResponder");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"Unhandled exception while handling changed variable '{name}'. ({e.Message})");
|
||||
}
|
||||
}
|
||||
|
||||
/*========================================\
|
||||
| required VoiceAttack plugin shenanigans |
|
||||
\========================================*/
|
||||
|
@ -159,12 +208,20 @@ namespace alterNERDtive
|
|||
{
|
||||
VA = vaProxy;
|
||||
Log.Notice("Initializing …");
|
||||
vaProxy.BooleanVariableChanged += new Action<String, Boolean?, Boolean?, Guid?>((name, from, to, id) => { ConfigurationChanged(name, from, to, id); });
|
||||
vaProxy.DateVariableChanged += new Action<String, DateTime?, DateTime?, Guid?>((name, from, to, id) => { ConfigurationChanged(name, from, to, id); });
|
||||
vaProxy.DecimalVariableChanged += new Action<String, decimal?, decimal?, Guid?>((name, from, to, id) => { ConfigurationChanged(name, from, to, id); });
|
||||
vaProxy.IntegerVariableChanged += new Action<String, int?, int?, Guid?>((name, from, to, id) => { ConfigurationChanged(name, from, to, id); });
|
||||
vaProxy.TextVariableChanged += new Action<String, String, String, Guid?>((name, from, to, id) => { ConfigurationChanged(name, from, to, id); });
|
||||
VA.SetBoolean("alterNERDtive-base.initialized", true);
|
||||
Commands.TriggerEvent("alterNERDtive-base.initialized", wait: false);
|
||||
Log.Notice("Init successful.");
|
||||
}
|
||||
|
||||
public static void VA_Invoke1(dynamic vaProxy)
|
||||
{
|
||||
VA = vaProxy;
|
||||
|
||||
string context = vaProxy.Context.ToLower();
|
||||
Log.Debug($"Running context '{context}' …");
|
||||
try
|
||||
|
@ -172,6 +229,12 @@ namespace alterNERDtive
|
|||
switch (context)
|
||||
{
|
||||
// plugin methods
|
||||
case "config.setup":
|
||||
Context_Config_Setup(vaProxy);
|
||||
break;
|
||||
case "config.getvariables":
|
||||
Context_Config_SetVariables(vaProxy);
|
||||
break;
|
||||
case "distancebetween":
|
||||
Context_DistanceBetween(vaProxy);
|
||||
break;
|
||||
|
|
|
@ -5,10 +5,219 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Pipes;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
|
||||
namespace alterNERDtive.util
|
||||
{
|
||||
public class Configuration
|
||||
{
|
||||
private readonly dynamic VA;
|
||||
private readonly string ID;
|
||||
private readonly VoiceAttackLog Log;
|
||||
private static readonly Dictionary<string, OptDict<string, Option>> Defaults = new Dictionary<string, OptDict<string, Option>>
|
||||
{
|
||||
{
|
||||
"alterNERDtive-base",
|
||||
new OptDict<string, Option>{
|
||||
{ new Option("eddi.quietMode", true, voiceTrigger: "eddi quiet mode", description: "Whether or not to make EDDI shut up.") },
|
||||
{ new Option("keyPressDuration", (decimal)0.01, voiceTrigger: "key press duration", description: "The time keys will be held down for.") },
|
||||
{ new Option("elite.pasteKey", "v", voiceTrigger: "elite paste key", description: "The key used to paste in conjunction with CTRL. The key that would be 'V' on QWERTY.") }
|
||||
}
|
||||
},
|
||||
{
|
||||
"EliteAttack",
|
||||
new OptDict<string, Option>{
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
"RatAttack",
|
||||
new OptDict<string, Option>{
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
"SpanshAttack",
|
||||
new OptDict<string, Option>{
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
"StreamAttack",
|
||||
new OptDict<string, Option>{
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private class Option
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly dynamic DefaultValue;
|
||||
public readonly string VoiceTrigger;
|
||||
public string TtsDescription { get => ttsDescription ?? VoiceTrigger; }
|
||||
private readonly string? ttsDescription;
|
||||
public string Description { get => description ?? "No description available."; }
|
||||
public readonly string? description;
|
||||
|
||||
public Option(string name, dynamic defaultValue, string voiceTrigger, string? ttsDescription = null, string? description = null)
|
||||
=> (Name, DefaultValue, VoiceTrigger, this.ttsDescription, this.description) = (name, defaultValue, voiceTrigger, ttsDescription, description);
|
||||
|
||||
public static implicit operator (string, Option)(Option o) => ( o.Name, o );
|
||||
public static explicit operator bool(Option o) => o.DefaultValue;
|
||||
public static explicit operator DateTime(Option o) => o.DefaultValue;
|
||||
public static explicit operator decimal(Option o) => o.DefaultValue;
|
||||
public static explicit operator int(Option o) => o.DefaultValue;
|
||||
public static explicit operator short(Option o) => o.DefaultValue;
|
||||
public static explicit operator string(Option o) => o.DefaultValue;
|
||||
public override string ToString() => DefaultValue.ToString();
|
||||
}
|
||||
private class OptDict<TKey, TValue> : Dictionary<TKey, TValue>
|
||||
{
|
||||
public OptDict() : base() { }
|
||||
public OptDict(int capacity) : base(capacity) { }
|
||||
|
||||
public void Add((TKey,TValue) tuple)
|
||||
{
|
||||
base.Add(tuple.Item1, tuple.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
public Configuration(dynamic vaProxy, VoiceAttackLog log, string id) => (VA, Log, ID) = (vaProxy, log, id);
|
||||
|
||||
public dynamic GetDefault(string name)
|
||||
{
|
||||
return GetDefault(ID, name);
|
||||
}
|
||||
public static dynamic GetDefault(string id, string name)
|
||||
{
|
||||
return Defaults[id][name];
|
||||
}
|
||||
|
||||
public void SetVoiceTriggers(System.Type type)
|
||||
{
|
||||
List<string> triggers = new List<string>();
|
||||
foreach (Dictionary<string,Option> options in Defaults.Values)
|
||||
{
|
||||
foreach (Option option in options.Values)
|
||||
{
|
||||
if (option.DefaultValue.GetType() == type)
|
||||
{
|
||||
if (triggers.Contains(option.VoiceTrigger))
|
||||
{
|
||||
throw new ArgumentException($"Voice trigger '{option.VoiceTrigger}' is not unique, aborting …");
|
||||
}
|
||||
triggers.Add(option.VoiceTrigger);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (triggers.Count > 0)
|
||||
{
|
||||
string triggerString = string.Join(";", triggers);
|
||||
VA.SetText($"alterNERDtive-base.triggers.{type.Name}", triggerString);
|
||||
Log.Debug($"Voice triggers for {type.Name}: '{triggerString}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
// make sure we don’t accidentally have weird things happening with empty config voice triggers
|
||||
string triggerString = $"tenuiadafesslejüsljlejutlesuivle{type.Name}";
|
||||
VA.SetText($"alterNERDtive-base.triggers.{type.Name}", triggerString);
|
||||
Log.Debug($"No voice triggers found for {type.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVariablesForTrigger(dynamic vaProxy, string trigger)
|
||||
{
|
||||
_ = trigger ?? throw new ArgumentNullException("trigger");
|
||||
|
||||
foreach (KeyValuePair<string,OptDict<string,Option>> options in Defaults)
|
||||
{
|
||||
try
|
||||
{
|
||||
Option option = options.Value.First(item => item.Value.VoiceTrigger == trigger).Value;
|
||||
vaProxy.SetText("~name", $"{options.Key}.{option.Name}");
|
||||
vaProxy.SetText("~ttsDescription", option.TtsDescription);
|
||||
vaProxy.SetText("~description", option.Description);
|
||||
break;
|
||||
}
|
||||
catch (InvalidOperationException) { }
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasDefault(string name)
|
||||
{
|
||||
return HasDefault(ID, name);
|
||||
}
|
||||
public static bool HasDefault(string id, string name)
|
||||
{
|
||||
return Defaults[id].ContainsKey(name);
|
||||
}
|
||||
|
||||
public dynamic? ApplyDefault(string name)
|
||||
{
|
||||
return ApplyDefault(ID, name);
|
||||
}
|
||||
public dynamic? ApplyDefault(string id, string name)
|
||||
{
|
||||
if (!HasDefault(id, name))
|
||||
{
|
||||
Log.Warn($"No default configuration value found for '{id}.{name}'");
|
||||
return null;
|
||||
}
|
||||
|
||||
dynamic value = Defaults[id][name].DefaultValue;
|
||||
Log.Debug($"Loading default configuration value, '{id}.{name}': '{value}' …");
|
||||
string variable = $"{id}.{name}#";
|
||||
if (value is bool)
|
||||
{
|
||||
VA.SetBoolean(variable, value);
|
||||
}
|
||||
else if (value is DateTime)
|
||||
{
|
||||
VA.SetDate(variable, value);
|
||||
}
|
||||
else if (value is decimal)
|
||||
{
|
||||
VA.SetDecimal(variable, value);
|
||||
}
|
||||
else if (value is int)
|
||||
{
|
||||
VA.SetInt(variable, value);
|
||||
}
|
||||
else if (value is short)
|
||||
{
|
||||
VA.SetSmallInt(variable, value);
|
||||
}
|
||||
else if (value is string)
|
||||
{
|
||||
VA.SetText(variable, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException($"Invalid data type for option '{id}.{name}': '{value}'");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
public void ApplyDefaults()
|
||||
{
|
||||
ApplyDefaults(ID);
|
||||
}
|
||||
public void ApplyAllDefaults()
|
||||
{
|
||||
foreach (string id in Defaults.Keys)
|
||||
{
|
||||
ApplyDefaults(id);
|
||||
}
|
||||
}
|
||||
public void ApplyDefaults(string id)
|
||||
{
|
||||
foreach (string key in Defaults[id].Keys)
|
||||
{
|
||||
ApplyDefault(id, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PythonProxy
|
||||
{
|
||||
public static Process SetupPythonScript(string path, string arguments)
|
||||
|
@ -78,7 +287,7 @@ namespace alterNERDtive.util
|
|||
WaitForReturn: wait,
|
||||
AsSubcommand: subcommand,
|
||||
CompletedAction: callback,
|
||||
PassedText: strings == null ? null : $"\"{String.Join<string>("\";\"", strings)}\"",
|
||||
PassedText: strings == null ? null : $@"""{String.Join<string>(@""";""", strings)}""",
|
||||
PassedIntegers: integers == null ? null : String.Join<int>(";", integers),
|
||||
PassedDecimals: decimals == null ? null : String.Join<decimal>(";", decimals),
|
||||
PassedBooleans: booleans == null ? null : String.Join<bool>(";", booleans),
|
||||
|
@ -178,7 +387,7 @@ namespace alterNERDtive.util
|
|||
|
||||
public PipeServer<Thing> Run()
|
||||
{
|
||||
Log.Debug($"Starting “{PipeName}” pipe …");
|
||||
Log.Debug($"Starting '{PipeName}' pipe …");
|
||||
if (!Running)
|
||||
{
|
||||
Running = true;
|
||||
|
@ -189,7 +398,7 @@ namespace alterNERDtive.util
|
|||
|
||||
public PipeServer<Thing> Stop()
|
||||
{
|
||||
Log.Debug($"Stopping “{PipeName}” pipe …");
|
||||
Log.Debug($"Stopping '{PipeName}' pipe …");
|
||||
if (Running)
|
||||
{
|
||||
Running = false;
|
||||
|
@ -225,7 +434,7 @@ namespace alterNERDtive.util
|
|||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
Log.Info("Ratsignal pipe has been closed.");
|
||||
Log.Debug($"'{PipeName}' pipe has been closed.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
Binary file not shown.
Loading…
Reference in a new issue