|
| 1 | +**Important: Chat Overflow is still work in progress. So this guide will probably change in the future!** |
| 2 | + |
| 3 | +There are 3 important steps when you want to create and implement a new chat overflow plugin: |
| 4 | + |
| 5 | +1. Create a new plugin project with the commands of the framework |
| 6 | +2. Inspect the `plugin.xml` file |
| 7 | +3. Extend the plugin with own logic |
| 8 | + |
| 9 | +## Create a new plugin project |
| 10 | + |
| 11 | +Use the *Create Plugin* configuration or start the custom task `sbt create` directly. Enter the basic plugin information in the command prompt. This includes mandatory values like the name, author, version and base plugin folder (e.g. `plugins-public`) and some optional values like a description, a website, a link to a source repo, a link to a bug tracker and a license. |
| 12 | + |
| 13 | +The command creates the folder structure of the new plugin and adds a basic build file. Here you can also add custom dependencies. In addition the command generates a basic `plugin.xml` containing all the passed information like name and description and a basic source code file generated in the language of your choice to get you started. Note that currently only Scala and Java are supported. |
| 14 | + |
| 15 | +Next, run the custom task `sbt fetch` to let the framework look for new plugins and update the plugin reference file `plugins.sbt`. If you're using IntelliJ, you can now reload the framework by hand to register the plugin as new and custom project. You should also run `sbt reload` (Yes, both actions have different effects although they shouldn't). |
| 16 | + |
| 17 | +## Inspect the `plugin.xml` file |
| 18 | + |
| 19 | +All the metadata of the plugin like the name and the author of the plugin is saved in a xml file which is located at `src/main/resources/plugin.xml` in the plugin directory. This file gets autogenerated by the create command but in case you need to update a value its good to know where this file is located. |
| 20 | + |
| 21 | +A simple version of the `plugin.xml` file might look like this: |
| 22 | + |
| 23 | + ```xml |
| 24 | +<plugin> |
| 25 | + <name>Demonstration</name> |
| 26 | + <author>sebinside</author> |
| 27 | + <description>This is a simple plugin for demonstration purposes.</description> |
| 28 | + <api> |
| 29 | + <major>3</major> |
| 30 | + <minor>0</minor> |
| 31 | + </api> |
| 32 | + <version>0.3.0</version> |
| 33 | + <website>https://codeoverflow.org</website> |
| 34 | + <sourceRepo>https://github.com/codeoverflow-org/chatoverflow-plugins</sourceRepo> |
| 35 | + <bugtracker>https://github.com/codeoverflow-org/chatoverflow/issues</bugtracker> |
| 36 | + <license>EPL-2.0</license> |
| 37 | +</plugin> |
| 38 | + ``` |
| 39 | + |
| 40 | +The properties called name, author, api versions and version are mandatory and the framework won't load the plugin if one of these is missing. All others are optional informations for the user. If you don't want to specify a value for those you can just omit them. |
| 41 | + |
| 42 | +The api tag contains the API-Version, you developed the plugin with. These are evaluated in the loading process to ensure that your plugin works with the framework version from the user. You can get these numbers either from `org.codeoverflow.chatoverflow.api.APIVersion` in the api project or in the `build.sbt` also in the api project. |
| 43 | + |
| 44 | +## Extend the Plugin with own logic |
| 45 | + |
| 46 | +The last step is the creation of the plugin class, which contains your own plugin logic. Again the create command has autogenerated a basic class extending `org.codeoverflow.chatoverflow.api.plugin.PluginImpl` in the language of your choice. Such a file might look like this in case of Scala: |
| 47 | + |
| 48 | +```scala |
| 49 | +import org.codeoverflow.chatoverflow.api.plugin.{PluginImpl, PluginManager} |
| 50 | + |
| 51 | +class DemonstrationPlugin(manager: PluginManager) extends PluginImpl(manager) { |
| 52 | + |
| 53 | + // require more requirements as needed here |
| 54 | + private val sampleReq = require.input.sample("sampleReq", "Sample requirement", true) |
| 55 | + |
| 56 | + // you can adjust the loop interval here |
| 57 | + // loopInterval = 1000; |
| 58 | + |
| 59 | + /** |
| 60 | + * The setup method is executed one, when the plugin is started. Do NOT define your requirements in here! |
| 61 | + */ |
| 62 | + override def setup(): Unit = { |
| 63 | + log("Initialized Demonstration!") |
| 64 | + } |
| 65 | + |
| 66 | + /** |
| 67 | + * The loop method is executed in loop with a specified interval until the shutdown method is called. |
| 68 | + * The loop method is NOT executed if a negative loop interval is set. |
| 69 | + */ |
| 70 | + override def loop(): Unit = { |
| 71 | + log("Demonstration loop!") |
| 72 | + } |
| 73 | + |
| 74 | + /** |
| 75 | + * The shutdown method should contain logic to close everything. |
| 76 | + */ |
| 77 | + override def shutdown(): Unit = { |
| 78 | + log("Shutting down Demonstration!") |
| 79 | + } |
| 80 | +} |
| 81 | +``` |
| 82 | + |
| 83 | +The framework searches for a class implementing `org.codeoverflow.chatoverflow.api.plugin.Plugin` when it tries to load a plugin. `PluginImpl` does this for you and also decreases some other boilerplate. Note that the whole plugin is only allowed to have *exactly* one class implementing `Plugin` otherwise the framework won't load your plugin. |
| 84 | + |
| 85 | +All methods in the generated class are pretty self explaining. The only thing we might need to talk about are *requirements*: These are the way to retrieve data from the outside world and returning information to it. Basically, you can require everything from a single parameter, set by the user, to full access to a users livestream chat. |
| 86 | + |
| 87 | +Thanks to `PluginImpl` a requirements object is already created, meaning you can start adding requirements right away. Here is a example: |
| 88 | + |
| 89 | +```scala |
| 90 | +private val twitchChatInput = require.input.twitchChat("reqTwitch", "A twitch channel", false) |
| 91 | +private val nameToSayHelloTo = require.parameter.string("reqHello", "Your name", false) |
| 92 | +``` |
| 93 | + |
| 94 | +This code requires reading-access to a twitch livestream chat and a parameter ("*a name to say hello to"*). Note: You can obviously not specify, which channel the user might choose - but you can be sure, that you will get a working input. This is ensured by the framework. |
| 95 | + |
| 96 | +After this, the last step is the `start` method. And it is as easy as you might think: Just add your own logic now, using the required parameters of your Requirement object. Here is a short example: This code will simply print out all messages from a twitch chat in the console. To access the chat, your required variable is used with the `getValue` method. |
| 97 | + |
| 98 | +```scala |
| 99 | +twitchChatInput.getValue.registerMessageHandler(msg => println(msg)) |
| 100 | +``` |
| 101 | + |
| 102 | +Of course, you can also add own classes and infrastructure by now - the important steps are done, happy coding! |
| 103 | + |
| 104 | +*One last note: If your testing your plugin the first time, a full reload might be needed. Use the custom task `[Advanced] Full Reload and run ChatOverlfow` to do so. Afters this, you can configure the framework to start your plugin using the [CLI](Using-the-CLI)!* |
0 commit comments