-
-
Notifications
You must be signed in to change notification settings - Fork 16
Plugin Development
Plugins are an alternative to script packages for extending Alkahest. A plugin is a compiled .NET assembly. There are pros and cons to using plugins instead of scripting.
Pros:
- You can use any .NET programming language (C#, F#, etc).
- Compilation is done ahead of time, making startup time faster.
- Compiler diagnostics are available before running Alkahest.
- You have full control over compiler options.
- Arbitrary third-party .NET assemblies can be referenced (e.g. via NuGet).
- Native compilation (e.g.
Ngen.exe
) is a possibility.
Cons:
- The Alkahest package registry does not support distribution of plugins.
- Users will not be able to easily see or modify the source code.
- Sharing code between plugins is more difficult than with scripting.
In general, it is recommended to use scripting wherever possible.
This is a quick guide to getting started with plugin development in C#, using an example plugin called example
.
- GitHub repository name:
alkahest-example
- Project name and namespace:
Alkahest.Plugins.Example
- Assembly name:
alkahest-example.dll
- Plugin class name:
ExamplePlugin
-
Alkahest.Core.Plugins.IPlugin.Name
property:"example"
- Create a C# class library project targeting .NET Framework 4.7.2 called
Alkahest.Plugins.Example
. - Go to the project's properties and set the assembly name to
alkahest-example
. - Add a reference to the
Alkahest.Core
NuGet package. - Create an
ExamplePlugin.cs
file in your project.
Your ExamplePlugin.cs
file should look like this:
using Alkahest.Core.Logging;
using Alkahest.Core.Plugins;
namespace Alkahest.Plugins.Example
{
public sealed class ExamplePlugin : IPlugin
{
public string Name => "example";
static readonly Log _log = new Log(typeof(ExamplePlugin));
readonly PluginContext _context;
ExamplePlugin(PluginContext context)
{
_context = context;
}
public void Start()
{
_log.Basic("Example plugin started");
}
public void Stop()
{
_log.Basic("Example plugin stopped");
}
}
}
You do not need to register your plugin class anywhere; simply implementing Alkahest.Core.Plugins.IPlugin
and adding a constructor taking an Alkahest.Core.Plugins.PluginContext
parameter is enough for Alkahest to find and instantiate your plugin class. The context
parameter provides functionality such as packet handling, data center access, and a list of server proxy (Alkahest.Core.Net.Game.GameProxy
) objects, each corresponding to an official server. For example, on EU, you would get 4 objects - one for each of Killian, Mystel, Seren, and Yurian.
Start
is invoked when the proxy server is starting. This is where a plugin should do its startup work; do not perform significant work in the constructor as a plugin will be instantiated even if it is disabled.
Stop
is invoked when the proxy server is stopping. Here, a plugin should clean up any resources it acquired in Start
.
The _log
field is used for logging rather than sending messages directly to the console or a file. These objects should be instantiated on a per-class basis, not per-object, and so should be private static readonly
.
After compiling the plugin, copy alkahest-example.dll
into the Plugins
sub-directory in your Alkahest directory. Start Alkahest and your plugin should be loaded.
Unlike in script packages, exceptions that occur during startup/shutdown of a plugin will not be caught by Alkahest; instead, they will cause the whole proxy server to terminate. This is intentional: Plugins are held to a higher standard of correctness than script packages. Exceptions that occur in packet handlers are treated the same as in script packages, however.
To debug a plugin, simply attach a debugger (e.g. Visual Studio) to the Alkahest process. When Alkahest detects the presence of a debugger, it will let all exceptions bubble up so the debugger can catch them and suspend the process. You can also set breakpoints in your plugin's code, or insert explicit calls to System.Diagnostics.Debugger.Break()
, in order to break into the debugger.