Skip to content

Plugins

Yvan edited this page May 16, 2024 · 13 revisions

Overview

Plugins are jar files that you place in the plugins folder. They are automatically started when the server starts. Overall, it is thanks to this that you will be able to configure the redirection rules and configure the proxy that you wish.

Here are some possibilities you can do with plugins:

  • Configure redirection rules, determine which server to send the player to.
  • Configure what to display on the MOTD when the server is pinged.
  • Block connections based on certain factors you decide.
  • And pretty much anything that happens when the player logs in.

Demo plugins using Gradle are available HERE.

Gradle/Maven Dependency

If you want to import TransferProxy API as a dependency for gradle or maven, here is how to do it:

Gradle

Repository:

repositories {
    mavenCentral()
    maven { url 'https://jitpack.io' }
}

Dependency:

compileOnly 'com.github.YvanMazy.TransferProxy:api:<VERSION>'

Maven

Repository:

<repository>
    <id>jitpack.io</id>
    <url>https://jitpack.io</url>
</repository>

Dependency:

<dependency>
    <groupId>com.github.YvanMazy.TransferProxy</groupId>
    <artifactId>api</artifactId>
    <version><VERSION></version>
</dependency>

It is also possible to import TransferProxy with these implementations by replacing api with core. Replace with the version you are using.

The latest version is: Release

How to develop a plugin?

The first step is to create a plugin.yml file in your project's resource files. The plugin.yml must respect the following format:

name: DemoPlugin
author: YvanMazy
version: 1.0
description: This is a demo plugin.
main: be.yvanmazy.demoplugin.DemoPlugin

Then create the main class, indicate in the plugin.yml. This class must implements be.yvanmazy.transferproxy.api.plugin.Plugin. Here is an example of a main class:

public final class DemoPlugin implements Plugin {

    @Override
    public void onEnable() {
    }

    @Override
    public void onDisable() {
    }

}

Events API

When the connection changes state, an event is called. It is possible to intercept this event to act on it. You can find the list of events in the EventType enum.

  • HANDSHAKE: Called when a new connection is initiated. This is the first event, it is possible to disconnect the connection.
  • PRE_LOGIN: Called when a connection begins the LOGIN state. It may be interesting to use it when you need to retrieve or set cookies as soon as possible.
  • STATUS: Called when a connection requests status. This is the event we use when we want to configure the motd.
  • READY: Called when a connection is ready to transfer. All information is retrieved when this event is called.

To listen to an event you must access EventManager. You can get a EventManager instance from the ModuleManager instance. From anywhere with

TransferProxy.getInstance().getModuleManager().getEventManager()

Or from the Plugin class with

this.getEventManager()

Here is a usage example to set a listener on the READY event.

this.getEventManager().<ReadyListener>addListener(EventType.READY, connection -> connection.transfer("lobby.my-server.com", 25565));

Here is a usage example to set a listener on the STATUS event.

this.getEventManager().<StatusListener>addListener(EventType.STATUS,
        new CachedStatusListener(StatusResponse.builder()
                .name("TransferProxy")
                .description(Component.text("My super message", NamedTextColor.GREEN))
                .build()));

Here is a usage example to set a listener on the PRE_LOGIN event.

this.getEventManager().<PreLoginListener>addListener(EventType.PRE_LOGIN, event -> {
    event.setCanSendSuccessPacket(false);
    this.executor.execute(() -> {
        // Do something asynchronously like fetch cookie
        event.getConnection().sendLoginSuccess(event.getUUID(), event.getUsername());
    });
});

Here is a usage example to set a listener on the HANDSHAKE event.

this.getEventManager().<HandshakeListener>addListener(EventType.HANDSHAKE, connection -> {
    if (connection.getChannel().remoteAddress() instanceof final InetSocketAddress address &&
            isBlacklisted(address.getAddress().getHostAddress())) {
        connection.disconnect(Component.text("You are blacklisted", NamedTextColor.RED));
    }
});

Cookies API

Along with transfer packets, Minecraft added cookie packets. It is a system that allows you to ask clients to store information within a limit of 5 kiB.

This information can be retrieved at any time and is retained between servers until the player logs out. So this is not persistent data.

Warning: It is technically possible for the client to lie and respond to the servers with falsified information. Please keep in mind that the data sent by the client may be false. If it is important information, it is best to think about a system to verify the integrity of the data. A demo plugin that uses JWT and SHA-256 to encrypt messages is available here.

Cookie keys are namespaced keys. That is to say that they are always in the following format: namespace:key For example : minecraft:super_cookie

Here are some code examples:

PlayerConnection connection = null; // Replaced by a PlayerConnection instance

// Store a cookie with a message
connection.storeCookie("transferproxy:my_cookie", "my message".getBytes());

// Fetch a cookie, convert the bytes to a String and display it in the console.
connection.fetchCookie("transferproxy:my_cookie").thenApply(String::new).thenAccept(System.out::println);

Please note, in this example, the data is not encrypted.

Clone this wiki locally