Bukkit & Bungee Plugin Messaging Channel - Historical

Applied By roblabla: Jun 9, 2013 at 10:48 AM

Bukkit & Bungee Plugin Messaging Channel
NOTE: This thread is for Bukkit plugins communicating with Bungee.
Here, I will explain how to use the BungeeCord Plugin Channel from a Bukkit plugin. This channel allows you to query information from bungeecord, as well as make your plugin communicate between the different bukkit subservers.

What is a Plugin Message ?
Originally, Plugin Messaging was implemented so server-side plugins could send any kind of data to client-side mods. Before, they would have needed to implement custom packets, but the problem with this is that it meant the minecraft client would get disconnected from the servers using those custom packets with an incomprehensible error message, because it would be unable to read that packet. To fix this issue, mojang introduced the "Custom Plugin Message Packet".

The anatomy of a Plugin Message Packet is as such :
1) The size of the plugin message (in a short)
2) The name of the "channel" (also named "tag" in bungeecord) the plugin message transits through (in a string)
3) The actual data (in a byte array)

BungeeCord Plugin Channel ?
First of all, BungeeCord's byte array is organized around the output of a Data(In/Out)putStream

Before using the BungeeCord plugin channel, you'll need to register it. That is, you need to tell Bukkit "Hey, I wanna use this channel". We'll also need to tell Bukkit what method to call whenever he receives a new message on channel "BungeeCord". I suggest you make your plugin class look like this :

PHP:
public class MyPlugin extends JavaPlugin implements PluginMessageListener {
    @Override
    public void onEnable() {
        this.getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
        this.getServer().getMessenger().registerIncomingPluginChannel(this, "BungeeCord", this);
    }
 
    @Override
    public void onPluginMessageReceived(String channel, Player player, byte[] message) {
        if (!channel.equals("BungeeCord")) {
            return;
        }
 
        DataInputStream in = new DataInputStream(new ByteArrayInputStream(message));
        String subchannel = in.readUTF();
        if (subchannel.equals("SomeSubChannel")) {
            // Do something
        } else if (subchannel.equals("SomeOtherSubChannel")) {
          // Do something else.
        }
    }
}
As for sending plugin messages, here is the way I recommend to do it :
PHP:
ByteArrayOutputStream b = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(b);
 
out.writeUTF("subchannel");
out.writeUTF("AnArgument");
 
 
// If the player is important :
Player p = Bukkit.getPlayer("someplayer");
// OR, if you don't need to send it to a specific player
Player p = Bukkit.getOnlinePlayers()[0];
 
p.sendPluginMessage(plugin, "BungeeCord", b.toByteArray());
BungeeCord's SubChannel Spec :
Connect
Connect a player to said subserver.

Arguments
String name of server to connect to, as defined in bungeecord config.yml

Receiver
the player you want to teleport.

Sending Example
PHP:
out.writeUTF("Connect");
out.writeUTF("pvp");
Response
None


IP
Get the (real) IP of a player.

Arguments
None

Receiver
The player you wish to get the IP of.

Example
PHP:
out.writeUTF("IP");
Response
PHP:
String ip = in.readUTF();
int port = in.readInt();

PlayerCount
Get the amount of players on a certain server, or on ALL the servers.

Arguments
String the name of the server to get the playercount of, or ALL to get the global player count

Receiver
Any player

Example
PHP:
out.writeUTF("PlayerCount");
out.writeUTF("pvp");
Response
PHP:
String server = in.readUTF(); // Name of server, as given in the arguments
int playercount = in.readInt();

PlayerList
Get a list of players connected on a certain server, or on ALL the servers.

Arguments
String the name of the server to get the list of connected players, or ALL for global online player list

Receiver
Any player

Example
PHP:
out.writeUTF("PlayerList");
out.writeUTF("pvp");
Response
PHP:
String server = in.readUTF(); // The name of the server you got the player list of, as given in args.
String[] playerList = in.readUTF().split(", ");

GetServers
Get a list of server name strings, as defined in bungeecord's config.yml

Arguments
None

Receiver
Any player

Example
PHP:
out.writeUTF("GetServers");
Response
PHP:
String[] serverList = in.readUTF().split(", ");

Message
Send a message (as in, a chat message) to the specified player.

Arguments
String the name of the player to send the chat message
String the message to send to the player

Receiver
Any player

Example
PHP:
out.writeUTF("roblabla");
out.writeUTF(ChatColor.RED + "Congrats, you just won 1$!");
Response
None


GetServer
Get this server's name, as defined in bungeecord's config.yml

Arguments
None

Receiver
Any player

Example
PHP:
out.writeUTF("GetServer");
Response
PHP:
String servername = in.readUTF();

Forward
Send a custom plugin message to said server. This is one of the most useful channel ever.

Arguments
String server to send to, or ALL to send to every server (except the one sending the plugin message)
String Subchannel to send to.
Short The size of the plugin message array.
Byte[] message to send.

Receiver
Any player

Example
PHP:
out.writeUTF("ALL");
out.writeUTF("MyChannel");
 
ByteArrayOutputStream msgbytes = new ByteArrayOutputStream();
DataOutputStream msgout = new DataOutputStream(msgbytes);
msgout.writeUTF("Some kind of data here"); // You can do anything you want with msgout
msgout.writeShort(123);
 
out.writeShort(msgbytes.toByteArray().length);
out.write(msgbytes.toByteArray());
Response
VERY IMPORTANT : the subchannel will NOT be Forward. It will be the subchannel you sent as an argument.
PHP:
short len = in.readShort();
byte[] msgbytes = new byte[len];
in.readFully(msgbytes);
 
DataInputStream msgin = new DataInputStream(new ByteArrayInputStream(msgbytes));
String somedata = msgin.readUTF(); // Read the data in the same way you wrote it
short somenumber = msgin.readShort();