more ground work brainstorming

This commit is contained in:
alterNERDtive 2022-07-07 14:58:12 +02:00
parent 6377a4142f
commit 36c7048f37
5 changed files with 354 additions and 33 deletions

View file

@ -19,6 +19,8 @@
using System;
using VoiceAttack;
namespace alterNERDtive.Yavapf.Example
{
public class ExamplePlugin
@ -27,13 +29,17 @@ namespace alterNERDtive.Yavapf.Example
static ExamplePlugin()
{
Plugin = new ()
{
Name = "Example Plugin",
Version = "0.0.1",
Info = "This is a description",
Guid = "{76FE674F-F729-45FD-A1DD-E53E9E66B360}",
};
Plugin = new (
name: "Example Plugin",
version: "0.0.1",
info: "This is a description",
guid: "{76FE674F-F729-45FD-A1DD-E53E9E66B360}");
Plugin.Init += Init;
Plugin.Exit += Exit;
Plugin.Stop += Stop;
Plugin.Contexts += Test;
}
public static string VA_DisplayName() => Plugin.VA_DisplayName();
@ -49,5 +55,24 @@ namespace alterNERDtive.Yavapf.Example
public static void VA_Exit1(dynamic vaProxy) => Plugin.VA_Exit1(vaProxy);
public static void VA_StopCommand() => Plugin.VA_StopCommand();
private static void Init(VoiceAttackInitProxyClass vaProxy)
{
}
private static void Exit(VoiceAttackProxyClass vaProxy)
{
}
private static void Stop()
{
}
[Context("test")]
[Context("other name")]
private static void Test(VoiceAttackInvokeProxyClass vaProxy)
{
Plugin.Log.Notice($"Plugin context '{vaProxy.Context}' invoked.");
}
}
}

View file

@ -6,10 +6,21 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VoiceAttack-Framework\VoiceAttack-Framework.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="VoiceAttack">
<HintPath>C:\Program Files\VoiceAttack\VoiceAttack.exe</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Settings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>

View file

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48</TargetFrameworks>
<RootNamespace>alterNERDtive.YAVAPF</RootNamespace>
<RootNamespace>alterNERDtive.Yavapf</RootNamespace>
<PackageId>alterNERDtive.YAVAPF</PackageId>
<Version>0.0.1</Version>
<Company>alterNERDtive</Company>
@ -38,7 +38,11 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ImpromptuInterface" Version="7.0.1" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="VoiceAttack">
<HintPath>C:\Program Files\VoiceAttack\VoiceAttack.exe</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
</Project>

View file

@ -0,0 +1,117 @@
// <copyright file="VoiceAttackLog.cs" company="alterNERDtive">
// Copyright 2022 alterNERDtive.
//
// This file is part of YAVAPF.
//
// YAVAPF is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// YAVAPF is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with YAVAPF. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
using System;
using VoiceAttack;
namespace alterNERDtive.Yavapf
{
public class VoiceAttackLog
{
private static readonly string[] LogColour = { "red", "yellow", "green", "blue", "gray" };
private static LogLevel? logLevel;
private readonly VoiceAttackInitProxyClass vaProxy;
private readonly string id;
public VoiceAttackLog(VoiceAttackInitProxyClass vaProxy, string id)
{
this.vaProxy = vaProxy;
this.id = id;
}
public LogLevel? LogLevel
{
get => logLevel ?? Yavapf.LogLevel.NOTICE;
set
{
logLevel = value;
this.Notice($"Log level set to {value ?? Yavapf.LogLevel.NOTICE}.");
}
}
public void SetLogLevel(string level)
{
if (level == null)
{
this.LogLevel = null;
}
else
{
this.LogLevel = (LogLevel)Enum.Parse(typeof(LogLevel), level.ToUpper());
}
}
public void Log(string message, LogLevel level = Yavapf.LogLevel.INFO)
{
_ = message ?? throw new ArgumentNullException("message");
if (level <= this.LogLevel)
{
this.vaProxy.WriteToLog($"{level} | {this.id}: {message}", LogColour[(int)level]);
}
}
public void Error(string message) => this.Log(message, Yavapf.LogLevel.ERROR);
public void Warn(string message) => this.Log(message, Yavapf.LogLevel.WARN);
public void Notice(string message) => this.Log(message, Yavapf.LogLevel.NOTICE);
public void Info(string message) => this.Log(message, Yavapf.LogLevel.INFO);
public void Debug(string message) => this.Log(message, Yavapf.LogLevel.DEBUG);
}
/// <summary>
/// Log levels that can be used when writing to the VoiceAttack log.
/// </summary>
public enum LogLevel
{
/// <summary>
/// Log level for error messages. Errors cause execution to abort.
/// </summary>
ERROR,
/// <summary>
/// Log level for warning messages. Warnings should not cause execution
/// to abort.
/// </summary>
WARN,
/// <summary>
/// Log level for notices. Notices should be noteworthy.
/// </summary>
NOTICE,
/// <summary>
/// Log level for informational messages. These should not be
/// noteworthy.
/// </summary>
INFO,
/// <summary>
/// Log level for debug messages. They should be useful only for
/// debugging.
/// </summary>
DEBUG,
}
}

