diff --git a/src/main/java/de/bixilon/minosoft/protocol/modding/channels/ChannelHandler.java b/src/main/java/de/bixilon/minosoft/protocol/modding/channels/ChannelHandler.java
new file mode 100644
index 000000000..59ef017da
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/protocol/modding/channels/ChannelHandler.java
@@ -0,0 +1,21 @@
+/*
+ * Codename Minosoft
+ * Copyright (C) 2020 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.protocol.modding.channels;
+
+import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
+
+public interface ChannelHandler {
+
+ void handle(PluginChannelHandler handler, InByteBuffer buffer);
+}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/modding/channels/DefaultPluginChannels.java b/src/main/java/de/bixilon/minosoft/protocol/modding/channels/DefaultPluginChannels.java
new file mode 100644
index 000000000..c6052819e
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/protocol/modding/channels/DefaultPluginChannels.java
@@ -0,0 +1,38 @@
+/*
+ * Codename Minosoft
+ * Copyright (C) 2020 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.protocol.modding.channels;
+
+public enum DefaultPluginChannels {
+ MC_BRAND("MC|Brand");
+
+
+ final String name;
+
+ DefaultPluginChannels(String name) {
+ this.name = name;
+ }
+
+ public static DefaultPluginChannels byName(String name) {
+ for (DefaultPluginChannels d : values()) {
+ if (d.getName().equals(name)) {
+ return d;
+ }
+ }
+ return null;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/modding/channels/PluginChannelHandler.java b/src/main/java/de/bixilon/minosoft/protocol/modding/channels/PluginChannelHandler.java
new file mode 100644
index 000000000..1906fabec
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/protocol/modding/channels/PluginChannelHandler.java
@@ -0,0 +1,112 @@
+/*
+ * Codename Minosoft
+ * Copyright (C) 2020 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.protocol.modding.channels;
+
+import de.bixilon.minosoft.logging.Log;
+import de.bixilon.minosoft.protocol.network.Connection;
+import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketPluginMessageSending;
+import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class PluginChannelHandler {
+ final Map> channels;
+ final List registeredClientChannels;
+ final List registeredServerChannels;
+ final Connection connection;
+
+ public PluginChannelHandler(Connection connection) {
+ channels = new HashMap<>();
+ registeredClientChannels = new ArrayList<>();
+ registeredServerChannels = new ArrayList<>();
+ this.connection = connection;
+ }
+
+ public void registerClientHandler(String name, ChannelHandler handler) {
+ if (channels.get(name) == null) {
+ // no channel with that name was registered yet
+ List handlerList = new ArrayList<>();
+ handlerList.add(handler);
+ channels.put(name, handlerList);
+ return;
+ }
+ // was registered, appending to list
+
+ channels.get(name).add(handler);
+ }
+
+ public void unregisterClientHandler(String name, ChannelHandler handler) {
+ if (channels.get(name) == null) {
+ // not registered
+ return;
+ }
+ channels.get(name).remove(handler);
+ }
+
+ public void handle(String name, byte[] data) {
+ if (name.equals("REGISTER")) {
+ // register this channel
+ String toRegisterName = new String(data);
+ registeredClientChannels.add(toRegisterName);
+ Log.debug(String.format("Server registered plugin channel \"%s\"", toRegisterName));
+ return;
+ }
+ if (name.equals("UNREGISTER")) {
+ // register this channel
+ String toUnregisterName = new String(data);
+ registeredClientChannels.remove(toUnregisterName);
+ Log.debug(String.format("Server unregistered plugin channel \"%s\"", toUnregisterName));
+ return;
+ }
+ // check if channel was registered or if it is a default channel
+ if (!registeredClientChannels.contains(name) && DefaultPluginChannels.byName(name) == null) {
+ Log.debug(String.format("Server tried to send data into unregistered plugin channel (name=\"%s\", messageLength=%d)", name, data.length));
+ return;
+ }
+ if (channels.get(name) == null) {
+ Log.debug(String.format("Can not handle plugin message in channel \"%s\" (messageLength=%d)", name, data.length));
+ return;
+ }
+
+ for (ChannelHandler handler : channels.get(name)) {
+ handler.handle(this, new InByteBuffer(data));
+ }
+ }
+
+ public void sendRawData(String channel, byte[] data) {
+ connection.sendPacket(new PacketPluginMessageSending(channel, data));
+ }
+
+ public void registerServerChannel(String name) {
+ if (DefaultPluginChannels.byName(name) != null) {
+ // channel is a default channel, can not register
+ throw new IllegalArgumentException(String.format("Can not register default Minecraft plugin channel (name=%s)", name));
+ }
+ sendRawData("REGISTER", name.getBytes());
+ registeredServerChannels.add(name);
+ }
+
+ public void unregisterServerChannel(String name) {
+ if (DefaultPluginChannels.byName(name) != null) {
+ // channel is a default channel, can not unregister
+ throw new IllegalArgumentException(String.format("Can not unregister default Minecraft plugin channel (name=%s)", name));
+ }
+ sendRawData("UNREGISTER", name.getBytes());
+ registeredServerChannels.remove(name);
+ }
+
+}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java b/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java
index 6cd71c5b8..8a8df0efb 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java
+++ b/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java
@@ -13,8 +13,12 @@
package de.bixilon.minosoft.protocol.network;
+import de.bixilon.minosoft.Minosoft;
+import de.bixilon.minosoft.config.GameConfiguration;
import de.bixilon.minosoft.game.datatypes.Player;
import de.bixilon.minosoft.logging.Log;
+import de.bixilon.minosoft.protocol.modding.channels.DefaultPluginChannels;
+import de.bixilon.minosoft.protocol.modding.channels.PluginChannelHandler;
import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
import de.bixilon.minosoft.protocol.packets.ServerboundPacket;
import de.bixilon.minosoft.protocol.packets.serverbound.handshaking.PacketHandshake;
@@ -33,11 +37,11 @@ public class Connection {
private final int port;
private final Network network;
private final PacketHandler handler;
+ private final PluginChannelHandler pluginChannelHandler;
private final ArrayList handlingQueue;
+ Thread handleThread;
private Player player;
private ConnectionState state = ConnectionState.DISCONNECTED;
- Thread handleThread;
-
private boolean onlyPing;
public Connection(String host, int port) {
@@ -46,6 +50,8 @@ public class Connection {
network = new Network(this);
handlingQueue = new ArrayList<>();
handler = new PacketHandler(this);
+ pluginChannelHandler = new PluginChannelHandler(this);
+ registerDefaultChannels();
}
/**
@@ -130,6 +136,10 @@ public class Connection {
return player;
}
+ public void setPlayer(Player player) {
+ this.player = player;
+ }
+
public void sendPacket(ServerboundPacket p) {
network.sendPacket(p);
}
@@ -157,11 +167,20 @@ public class Connection {
handleThread.start();
}
- public void setPlayer(Player player) {
- this.player = player;
- }
-
public void sendChatMessage(String message) {
sendPacket(new PacketChatMessage(message));
}
+
+ public PluginChannelHandler getPluginChannelHandler() {
+ return pluginChannelHandler;
+ }
+
+ public void registerDefaultChannels() {
+ // MC|Brand
+ getPluginChannelHandler().registerClientHandler(DefaultPluginChannels.MC_BRAND.getName(), (handler, buffer) -> {
+ Log.info(String.format("Server is running %s on version %s", new String(buffer.readBytes(buffer.getBytesLeft())), getVersion().getName()));
+
+ getPluginChannelHandler().sendRawData(DefaultPluginChannels.MC_BRAND.getName(), (Minosoft.getConfig().getBoolean(GameConfiguration.NETWORK_FAKE_CLIENT_BRAND) ? "vanilla" : "Minosoft").getBytes());
+ });
+ }
}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java
index 621982bb6..0bec7e2e1 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java
+++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java
@@ -13,8 +13,6 @@
package de.bixilon.minosoft.protocol.protocol;
-import de.bixilon.minosoft.Minosoft;
-import de.bixilon.minosoft.config.GameConfiguration;
import de.bixilon.minosoft.game.datatypes.GameMode;
import de.bixilon.minosoft.game.datatypes.blocks.Blocks;
import de.bixilon.minosoft.game.datatypes.entities.meta.HumanMetaData;
@@ -30,7 +28,6 @@ import de.bixilon.minosoft.protocol.packets.clientbound.status.PacketStatusRespo
import de.bixilon.minosoft.protocol.packets.serverbound.login.PacketEncryptionResponse;
import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketKeepAliveResponse;
import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketPlayerPositionAndRotationSending;
-import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketPluginMessageSending;
import javax.crypto.SecretKey;
import java.math.BigInteger;
@@ -103,13 +100,7 @@ public class PacketHandler {
}
public void handle(PacketPluginMessageReceiving pkg) {
- if (pkg.getChannel().equals("MC|Brand")) {
- // server brand received
- Log.info(String.format("Server is running %s on version %s", new String(pkg.getData()), connection.getVersion().getName()));
-
- // send back own brand
- connection.sendPacket(new PacketPluginMessageSending("MC|Brand", (Minosoft.getConfig().getBoolean(GameConfiguration.NETWORK_FAKE_CLIENT_BRAND) ? "vanilla" : "Minosoft")));
- }
+ connection.getPluginChannelHandler().handle(pkg.getChannel(), pkg.getData());
}
public void handle(PacketSpawnLocation pkg) {