Skip to content
mohammed edited this page Oct 4, 2024 · 16 revisions

RedisBungee Java API

API stability

In general, API-breaking changes are only introduced for new major releases (e.g. 0.2.5 to 0.3).

Any changes made after limework fork 0.6.5+ are subject to be removed but Bungeecord version should be backward compatible with RedisBungee 0.5 pre fork.

Jitpack repo setup

Since RedisBungee uses jitpack, we need to setup jitpack repository in the project

  • maven
	<repositories>
		<repository>
		    <id>jitpack.io</id>
		    <url>https://jitpack.io</url>
		</repository>
	</repositories>
  • gradle (kotlin dsl)
repositories {
    maven("https://jitpack.io/")
}

For Bungeecord / waterfall

We need to import the RedisBungee-Bungee Module

  • maven
	<dependency>
        <groupId>com.github.ProxioDev.ValioBungee</groupId>
	    <artifactId>RedisBungee-Bungee</artifactId>
	    <version>0.12.3</version>
	    <scope>provided</scope>
	</dependency>
	
  • Gradle kotlin dsl
compileOnly("com.github.ProxioDev.ValioBungee:RedisBungee-Bungee:0.12.3")

then in your project plugin.yml add RedisBungee to depends like this

name: "yourplugin"
main: your.main.class
version: 1.0.0-SNAPSHOT
author: idk
depends: [ RedisBungee ]

For velocity

  • maven
	<dependency>
	    <groupId>com.github.ProxioDev.ValioBungee</groupId>
	    <artifactId>RedisBungee-Velocity</artifactId>
	    <version>0.12.3</version>
	    <scope>provided</scope>
	</dependency>
  • gradle (kotlin dsl)
compileOnly("com.github.ProxioDev.ValioBungee:RedisBungee-Velocity:0.12.3")

then to make your plugin depends on RedisBungee, make sure your plugin class Annotation have @Dependency(id = "redisbungee") like this

@Plugin(
  id = "myplugin",
  name = "My Plugin",
  version = "0.1.0-beta",
  dependencies = {
    @Dependency(id = "redisbungee")
  }
)
public class PluginMainClass {

}

Access the API

Each platform got it own RedisBungeeAPI class for example velocity' which implements AbstractRedisBungeeAPI

RedisBungeeAPI api = RedisBungeeAPI.getRedisBungeeApi();

int playerCount = api.getPlayerCount(); // network players count

String proxyId = api.getProxyId(); // Current proxy id

// lets kick a player in the network, message uses Adventure api component class

UUID player = api.getUuidFromName("Ham1255"); // uses uuid cache if username for uuid exists

api.kickPlayer(player, Component.text("lmao, you got kicked"));

// you can view classes / java docs for more info about methods in API

Relocation / Access built-in UnifiedJedis

UnifiedJedis

this should return non closeable version of unifiedjedis, so we don't need api users to kill the connection to the db

UnifiedJedis jedis = RedisBungeeAPI.getRedisBungeeApi().getSummoner().obtainResource();

note: that UnifiedJedis is Parent class of most Jedis stuff like JedisPooled and JedisCluster.

Relocation

Because RedisBungee shades and relocates the jedis lib we need to make our plugin relocated to package path

an example for Gradle shadow in kotlin dsl:

plugins {
    java
    id("com.github.johnrengelman.shadow") version "8.1.1" // load the gradle shadow 

}

group = "org.example1"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
    maven {
        name = "sonatype"
        url = uri("https://oss.sonatype.org/content/groups/public/")
    }
    maven {
        name = "papermc-repo"
        url = uri("https://repo.papermc.io/repository/maven-public/")
    }
    maven {
        url = uri("https://jitpack.io")
    }
}

dependencies {
    compileOnly("io.github.waterfallmc:waterfall-api:1.20-R0.1-SNAPSHOT")
    compileOnly("com.github.ProxioDev.ValioBungee:RedisBungee-Bungee:0.12.3")
}

