193 lines
8.1 KiB
Markdown
193 lines
8.1 KiB
Markdown
# Getting Started
|
||
|
||
First off, you can see [the Example plugin
|
||
project](https://github.com/alterNERDtive/YAVAPF/tree/release/ExamplePlugin) on
|
||
Github for reference.
|
||
|
||
Second off, this documentation assumes that you have at least cross read the
|
||
section about plugins [in the VoiceAttack
|
||
manual](https://voiceattack.com/VoiceAttackHelp.pdf). If any terminology is new
|
||
to you, it is probably introduced there. Unlike said manual though this will
|
||
provide step by step instructions to get your plugin set up.
|
||
|
||
## Creating a Visual Studio Project
|
||
|
||
I am going to assume for this part of the documentation that you are using
|
||
Visual Studio 2022 or later (_not_ Visual Studio Code!) as your development
|
||
environment. [The Community Edition is free for unlimited time personal
|
||
use](https://visualstudio.microsoft.com/vs/compare/).
|
||
|
||
VoiceAttack is a .Net Framework 4.8 application. Plugins targeting .Net 5+ or
|
||
.Net Core will not work. I still recommend creating a .Net project instead of a
|
||
.Net Framework project, then changing the “Target Framework” to .Net Framework
|
||
4.8. This allows you to use the full `dotnet` tool chain, which makes e.g. using
|
||
Github Actions to build / release your project much less painful. Trust me, I’ve
|
||
done it both ways.
|
||
|
||
So, create a new “Class Library” project, then use a text editor to change the
|
||
“TargetFrameworks” property to `net48`. While you’re there you might also want
|
||
to change the “LanguageVerison” to `10`. Most new features are backwards
|
||
compatible with .Net Framework. The compiler will assist you with errors for
|
||
those that are not.
|
||
|
||
## Adding YAVAPF as a Dependency
|
||
|
||
This one is the simple part, just install `alterNERDtive.YAVAPF` through NuGet.
|
||
Done.
|
||
|
||
Alternatively you can add it manually by cloning
|
||
`github.com/alterNERDtive/YAVAPF.git` as a git submodule and referencing
|
||
`VoiceAttack-Framework\VoiceAttack-Framework.csproj` as a project reference.
|
||
|
||
But seriously, use NuGet. I haven’t taught myself how to release NuGet packages
|
||
just for you to ignore it!
|
||
|
||
## Adding VoiceAttack as a Dependency
|
||
|
||
This is a little more involved. In order to use the actual proxy classes from
|
||
VoiceAttack instead of the “official” crutch of `dynamic` types, you will need
|
||
to add an assembly reference to `VoiceAttack.exe`.
|
||
|
||
Right click → “Add” → “Assembly Reference…” → “Browse” → browse to the
|
||
VoiceAttack installation folder → select `VoiceAttack.exe` → hit “Add” → make
|
||
sure it is ticked in the list → hit “OK”.
|
||
|
||
Now, we want to _reference_ `VoiceAttack.exe`, but we don’t want to _include_ it
|
||
when compiling the plugin. So select “VoiceAttack” in “Dependencies” →
|
||
“Assemblies” and make sure that both “Copy Local” and “Embed Interop Types” are
|
||
set to “No”.
|
||
|
||
Distributing `VoiceAttack.exe` with your plugin would technically be a copyright
|
||
violation. _Do_ make sure to take the steps outlined in the last paragraph to
|
||
prevent accidentally doing that! Using it as a reference assembly is generally
|
||
OK and I have received confirmation from Gary, the author of VoiceAttack.
|
||
|
||
## Setting Up Debugging Through VoiceAttack
|
||
|
||
In order to be able to run VoiceAttack when debugging and actually debug your
|
||
plugin, you will need to open “Debug” → “<your project\> Debug Properties”.
|
||
|
||
There you will need to “Create a new profile” → “Executable”. Set the path to
|
||
your VoiceAttack executable and any command line options you might prefer.
|
||
Personally I like to set a custom `-datadir` in order to not mess with my
|
||
regular profile database accidentally.
|
||
|
||
The example plugin project has a `Properties\launchSettings.sample.json` file
|
||
that you can copy to `Properties\launchSettings.json` and edit accordingly to
|
||
accomplish the same thing.
|
||
|
||
The last thing you’ll need to do is make your plugin available to VoiceAttack
|
||
in a place where it can find it. I have requested an equivalent `-appdir`
|
||
parameter, but as long as that is not available you will need to have your
|
||
plugin present inside the regular `Apps` folder of VoiceAttack. I recommend
|
||
creating a directory junction (`mklink /j`, or `New-Item -ItemType Junction` in
|
||
PowerShell) between an `Apps` subfolder and your project’s debug output
|
||
directory (usually `<project name>\bin\Debug\net48` inside your solution
|
||
folder).
|
||
|
||
## Building Through Github Actions
|
||
|
||
If you, like me, want to automate building/testing/releasing through [Github
|
||
Actions](https://docs.github.com/en/actions), you’ll need to have VoiceAttack
|
||
available while building on the worker. Obviously that will only work on a
|
||
Windows worker.
|
||
|
||
I have created the
|
||
[`alterNERDtive/setup-voiceattack-action`](https://github.com/alterNERDtive/setup-voiceattack-action)
|
||
to facilitate that. Usage example:
|
||
|
||
```yaml
|
||
- name: Install VoiceAttack
|
||
uses: alterNERDtive/setup-voiceattack-action
|
||
with:
|
||
version: "1.10"
|
||
```
|
||
|
||
Make sure that the path to VoiceAttack on your machine (which is the path
|
||
referenced in the project file) matches the path where you install VoiceAttack
|
||
on the worker! Alternatively, if you have installed VoiceAttack in a custom
|
||
folder locally, you can create a symlink (`mklink`, or
|
||
`New-Item -ItemType SymbolicLink` in PowerShell) to your `VoiceAttack.exe`
|
||
location at `C:\Program Files\VoiceAttack\VoiceAttack.exe` and include that as
|
||
the assembly reference.
|
||
|
||
## Creating a Minimum Viable Plugin
|
||
|
||
A valid VoiceAttack plugin must implement a selection of public, static methods:
|
||
|
||
* `VA_DisplayName()`: Must return the name of the plugin.
|
||
* `VA_DisplayInfo()`: Must return the description of the plugin.
|
||
* `VA_Id()`: Must return the GUID of the plugin.
|
||
* `VA_Init1(dynamic)`: Is executed when the plugin is loaded into VoiceAttack.
|
||
* `VA_Invoke1(dynamic)`: Is executed whenever a plugin context is run from a
|
||
command.
|
||
* `VA_Exit1(dynamic)`: Is executed when VoiceAttack shuts down.
|
||
* `VA_StopCommand()`: Is executed when VoiceAttack stops all commands, e.g.
|
||
through the command action or main interface button.
|
||
|
||
When using YAVAPF these methods are to be passed straight to the corresponding
|
||
methods of a `VoiceAttackPlugin` object that handles most things for you. It has
|
||
a few required properties:
|
||
|
||
* `Name`: The name of the plugin.
|
||
* `Version`: The version of the plugin.
|
||
* `Info`: The description of the plugin.
|
||
* `Guid`: The GUID of the plugin.
|
||
|
||
All of those are `string`s for ease of use, though the `Guid` obviously has to
|
||
be a valid string representation of a GUID. You can generate one using “Tools” →
|
||
“Create GUID”. Make sure to select “Registry Format”.
|
||
|
||
For a YAVAPF plugin you will have to derive your plugin class from
|
||
`alterNERDtive.Yavapf.VoiceAttackPlugin`. Since VoiceAttack’s plugin API relies
|
||
entirely on static methods, you’ll need to instantiate your plugin object in its
|
||
static constructor and hold it in a static variable for future reference (no pun
|
||
intended).
|
||
|
||
So a minimum viable plugin using YAVAPF looks kind of like this:
|
||
|
||
```csharp
|
||
using System;
|
||
|
||
using alterNERDtive.Yavapf;
|
||
|
||
namespace YourNamespace
|
||
{
|
||
public class YourPlugin : VoiceAttackPlugin
|
||
{
|
||
private static readonly YourPlugin Plugin;
|
||
|
||
static YourPlugin()
|
||
{
|
||
Plugin = new ()
|
||
{
|
||
Name = "Your Plugin",
|
||
Version = "0.0.1",
|
||
Info = "This is a description",
|
||
Guid = "{5E93F293-B2CB-4B3F-AFC5-AE500A7EEBA9}",
|
||
};
|
||
}
|
||
|
||
public static string VA_DisplayName() => Plugin.VaDisplayName();
|
||
|
||
public static string VA_DisplayInfo() => Plugin.VaDisplayInfo();
|
||
|
||
public static Guid VA_Id() => Plugin.VaId();
|
||
|
||
public static void VA_Init1(dynamic vaProxy) => Plugin.VaInit1(vaProxy);
|
||
|
||
public static void VA_Invoke1(dynamic vaProxy) => Plugin.VaInvoke1(vaProxy);
|
||
|
||
public static void VA_Exit1(dynamic vaProxy) => Plugin.VaExit1(vaProxy);
|
||
|
||
public static void VA_StopCommand() => Plugin.VaStopCommand();
|
||
}
|
||
}
|
||
```
|
||
|
||
That’s it! Technically you’re done. Hit the debug button, and VoiceAttack should
|
||
find your plugin on startup, report loading it in the event log, and list it
|
||
under “Options” → “General” → “Plugin Manager”.
|
||
|
||
Of course you are only just getting started if you want your plugin to actually
|
||
_do_ something!
|