Skip to content

Plugins

Bluscream edited this page Oct 14, 2017 · 15 revisions

Getting started

To get started create a folder like Plugins and set the PluginManager::PluginPath setting accordingly.

Avaiable Hooks

There are two different kinds of classes you can extend the bot with:

  • ITabPlugin The universal extention tool for commands and new functionality
  • IFactory A provider to resolve links for the commands !play and !playlist

Storing Plugins

There are two ways to add your plugin to the bot.

  1. For quick and dirty testing you can simply add a *.cs file into the plugin folder and the bot will automatically compile it for you when requested. Note that the itegrated compiler only supports the C# language specification up to 4.0!
  2. The usual way is to place any .NET *.dll or *.exe (will be treated like a library) into the plugins folder. Note: If you want your new plugin to autoload, just create a new file YourPluginName.Extension.status and add a 1 as it's content.

Listing plugins

To list all your plugins simply send !plugin list to the bot.

#0|OFF|MyFile1.cs
#1|RDY|Plugin: MyPlugin2
#2|+ON|Factory: youtube
#3|UNL|Plugin: <unknown>
#4|ERR|MyFile2.cs 

There are different states a plugin can be in

  • OFF A file has been found but not yet checked
  • RDY The file was loaded without error and can be enabled
  • +ON The plugin (or factory) was successfully enabled and is now integrated into the bot
  • UNL The plugin was manually disabled and will not be loaded
  • ERR Threr was an error loading the file (See in the console/log for detailed information)

Each id is unique and will be kept for a file even if the file gets changed or reloaded. When a file gets deleted or renamed the id will be freed (and a new one associated).

You can load and unload your plugins with !plugin load <plugin> and !plugin unload <plugin>. Both can take for the <plugin> parameter either the currently assigned id or the complete file name.

Command Plugins

To start with a simple plugin create an empty file and call it MyPlugin.cs
This is the mimimalistic base structure:

using TS3AudioBot;
using TS3AudioBot.CommandSystem;
using TS3AudioBot.Plugins;

namespace MyNamespace
{
    public class MyPlugin : ITabPlugin
    {
        MainBot mainBot;

        public void Initialize(MainBot bot)
	{
	    mainBot = bot;
        }

        public void Dispose()
        {

        }

        // Commands etc...
    }
}

Initialize

The Initialize method gets called when your plugin gets stated (!plugin load). This is the only time when you get a MainBot reference to the bot instance that is loading your plugin.
In a command call you will get the MainBot instance that received the command. This will usually be the same instance but it can differ.

Dispose

When you allocate external resources, other IDisposable objects or make other changes to the bot, make sure to deallocate, dispose and undo all those changes in this method.

Commands

To create a new command which can be called from the commandsystem with !..., simply create a method and add the CommandAttribute to it.
For example:

[Command("greet", "Does some cool things!")]
public string CommandApiToken(string name, int number)
{
    return "Hi " + name + ", you choose " + number;
}

Attributes

You can add the following attributes to a command (All attributes described here are in the TS3AudioBot.CommandSystem namespace):

  • CommandAttribute This attribute is required to mark a function as a bot command. It has two parameter:
    1. The first one specifies the command path which must be lower case letters and spaces only. This path must be unique together with the parameter types of the function.
    2. The second parameter is optional and may provide a short help text to the user when called with !help <your> <command>
  • UsageAttribute Add this when a commands get more complicated and you want to give more detailed help to one or more specific use cases of your command.
    This command can be added multiple times for multiple examples. It has two parameter:
    1. The first one lists your parameter names
    2. The second one should explain it.
  • RequiredParametersAttribute By default when calling a bot command the commandsystem will require a value for each parameter in your function (in the above example string name and int number, so the command must be called !greet Tom 42). When less values are given the command will not execute. This attribute allows you to specify the minimal amount of values this command needs. All parameter beyond the specified amount will be considered optional.

Input

The commandsystem will automatically serialize and deserialize all primitve types (bool, byte, string, ...), their nullable variant (bool?, byte?, ...), and enums when passing values to your function.

