Skip to content

Plugins

C272 edited this page Aug 19, 2019 · 5 revisions

If you find a piece of functionality is lacking from Algo, you can create a C# plugin to add that functionality to the language! This article will give a quick tutorial as to how.

Setup

First, you will need to create a new .NET Framework 4.x Class Library, from template if possible.

Templates

After that, download the Algo SDK, and load it in Visual Studio. You can download it from the Releases tab, or grab it from your root Algo directory, then simply add a reference to it in Visual Studio.

Reference image.

Now, create a new class, such as the one outlined below, for your plugin.

using System;
using AlgoSDK;

namespace YourNamespaceHere
{
    public class AwesomeAlgoPlugin : IFunctionPlugin
    {

    }
}

Implementation

Next, implement the required methods and properties outlined in IFunctionPlugin (Visual Studio should have an option for this with the CTRL + . shortcut, but if not, there is an example below).

public class AwesomeAlgoPlugin : IFunctionPlugin
{
    public string Name { get; set; } = "awesomeAlgoPlugin";
    public List<AlgoPluginFunction> Functions { get; set; } = new List<AlgoPluginFunction>()
    {

    }
}

Now you can get round to implementing your custom functionality! To create a runnable function in Algo, your functions must all adhere to the AlgoFunctionDelegate delegate, which is outlined below in case you can't see in VS.

public static AlgoValue SomeCustomFunctionality(ParserRuleContext context, params AlgoValue[] args)
{
    ...
}

Here are some key tips for writing clean Algo functions:

  • If you want to return nothing from a function, use return null. AlgoValue.Null is an actual null Algo value, whereas null is returning nothing.
  • You can check the types of your arguments by using args[i].Type == AlgoValueType.x.
  • Use Error.Fatal to throw errors instead of Error.FatalNoContext, it helps the user trace the error. You can pass in the ParserRuleContext provided in the arguments of the function.

Now that your function is written, go back up to your property definition for Functions, and add a new AlgoPluginFunction instance, customized to your needs. Here's an example:

public List<AlgoPluginFunction> Functions { get; set; } = new List<AlgoPluginFunction>()
{
    //input.get();
    new AlgoPluginFunction()
    {
        Name = "input_get",
        Function = GetConsoleInput,
        ParameterCount = 0
    }
}

Loading

Now that your custom functionality is complete, you just have to load your function into Algo itself. Build your class library, and place the .dll file that is generated inside a new folder in /algo/packages. For example, if my plugin was called "CustomFuncPlug", I'd place my .dll inside /algo/packages/customFuncPlug. This isn't important, but helps organise your different plugins.

Now that your DLL is placed into packages, create a new Algo file in the root packages directory. In my example, I'd call it "customFuncPlug.ag". Inside it, you can then create a library for your plugin, and load in your custom functions. Here's an example of how that looks:

//customFuncPlug.ag
//(c) Larry T, 2019

library customFuncPlug
{
    external myFunc <- awesomeAlgoPlugin.input_get;
}

To break it down:

  • The "library" statement wrapped around it creates a separate namespace for it, such as input.get() rather than get().
  • The "external" signals that it's a plugin function that needs to be loaded.
  • The awesomeAlgoPlugin.input_get is derived like so: name.func. So, if the "Name" property in your plugin is set to "foo", and you had a function called "bar", it would be "foo.bar".
  • You can load as many external functions as you need.

Runtime

You've successfully created a plugin for Algo! Now, to run it, simply use import "myPluginName" in a script, and you can use whatever functions you've defined (in my case, customFuncPlug.myFunc()).