Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 23 additions & 114 deletions docs/development/creating-a-first-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,116 +6,13 @@ sidebar_label: Creating Your First Plugin

## Prerequisites

1. Follow the ["API Getting Started" guide](/docs/api/api-getting-started) and
install the API into your classpath.
2. An understanding of the Java programming language is necessary.
1. An understanding of the Java programming language is necessary.
2. Follow the [Getting Started guide](getting-started.md) to set up the project in your Java IDE (like IntelliJ IDEA or Eclipse).
3. A test plugin has been created in the GoMint repository and can be browsed [here](https://github.com/gomint/GoMint/tree/master/gomint-test-plugin/src/main/java/io/gomint/testplugin) for another example of what we will be creating.

### pom.xml Setup

Before you begin writing a plugin, you will need a ```pom.xml``` for the plugin. It is pertinent that this file be included.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<!-- Here is where you will substitute your plugin's information -->
<groupId>io.gomint.testplugin</groupId>
<artifactId>gomint-testplugin</artifactId>
<version>1.0-SNAPSHOT</version>

<!-- Here is where you will substitute your plugin's name and description -->
<name>GoMint Test Plugin</name>
<description>A plugin to test and see GoMint's API design</description>

<dependencies>
<!-- This is the GoMint API Maven Library which is necessary to create a plugin -->
<dependency>
<groupId>io.gomint</groupId>
<artifactId>gomint-api</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<resources>
<resource>
<directory>${pom.basedir}/src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>*.*</include>
</includes>
</resource>
</resources>

<!-- Needed for GoMint to load plugin external dependencies -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<id>copy-dependencies-netty-codecs</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeArtifactIds>netty-codec-http,netty-codec-http2,netty-handler-proxy</includeArtifactIds>
<outputDirectory>${project.build.directory}/classes/dependency</outputDirectory>
</configuration>
</execution>
<execution>
<id>copy-dependencies-discord</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<excludeScope>provided</excludeScope>
<excludeGroupIds>io.netty</excludeGroupIds>
<outputDirectory>${project.build.directory}/classes/dependency</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

<!-- Include the snapshot repository we are currently on for latest master builds -->
<repositories>
<repository>
<id>central</id>
<url>https://repo1.maven.org/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
</project>
```

## Step One - The ```Plugin``` Type

All plugins for the GoMint server contain a class extending ```io.gomint.plugin.Plugin```
All plugins for the GoMint server contain a class extending [```io.gomint.plugin.Plugin```](https://janmm14.de/static/gomint/index.html?gomint.api/io/gomint/plugin/Plugin.html)
where the initialization and cleanup of the plugin will take place, as well as the
registration of event handlers, new logic, etc. In lieu of a ```main()``` method, the plugin management system handles the initialization of plugins, so it is important that the annotations and types are setup correctly.

Expand All @@ -125,7 +22,7 @@ package me.plugincrafter.demo;
import io.gomint.plugin.Plugin;

// The class MUST extend Plugin. It is common for new users to write
// 'JavaPlugin', as they are coming from Bukkit/Spigot.
// 'JavaPlugin', as they are coming from Bukkit/Spigot, but here it is just 'Plugin'.
public class TestPlugin extends Plugin {}
```

Expand All @@ -135,11 +32,11 @@ Rather than use a configuration file that is packed into the JAR file to describ

Annotations:

| Annotation | Type | Value | See Also |
|------------|-----------------|---------------------------|---------------------------------------------------------------------------------------|
| PluginName | String | Your plugin's name | |
| Version | int, int | ```major```, ```minor``` | |
| Startup | StartupPriority | See Enums | [JavaDoc](https://janmm14.de/static/gomint/index.html?gomint.api/module-summary.html) |
| Annotation | Type | Value |
|------------|-----------------|---------------------------------------------------------------------------------------------------------------------|
| PluginName | String | Your plugin's name |
| Version | int, int | ```major```, ```minor``` |
| Startup | StartupPriority | See Enum in [JavaDoc](https://janmm14.de/static/gomint/index.html?gomint.api/io/gomint/plugin/StartupPriority.html) |

```java
package me.plugincrafter.demo;
Expand All @@ -156,17 +53,29 @@ import io.gomint.plugin.Version;
public class TestPlugin extends Plugin {}
```

## Step Three - GoMint API philosophies and differences to other server software

GoMint is one of the first Minecraft server softwares which have built in world multithreading - each world has its own main thread.
This means that many actions to worlds and entites need to run in the world's thread.

Additionally GoMint provides an easy-to-use API for plugins to [restrict plugins to certain worlds](../get-started/plugin-world-restriction.md), which **every** plugin should obey to.

## ```Plugin``` Available Methods

The following methods are inherited from ```Plugin``` and can be used to install event handlers, listeners, and setup your plugin:
The following methods are inherited from [```Plugin```](https://janmm14.de/static/gomint/index.html?gomint.api/io/gomint/plugin/Plugin.html) and can be used to install event handlers, listeners, and setup your plugin:

* ```onInstall()``` - Invoked when the plugin enters the runtime stage.
* ```onStartup()``` - Invoked when the plugin has been installed.
* ```onUninstall()``` - Invoked when the plugin has been uninstalled.
* ```isInstalled()``` - Can be invoked to determine if the plugin has been installed yet.
* ```registerCommand(io.gomint.command.Command)``` - Invoke to register your own commands.
* ```registerListener(io.gomint.event.EventListener)``` - Invoke to register your own event listeners.
* ```registerActiveWorldsListener(io.gomint.event.EventListener)``` - Invoke to register your own event listeners, limited to the [worlds your plugin should be active in](../get-started/plugin-world-restriction.md).
* ```registerListener(io.gomint.event.EventListener)``` - Invoke to register your own global event listeners.
* ```registerListener(io.gomint.event.EventListener, Predicate<Event>)``` - Invoke to register your own custom-limited event listeners.
* ```unregisterListener(io.gomint.event.EventListener)``` - Invoke to remove an event listener.
* ```activeInWorld(io.gomint.world.World)``` - Returns whether the plugin should be active in the given world.
* ```eventInActiveWorlds(io.gomint.event.Event)``` - Returns whether the plugin should be active in the given world.
* ```activeWorldsSnapshot()``` - Returns a set of currently loaded worlds where the plugin should be active in. Do **not** save it for later use.
* ```dataFolder()``` - Returns the data folder for this plugin as a File object.
* ```pluginManager()``` - Returns the plugin manager of the GoMint server.
* ```name() ``` - Returns the name of this plugin.
Expand Down
81 changes: 81 additions & 0 deletions docs/development/creating-your-first-event-listener.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
id: creating-your-first-event-listener
title: Creating Your First Event Listener
sidebar_label: Creating Your First Event Listener
---

## Prerequisites

This guide assumes that you have a [plugin environment](creating-a-first-plugin.md) setup.
If you have not already, follow that guide first.

## Event Concept

Many actions done by players, blocks or mobs trigger an event. Technically: a class extending `Event`. Events allow you to know, edit or cancel default behaviour.
For your plugin to get informed when an event happens, you need to create a class implementing `EventListener` (a marker interface):

```java
public class MyFirstEventListener implements EventListener {}
```

Now we marked the class for us and the api as event listener. Then we have to register our class to the API. We do that for example in the `onInstall` method in our `TestPlugin` class. Note that we use the method [`registerActiveWorldsListener`](https://janmm14.de/static/gomint/gomint.api/io/gomint/plugin/Plugin.html#registerActiveWorldsListener(io.gomint.event.EventListener)) which automatically filters events so we only get events taking place in any of the [plugin's active worlds](../get-started/plugin-world-restriction.md).

```java
@Override
public void onInstall() {
registerActiveWorldsListener(new MyFirstEventListener());
}
```
Next up we need to define which event(s) we want to listen to in this event listener.
This is done simply by creating a method annotated with `@EventHandler` which takes one argument (the event we want to listen to) and returns `void`:

Comment thread
Janmm14 marked this conversation as resolved.
```java
public class MyFirstEventListener implements EventListener {
@EventHandler
public void onExplode(EntityExplodeEvent event) {
// this method gets called every time an entity explodes
}
}
```

Now we just need to implement some logic. We can praise explosions for example with a chat message sent to every player:


```java
public class MyFirstEventListener implements EventListener {
@EventHandler
public void onExplode(EntityExplodeEvent event) {
GoMint.instance().onlinePlayers().forEach(p -> p.sendMessage("Hooray, " + event.affectedBlocks().size() + " are gone!"));
Comment thread
Janmm14 marked this conversation as resolved.
}
}
```

## Cancellable events

We changed our minds now and want to prevent explosions from happening. Great that [EntityExplodeEvent](https://janmm14.de/static/gomint/index.html?gomint.api/io/gomint/event/entity/EntityExplodeEvent.html) extends [CancellableEvent](https://janmm14.de/static/gomint/index.html?gomint.api/io/gomint/event/CancellableEvent.html). To cancel events we write this method in our event listener:

```java
@EventHandler
public void preventExplosions(EntityExplodeEvent event) {
event.cancelled(true);
}
```

## ```@EventHandler``` options

| option | possible values |
|-----------------|-----------------|
| priority | [EventPriority](https://janmm14.de/static/gomint/index.html?gomint.api/io/gomint/event/EventPriority.html) enum: `LOWEST`, `LOW`, `NORMAL` (default), `HIGH`, `HIGHEST` |
| ignoreCancelled | <ul><li>`true` method will not be called for cancelled events<br></li><li>`false` (default) method will be called regardless of event cancelled state</li></ul> |

### Details on priority option

We have two event listeners for the same event. So how do we define the order in which they will execute?

This is possible with the priority option of the `@EventHandler` annotation.

```java
@EventHandler(priority = EventPriority.HIGHEST)
```

Priority `LOWEST` is called first, `HIGHEST` will be called last. So you should choose `HIGHEST` if you want to monitor the result of an event, use `HIGH` to override other plugins and use `LOWEST` or `LOW` for changes other plugins who listen on a higher priority should be able to react to.
Loading