To get more information from a botcommand call you can add a ExecutionInformation info parameter to your function. This special command does not count towards the command parameter list and can always be obtained. This objects holds many useful information about the current call:

  • TextMessage the origninal complete textmessage that initiated this call
  • InvokerData all information which are known about the sender of this textmessage. Note that many properties are declared as nullable and many strings also might be null.
  • Session the session is a useful object to annotate certain informatin to a user
  • SkipRightsChecks use this to disable all further rights checks in this call. Note to use this with caution as this may be a dangerous security hole.
  • Bot the MainBot instance that received/initiated this command call. If you want to access related structures use this instance instead of the one given with Initialize.

Output

A function can return void, string or JsonObject.

  • void Nothing will be returned.
  • string A string or null for a void equivalent can be returned to the user or a calling parent funtion.
  • JsonObject This is the preferred variant for best compatibility with the chat and api. The commandsystem can decide whether the caller wants the readable string for the chat or a json-serialized object for the api.
    • JsonEmpty is the void equivalent.
    • JsonSingleValue will generate { "Value" : "yourValue" }, use preferedly for primitve types which have no structure.
    • JsonSingleObject will generate { ... }, use this if you want to serialize an entire object.
    • JsonArray can be used for an array of values or objects
    • JsonError should not be used. The commandsystem will generate this type for you when you throw a CommandException.

Teamspeak Functions and Events

High Level

Some functions and events of TS3Client library already got wrapped for easy access and use. You can view them with your mainbot's .QueryConnection attribute. Example:

using System;
using TS3AudioBot;
using TS3AudioBot.Plugins;
using TS3Client;
using TS3Client.Commands;
using TS3Client.Full;

namespace Example
{
    public class Example : ITabPlugin {
        private MainBot bot;
        public void Initialize(MainBot mainBot)
        {
            bot = mainBot;
            bot.QueryConnection.OnClientConnect += QueryConnection_OnClientConnect;
        }
        private void QueryConnection_OnClientConnect(object sender, TS3Client.Messages.ClientEnterView e) {
            bot.QueryConnection.SendMessage("Hello, you just connected to this server", e.InvokerId);
        }
        public void Dispose() {
            bot.QueryConnection.OnClientConnect -= QueryConnection_OnClientConnect;
        }
    }
}

Low Level

The more low-level functions and events are only available by using "mainBot.QueryConnection.GetLowLibrary();" Example:

using System;
using TS3AudioBot;
using TS3AudioBot.Plugins;
using TS3Client;
using TS3Client.Commands;
using TS3Client.Full;

namespace Example
{
    public class Example : ITabPlugin {
        private MainBot bot;
        private Ts3FullClient lib;
        public void Initialize(MainBot mainBot)
        {
            bot = mainBot;
            lib = bot.QueryConnection.GetLowLibrary<Ts3FullClient>();
            lib.OnClientMoved += Lib_OnClientMoved;
        }
        private void Lib_OnClientMoved(object sender, System.Collections.Generic.IEnumerable<TS3Client.Messages.ClientMoved> e) {
            foreach (var client in e)
            {
                lib.SendPrivateMessage("Hello, you just moved to another channel", client.ClientId);
		try { lib.Send("clientpoke", new CommandParameter("clid", client.ClientId), new CommandParameter("msg", "Oh,\\sno\\swhat\\sare\\syou\\sdoing?"));
		} catch (Exception ex) { Log.Write(Log.Level.Warning, string.Format("Exception thrown while trying to poke client #{0}: {1}", client.ClientId, ex.Message)); }
	    }
        }
        public void Dispose() {
            lib.OnClientMoved -= Lib_OnClientMoved;
        }
    }
}

Resource Factories

[TODO]

General

IResourceFactory

IPlaylistFactory

IThumbnailFactory

Technical stuff

Due to technical limitations each time you load/unload a plugin, a new assembly will be loaded into the application. This means should you notice a high memory uasage after a plugin developing session you will need to restart the bot to get to normal memory usage again.