From 49342fedbf0f374c6fc7aa0414b0412a09743268 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Sat, 25 Jul 2020 16:10:33 +0200 Subject: [PATCH] LoginPluginMessages --- .../modding/channels/LoginChannelHandler.java | 21 +++++++ .../channels/PluginChannelHandler.java | 53 +++++++++++++--- .../login/PacketLoginPluginRequest.java | 62 +++++++++++++++++++ .../login/PacketLoginPluginResponse.java | 57 +++++++++++++++++ .../protocol/protocol/PacketHandler.java | 5 ++ .../minosoft/protocol/protocol/Protocol.java | 2 + 6 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/protocol/modding/channels/LoginChannelHandler.java create mode 100644 src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/login/PacketLoginPluginRequest.java create mode 100644 src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/login/PacketLoginPluginResponse.java diff --git a/src/main/java/de/bixilon/minosoft/protocol/modding/channels/LoginChannelHandler.java b/src/main/java/de/bixilon/minosoft/protocol/modding/channels/LoginChannelHandler.java new file mode 100644 index 000000000..9efc44793 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/protocol/modding/channels/LoginChannelHandler.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 LoginChannelHandler { + + void handle(int messageId, PluginChannelHandler handler, InByteBuffer buffer); +} 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 index 433fcfd08..b7694fbb6 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/modding/channels/PluginChannelHandler.java +++ b/src/main/java/de/bixilon/minosoft/protocol/modding/channels/PluginChannelHandler.java @@ -15,6 +15,7 @@ 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.login.PacketLoginPluginResponse; import de.bixilon.minosoft.protocol.packets.serverbound.play.PacketPluginMessageSending; import de.bixilon.minosoft.protocol.protocol.InByteBuffer; import de.bixilon.minosoft.protocol.protocol.OutByteBuffer; @@ -22,18 +23,15 @@ import de.bixilon.minosoft.protocol.protocol.OutByteBuffer; 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 HashMap> channels = new HashMap<>(); + final HashMap> loginChannels = new HashMap<>(); + final ArrayList registeredClientChannels = new ArrayList<>(); + final ArrayList registeredServerChannels = new ArrayList<>(); final Connection connection; public PluginChannelHandler(Connection connection) { - channels = new HashMap<>(); - registeredClientChannels = new ArrayList<>(); - registeredServerChannels = new ArrayList<>(); this.connection = connection; } @@ -50,6 +48,19 @@ public class PluginChannelHandler { channels.get(name).add(handler); } + public void registerLoginClientHandler(String name, LoginChannelHandler handler) { + if (loginChannels.get(name) == null) { + // no channel with that name was registered yet + List handlerList = new ArrayList<>(); + handlerList.add(handler); + loginChannels.put(name, handlerList); + return; + } + // was registered, appending to list + + loginChannels.get(name).add(handler); + } + public void unregisterClientHandler(String name, ChannelHandler handler) { if (channels.get(name) == null) { // not registered @@ -58,6 +69,26 @@ public class PluginChannelHandler { channels.get(name).remove(handler); } + public void unregisterLoginClientHandler(String name, LoginChannelHandler handler) { + if (loginChannels.get(name) == null) { + // not registered + return; + } + loginChannels.get(name).remove(handler); + } + + public void handle(int messageId, String name, byte[] data) { + if (loginChannels.get(name) == null) { + Log.debug(String.format("Can not handle plugin message in channel \"%s\" (messageLength=%d, messageId=%d)", name, data.length, messageId)); + connection.sendPacket(new PacketLoginPluginResponse(messageId, false)); + return; + } + for (LoginChannelHandler handler : loginChannels.get(name)) { + handler.handle(messageId, this, new InByteBuffer(data, connection.getVersion())); + } + + } + public void handle(String name, byte[] data) { DefaultPluginChannels defaultPluginChannel = DefaultPluginChannels.byName(name, connection.getVersion()); if (defaultPluginChannel == DefaultPluginChannels.REGISTER) { @@ -97,6 +128,14 @@ public class PluginChannelHandler { connection.sendPacket(new PacketPluginMessageSending(channel, buffer.getOutBytes())); } + public void sendRawData(int messageId, byte[] data) { + connection.sendPacket(new PacketLoginPluginResponse(messageId, data)); + } + + public void sendRawData(int messageId, OutByteBuffer buffer) { + connection.sendPacket(new PacketLoginPluginResponse(messageId, buffer.getOutBytes())); + } + public void registerServerChannel(String name) { if (DefaultPluginChannels.byName(name, connection.getVersion()) != null) { // channel is a default channel, can not register diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/login/PacketLoginPluginRequest.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/login/PacketLoginPluginRequest.java new file mode 100644 index 000000000..d81a84777 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/login/PacketLoginPluginRequest.java @@ -0,0 +1,62 @@ +/* + * 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.packets.clientbound.login; + +import de.bixilon.minosoft.logging.Log; +import de.bixilon.minosoft.protocol.packets.ClientboundPacket; +import de.bixilon.minosoft.protocol.protocol.InByteBuffer; +import de.bixilon.minosoft.protocol.protocol.PacketHandler; + +public class PacketLoginPluginRequest implements ClientboundPacket { + int messageId; + String channel; + byte[] data; + + + @Override + public boolean read(InByteBuffer buffer) { + switch (buffer.getVersion()) { + case VERSION_1_13_2: + case VERSION_1_14_4: + messageId = buffer.readVarInt(); + channel = buffer.readString(); + data = buffer.readBytesLeft(); + return true; + } + + return false; + } + + @Override + public void log() { + Log.protocol(String.format("Received login plugin request in channel \"%s\" with %s bytes of data (messageId=%d)", channel, data.length, messageId)); + } + + @Override + public void handle(PacketHandler h) { + h.handle(this); + } + + public int getMessageId() { + return messageId; + } + + public String getChannel() { + return channel; + } + + public byte[] getData() { + return data; + } +} diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/login/PacketLoginPluginResponse.java b/src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/login/PacketLoginPluginResponse.java new file mode 100644 index 000000000..941cb39f4 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/login/PacketLoginPluginResponse.java @@ -0,0 +1,57 @@ +/* + * 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.packets.serverbound.login; + +import de.bixilon.minosoft.logging.Log; +import de.bixilon.minosoft.protocol.packets.ServerboundPacket; +import de.bixilon.minosoft.protocol.protocol.OutPacketBuffer; +import de.bixilon.minosoft.protocol.protocol.Packets; +import de.bixilon.minosoft.protocol.protocol.ProtocolVersion; + +public class PacketLoginPluginResponse implements ServerboundPacket { + final int messageId; + final boolean successful; + byte[] data; + + public PacketLoginPluginResponse(int messageId, boolean successful) { + this.messageId = messageId; + this.successful = successful; + } + + public PacketLoginPluginResponse(int messageId, byte[] data) { + this.messageId = messageId; + this.successful = true; + this.data = data; + } + + @Override + public OutPacketBuffer write(ProtocolVersion version) { + OutPacketBuffer buffer = new OutPacketBuffer(version, version.getPacketCommand(Packets.Serverbound.LOGIN_PLUGIN_RESPONSE)); + switch (version) { + case VERSION_1_13_2: + case VERSION_1_14_4: + buffer.writeVarInt(messageId); + buffer.writeBoolean(successful); + if (successful) { + buffer.writeBytes(data); + } + } + return buffer; + } + + @Override + public void log() { + Log.protocol(String.format("Sending login plugin response (messageId=%d, successful=%s)", messageId, successful)); + } +} 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 3c3944f52..e0eecc833 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java @@ -33,6 +33,7 @@ import de.bixilon.minosoft.nbt.tag.StringTag; import de.bixilon.minosoft.protocol.network.Connection; import de.bixilon.minosoft.protocol.packets.clientbound.login.PacketEncryptionRequest; import de.bixilon.minosoft.protocol.packets.clientbound.login.PacketLoginDisconnect; +import de.bixilon.minosoft.protocol.packets.clientbound.login.PacketLoginPluginRequest; import de.bixilon.minosoft.protocol.packets.clientbound.login.PacketLoginSuccess; import de.bixilon.minosoft.protocol.packets.clientbound.play.*; import de.bixilon.minosoft.protocol.packets.clientbound.status.PacketStatusPong; @@ -619,4 +620,8 @@ public class PacketHandler { public void handle(PacketAcknowledgePlayerDigging pkg) { } + + public void handle(PacketLoginPluginRequest pkg) { + connection.getPluginChannelHandler().handle(pkg.getMessageId(), pkg.getChannel(), pkg.getData()); + } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/Protocol.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/Protocol.java index 7d3af5990..cb346669a 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/Protocol.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/Protocol.java @@ -17,6 +17,7 @@ import com.google.common.collect.HashBiMap; import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.packets.clientbound.login.PacketEncryptionRequest; import de.bixilon.minosoft.protocol.packets.clientbound.login.PacketLoginDisconnect; +import de.bixilon.minosoft.protocol.packets.clientbound.login.PacketLoginPluginRequest; import de.bixilon.minosoft.protocol.packets.clientbound.login.PacketLoginSuccess; import de.bixilon.minosoft.protocol.packets.clientbound.play.*; import de.bixilon.minosoft.protocol.packets.clientbound.status.PacketStatusPong; @@ -34,6 +35,7 @@ public abstract class Protocol implements ProtocolInterface { packetClassMapping.put(Packets.Clientbound.LOGIN_LOGIN_SUCCESS, PacketLoginSuccess.class); packetClassMapping.put(Packets.Clientbound.LOGIN_DISCONNECT, PacketLoginDisconnect.class); packetClassMapping.put(Packets.Clientbound.LOGIN_SET_COMPRESSION, PacketLoginSetCompression.class); + packetClassMapping.put(Packets.Clientbound.LOGIN_PLUGIN_REQUEST, PacketLoginPluginRequest.class); packetClassMapping.put(Packets.Clientbound.PLAY_JOIN_GAME, PacketJoinGame.class); packetClassMapping.put(Packets.Clientbound.PLAY_PLAYER_INFO, PacketPlayerInfo.class);