Skip to content

Creating a plugin

JR edited this page Mar 3, 2023 · 21 revisions

Completely understanding plugins still requires reading the source. Still, writing a basic plugin is very easy and only requires some small knowledge of how IRC events are handled. Refer to the page on IRCEvent[1] for more information on the kind of event struct you will be dealing with.

API documentation can be found here and here.

Basic plugin template

A simple starter skeletal plugin would look like the following.

module kameloso.plugins.myplugin;

private:

import kameloso.plugins.common;
import dialect.defs;

// Implementation goes here, doesn't have to be public

public:

final class MyPlugin : IRCPlugin
{
    mixin IRCPluginImpl;
}

mixin ModuleRegistration!MyPlugin;

This is enough. Everything else is the implementation of your plugin. Only the actual plugin class has to be public.

To get it to actually do something, create some functions and annotate them with the user-defined attribute (UDA[2]) type member of enum IRCEvent.Type you want them to trigger upon. It is as simple as adding a @(IRCEvent.Type.SOMETYPE) to your function signature. These should be placed at the top module level, and not as methods to your class.

@(IRCEventHandler()
    .onEvent(IRCEvent.Type.QUERY)
)
void onQuery(MyPlugin plugin, const ref IRCEvent event)
{
    writeln("I received a QUERY!");
    writeln("It was from: ", event.sender.nickname);
    writeln("The contents were: ", event.content);
}

Compiled and restarted, the event handler we mixed into your IRCPlugin will now automatically dispatch any incoming QUERY events to your new function. You can have several type annotations on the same function to have them trigger on several different events. You can also share type annotations with other functions in your plugin module; they will be executed in the order of their definitions, assuming you also add the UDA @Chainable to them. Else it will stop after executing the first matching function.

There are a few more kinds of annotations available. Please see the wiki page on more advanced plugins.

Awareness

The bot provides the opt-in options of keeping automatic bookkeeping on users, and on channels. This means that it can keep track of which users it has seen and their details, and optionally also information about the channels you're in, including participants. Both are opt-in.

They are essentially aggregates of common IRCEvent-annotated event handlers, like those described above. With UserAwareness, when someone JOINs a channel it stores their IRCUser, and removes it when they QUIT. It updates their entry in the user storage when they change their NICK, and other forms of bookkeeping. The same goes for channels if we opt-in for ChannelAwareness; when we join a channel it creates an entry in its internal list of channels, and after a while it queries it for its current participants, its TOPIC and its MODEs. When someone JOINs, it adds them to the channel's list of users, and removes them when they PART or QUIT.

If you don't need them there's little point in mixing them in, but if you plan to write your plugin in a way where being aware of users and/or channels, it can provide that for you, so you don't have to write it yourself.

mixin UserAwareness;
mixin ChannelAwareness;  // requires UserAwareness

Getting it up and running

You simply need to...

  1. add the plugin module to the compilation process. Assuming use of dub to build the project, it should be enough to simply drop your source file into the source/plugins directory.
  2. get the plugin instantiated on program startup/connect. This merely requires mixing in the ModuleRegistration mixin from kameloso.plugins.common.core, at the module-level.

Save, compile and test!