View file

@ -18,64 +18,228 @@
// </copyright>
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using VoiceAttack;
namespace alterNERDtive.Yavapf
{
public class VoiceAttackPlugin
{
public string Name { get; set; }
public VoiceAttackPlugin(string name, string version, string info, string guid)
=> (this.Name, this.Version, this.Info, this.Guid)
= (name, version, info, new (guid));
public string Version { get; set; }
// this just hides the default constructor to make sure Properties are set.
private VoiceAttackPlugin()
{
}
public string Info { get; set; }
public event Action<VoiceAttackInitProxyClass>? Init;
public string Guid { get; set; }
public event Action<VoiceAttackProxyClass>? Exit;
private dynamic? vaProxy;
public event Action? Stop;
public HandlerList<Action<VoiceAttackInvokeProxyClass>> Contexts { get; set; } = new ();
public VoiceAttackInitProxyClass Proxy
{
get => this.vaProxy;
}
public string Name { get; }
public string Version { get; }
public string Info { get; }
public Guid Guid { get; }
public VoiceAttackLog Log {
get => this.log ??= new VoiceAttackLog(this.vaProxy, this.Name);
}
private VoiceAttackLog log;
protected VoiceAttackInitProxyClass vaProxy;
public void Set<T>(string name, T? value)
{
switch (value)
{
case bool b:
this.vaProxy.SetBoolean(name, b);
break;
case DateTime d:
this.vaProxy.SetDate(name, d);
break;
case decimal d:
this.vaProxy.SetDecimal(name, d);
break;
case int i:
this.vaProxy.SetInt(name, i);
break;
case short s:
this.vaProxy.SetSmallInt(name, s);
break;
case string s:
this.vaProxy.SetText(name, s);
break;
default:
throw new InvalidDataException($"Cannot set variable '{name}': invalid type '{typeof(T).Name}'.");
}
}
public T? Get<T>(string name)
{
dynamic? ret = null;
switch (default(T))
{
case bool _:
ret = this.vaProxy.GetBoolean(name);
break;
case DateTime _:
ret = this.vaProxy.GetDate(name);
break;
case decimal _:
ret = this.vaProxy.GetDecimal(name);
break;
case int _:
ret = this.vaProxy.GetInt(name);
break;
case short _:
ret = this.vaProxy.GetSmallInt(name);
break;
case string _:
ret = this.vaProxy.GetText(name);
break;
default:
throw new InvalidDataException($"Cannot get variable '{name}': invalid type '{typeof(T).Name}'.");
}
return ret;
}
public string VA_DisplayName() => $"{this.Name} v{this.Version}";
public string VA_DisplayInfo() => this.Info;
public Guid VA_Id() => new (this.Guid);
public Guid VA_Id() => this.Guid;
public void VA_Init1(dynamic vaProxy)
public void VA_Init1(VoiceAttackInitProxyClass vaProxy)
{
this.vaProxy = vaProxy;
this.vaProxy.TextVariableChanged += new Action<string, string, string, Guid?>(this.TextVariableChanged);
this.vaProxy.IntegerVariableChanged += new Action<string, int?, int?, Guid?>(this.IntegerVariableChanged);
this.vaProxy.DecimalVariableChanged += new Action<string, decimal?, decimal?, Guid?>(this.DecimalVariableChanged);
this.vaProxy.BooleanVariableChanged += new Action<string, bool?, bool?, Guid?>(this.BooleanVariableChanged);
this.vaProxy.DateVariableChanged += new Action<string, DateTime?, DateTime?, Guid?>(this.DateVariableChanged);
this.Set<string>($"{this.Name}.version", this.Version);
this.Log.Debug($"Initializing v{this.Version} …");
this.vaProxy.TextVariableChanged += this.TextVariableChanged;
this.vaProxy.IntegerVariableChanged += this.IntegerVariableChanged;
this.vaProxy.DecimalVariableChanged += this.DecimalVariableChanged;
this.vaProxy.BooleanVariableChanged += this.BooleanVariableChanged;
this.vaProxy.DateVariableChanged += this.DateVariableChanged;
this.Log.Debug("Running Init handlers …");
this.Init?.Invoke(vaProxy);
this.Log.Debug("Finished running Init handlers.");
this.Set<bool>($"{this.Name}.initialized", true);
this.Log.Debug("Initialized.");
}
public void VA_Invoke1(dynamic vaProxy)
public void VA_Invoke1(VoiceAttackInvokeProxyClass vaProxy)
{
this.vaProxy = vaProxy;
string context = vaProxy.Context.ToLower();
try
{
bool exists = false;
foreach (Action<VoiceAttackInvokeProxyClass> action in Contexts)
{
foreach (ContextAttribute attr in action.Method.GetCustomAttributes<ContextAttribute>())
{
if (attr.Name == context)
{
exists = true;
action.Invoke(vaProxy);
}
}
}
if (!exists)
{
this.Log.Error($"Invalid plugin context '{vaProxy.Context}'.");
}
}
catch (ArgumentNullException e)
{
this.Log.Error($"Missing parameter '{e.ParamName}' for context '{context}'");
}
catch (Exception e)
{
this.Log.Error($"Unhandled exception while executing plugin context '{context}'. ({e.Message})");
}
}
public void VA_Exit1(dynamic vaProxy)
public void VA_Exit1(VoiceAttackProxyClass vaProxy)
{
this.vaProxy = vaProxy;
this.Exit?.Invoke(vaProxy);
}
public void VA_StopCommand()
{
this.Stop?.Invoke();
}
private void TextVariableChanged(string name, string from, string to, Guid? internalID = null)
{ }
{
}
private void IntegerVariableChanged(string name, int? from, int? to, Guid? internalID = null)
{ }
{
}
private void DecimalVariableChanged(string name, decimal? from, decimal? to, Guid? internalID = null)
{ }
protected void DecimalVariableChanged(string name, decimal? from, decimal? to, Guid? internalID = null)
{
}
private void BooleanVariableChanged(string name, bool? from, bool? to, Guid? internalID = null)
{ }
protected void BooleanVariableChanged(string name, bool? from, bool? to, Guid? internalID = null)
{
}
private void DateVariableChanged(string name, DateTime? from, DateTime? to, Guid? internalID = null)
{ }
protected void DateVariableChanged(string name, DateTime? from, DateTime? to, Guid? internalID = null)
{
}
public class HandlerList<T> : List<T>
{
public static HandlerList<T> operator +(HandlerList<T> handlers, T item)
{
handlers.Add(item);
return handlers;
}
public static HandlerList<T> operator -(HandlerList<T> handlers, T item)
{
handlers.Remove(item);
return handlers;
}
}
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class ContextAttribute : Attribute
{
public string Name { get; }
public ContextAttribute(string context)
{
this.Name = context;
}
}
}