tasks {
    compileJava {
        options.encoding = Charsets.UTF_8.name()
        options.release.set(17)
    }
    // this is for relocation
    shadowJar {
        relocate("redis.clients.jedis", "com.imaginarycode.minecraft.redisbungee.internal.jedis")
        relocate("redis.clients.util", "com.imaginarycode.minecraft.redisbungee.internal.jedisutil")
        // BUNGEECORD ONLY
        relocate("com.google.common", "com.imaginarycode.minecraft.redisbungee.internal.com.google.common")
        relocate("com.google.errorprone", "com.imaginarycode.minecraft.redisbungee.internal.com.google.errorprone")
        relocate("com.google.gson", "com.imaginarycode.minecraft.redisbungee.internal.com.google.gson")
        relocate("com.google.j2objc", "com.imaginarycode.minecraft.redisbungee.internal.com.google.j2objc")
        relocate("com.google.thirdparty", "com.imaginarycode.minecraft.redisbungee.internal.com.google.thirdparty")
    }
}

example for Maven only the shade part:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.4</version>
    <configuration>
        <relocations>
            <relocation>
                <pattern>redis.clients.jedis</pattern>
                <shadedPattern>com.imaginarycode.minecraft.redisbungee.internal.jedis</shadedPattern>
            </relocation>
            <relocation>
                <pattern>redis.clients.util</pattern>
                <shadedPattern>com.imaginarycode.minecraft.redisbungee.internal.jedisutil</shadedPattern>
            </relocation>
        </relocations>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Javadocs

Plugin Messaging (Bukkit or any downstream server)

From Bukkit, you can access some RedisBungee functionality via the plugin messaging API. RedisBungee listens on its own plugin messaging channels

  • 'legacy:redisbungee' or 'redisbungee' for pre 1.13
  • RedisBungee

and expects all messages in Data{Input,Output}Stream format.

Examples

Sending messages

ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("PlayerCount");
out.writeUTF("ALL");
player.sendPluginMessage(MyPlugin.getInstance(), "RedisBungee", out.toByteArray());

Deserializing ServerPlayers results

private Multiset<String> deserializeNoMembers(ByteArrayDataInput input) {
    int collectionSize = input.readInt();
    Multiset<String> multiset = HashMultiset.create();
    for (int i = 0; i < collectionSize; i++) {
        String in = input.readUTF();
        int cnt = input.readInt();
        multiset.setCount(in, cnt);
    }
    return multiset;
}

private Multimap<String, String> deserializeWithMembers(ByteArrayDataInput input) {
    int collectionSize = input.readInt();
    Multimap<String, String> multimap = HashMultimap.create();
    for (int i = 0; i < collectionSize; i++) {
        String in = input.readUTF();
        int cnt = input.readInt();
        for (int i1 = 0; i1 < cnt; i1++) {
            String in2 = input.readUTF();
            multimap.put(in, in2);
        }
    }
    return multimap;
}

Definitions

  • Player
    • Username or UUID (Java or Mojang-style)

Commands

Subchannel Arguments Response Notes
PlayerList Server or ALL The command returned (but see the notes), then a comma-separated list of players. Due to a bug (fixed in 0.3.2), the first string of the response was Players, not PlayerList.
PlayerCount Server or ALL The command returned, then the number of players found.
LastOnline See Definitions The command returned, then a long specified by the output of the getLastOnline() API.
Proxy none The command returned, then the proxy's name Introduced in 0.3.6 (June 29, 2015)
ServerPlayers COUNT or PLAYERS The command returned, then the type specified, then a serialized multimap Introduced in 0.3.6 (June 29, 2015)

Redis PubSub

RedisBungee supports Redis PubSub. PUBLISH a command to redisbungee-allservers to a BungeeCord command on all servers, or redisbungee-<SERVERID> to invoke the command on just one server. You can also listen on a separate PubSub channel and handle the PubSubMessageEvent event for it, starting with RedisBungee 0.3. See the registerPubSubChannels(), unregisterPubSubChannels() and PubSubMessageEvent. no longer needed to register a channel after 0.12.0 due switch to streams

If you are invoking a command, make sure that the sender is an instance of RedisBungeeCommandSender!

Not recommended: Tinkering with RedisBungee's datasets

While this is possible, doing so will cause problems when RedisBungee's data schema changes (which is sometimes quite often). A good example of this is the 0.2.x to 0.3.x transition, when UUIDs were stored instead of usernames. RedisBungee does everything humanely possible to hide its internals from other plugins, so backend changes can be made with ease.