From d8ef6423c523cf78963b4a0a5d59757dce4ba07a Mon Sep 17 00:00:00 2001 From: lax1dude Date: Fri, 9 Aug 2024 19:58:17 -0700 Subject: [PATCH] Add backend RPC protocol classes --- .../EaglerBackendRPCProtocol.java | 147 +++++++ .../pkt/EaglerBackendRPCHandler.java | 143 +++++++ .../pkt/EaglerBackendRPCPacket.java | 72 ++++ .../pkt/WrongRPCPacketException.java | 24 ++ .../pkt/client/CPacketRPCDisabled.java | 48 +++ .../pkt/client/CPacketRPCEnabled.java | 62 +++ .../pkt/client/CPacketRPCNotifBadgeHide.java | 58 +++ .../pkt/client/CPacketRPCNotifBadgeShow.java | 167 ++++++++ .../client/CPacketRPCNotifIconRegister.java | 85 ++++ .../client/CPacketRPCNotifIconRelease.java | 86 ++++ .../pkt/client/CPacketRPCRedirectPlayer.java | 64 +++ .../client/CPacketRPCRequestPlayerInfo.java | 74 ++++ .../client/CPacketRPCResetPlayerMulti.java | 68 ++++ .../pkt/client/CPacketRPCSendRawMessage.java | 72 ++++ .../client/CPacketRPCSendWebViewMessage.java | 86 ++++ .../client/CPacketRPCSetPauseMenuCustom.java | 217 ++++++++++ .../pkt/client/CPacketRPCSetPlayerCape.java | 65 +++ .../pkt/client/CPacketRPCSetPlayerCookie.java | 83 ++++ .../pkt/client/CPacketRPCSetPlayerFNAWEn.java | 60 +++ .../pkt/client/CPacketRPCSetPlayerSkin.java | 65 +++ .../pkt/client/CPacketRPCSubscribeEvents.java | 60 +++ .../pkt/server/SPacketRPCEnabledFailure.java | 62 +++ .../pkt/server/SPacketRPCEnabledSuccess.java | 60 +++ .../server/SPacketRPCEventToggledVoice.java | 64 +++ .../server/SPacketRPCEventWebViewMessage.java | 86 ++++ .../SPacketRPCEventWebViewOpenClose.java | 71 ++++ .../server/SPacketRPCResponseTypeBytes.java | 65 +++ .../server/SPacketRPCResponseTypeCookie.java | 83 ++++ .../server/SPacketRPCResponseTypeError.java | 60 +++ .../server/SPacketRPCResponseTypeNull.java | 56 +++ .../server/SPacketRPCResponseTypeString.java | 68 ++++ .../server/SPacketRPCResponseTypeUUID.java | 62 +++ .../SPacketRPCResponseTypeVoiceStatus.java | 64 +++ .../SPacketRPCResponseTypeWebViewStatus.java | 81 ++++ .../util/NotificationBadgeBuilder.java | 372 ++++++++++++++++++ .../util/PacketImageData.java | 78 ++++ .../util/SkinPacketHelper.java | 214 ++++++++++ 37 files changed, 3352 insertions(+) create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/EaglerBackendRPCProtocol.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/EaglerBackendRPCHandler.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/EaglerBackendRPCPacket.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/WrongRPCPacketException.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCDisabled.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCEnabled.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifBadgeHide.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifBadgeShow.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifIconRegister.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifIconRelease.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCRedirectPlayer.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCRequestPlayerInfo.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCResetPlayerMulti.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSendRawMessage.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSendWebViewMessage.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPauseMenuCustom.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerCape.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerCookie.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerFNAWEn.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerSkin.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSubscribeEvents.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEnabledFailure.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEnabledSuccess.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEventToggledVoice.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEventWebViewMessage.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEventWebViewOpenClose.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeBytes.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeCookie.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeError.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeNull.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeString.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeUUID.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeVoiceStatus.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeWebViewStatus.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/util/NotificationBadgeBuilder.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/util/PacketImageData.java create mode 100644 gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/util/SkinPacketHelper.java diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/EaglerBackendRPCProtocol.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/EaglerBackendRPCProtocol.java new file mode 100644 index 0000000..b1f4e82 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/EaglerBackendRPCProtocol.java @@ -0,0 +1,147 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.*; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server.*; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public enum EaglerBackendRPCProtocol { + INIT(0, + define_CLIENT_(0x00, CPacketRPCEnabled.class), + define_SERVER_(0x01, SPacketRPCEnabledSuccess.class), + define_SERVER_(0x02, SPacketRPCEnabledFailure.class) + ), V1(1, + define_CLIENT_(0x03, CPacketRPCDisabled.class), + define_CLIENT_(0x04, CPacketRPCRequestPlayerInfo.class), + define_CLIENT_(0x05, CPacketRPCSubscribeEvents.class), + define_CLIENT_(0x06, CPacketRPCSetPlayerSkin.class), + define_CLIENT_(0x07, CPacketRPCSetPlayerCape.class), + define_CLIENT_(0x08, CPacketRPCSetPlayerCookie.class), + define_CLIENT_(0x09, CPacketRPCSetPlayerFNAWEn.class), + define_CLIENT_(0x0A, CPacketRPCSetPauseMenuCustom.class), + define_CLIENT_(0x0B, CPacketRPCRedirectPlayer.class), + define_CLIENT_(0x0C, CPacketRPCResetPlayerMulti.class), + define_SERVER_(0x0D, SPacketRPCResponseTypeNull.class), + define_SERVER_(0x0E, SPacketRPCResponseTypeBytes.class), + define_SERVER_(0x0F, SPacketRPCResponseTypeString.class), + define_SERVER_(0x10, SPacketRPCResponseTypeUUID.class), + define_SERVER_(0x11, SPacketRPCResponseTypeCookie.class), + define_SERVER_(0x12, SPacketRPCResponseTypeVoiceStatus.class), + define_SERVER_(0x13, SPacketRPCResponseTypeWebViewStatus.class), + define_SERVER_(0x14, SPacketRPCResponseTypeError.class), + define_CLIENT_(0x15, CPacketRPCSendWebViewMessage.class), + define_SERVER_(0x16, SPacketRPCEventWebViewOpenClose.class), + define_SERVER_(0x17, SPacketRPCEventWebViewMessage.class), + define_SERVER_(0x18, SPacketRPCEventToggledVoice.class), + define_CLIENT_(0x19, CPacketRPCNotifIconRegister.class), + define_CLIENT_(0x1A, CPacketRPCNotifIconRelease.class), + define_CLIENT_(0x1B, CPacketRPCNotifBadgeShow.class), + define_CLIENT_(0x1C, CPacketRPCNotifBadgeHide.class), + define_CLIENT_(0x1D, CPacketRPCSendRawMessage.class) + ); + + public static final String CHANNEL_NAME = "EAG|1.8-RPC"; + public static final String CHANNEL_NAME_READY = "EAG|1.8-Ready"; + + public static final int CLIENT_TO_SERVER = 0; + public static final int SERVER_TO_CLIENT = 1; + + public final int vers; + + private final PacketDef[] idMap = new PacketDef[32]; // May need to grow this in the future + private final Map, PacketDef> classMap = new HashMap<>(); + + private EaglerBackendRPCProtocol(int vers, PacketDef...pkts) { + this.vers = vers; + for(int i = 0; i < pkts.length; ++i) { + PacketDef def = pkts[i]; + if(idMap[def.id] != null) { + throw new IllegalArgumentException("Packet ID " + def.id + " registered twice!"); + } + idMap[def.id] = def; + if(classMap.put(def.pkt, def) != null) { + throw new IllegalArgumentException("Packet class " + def.pkt.getSimpleName() + " registered twice!"); + } + } + } + + private static PacketDef define_CLIENT_(int id, Class pkt) { + return new PacketDef(id, 0, pkt); + } + + private static PacketDef define_SERVER_(int id, Class pkt) { + return new PacketDef(id, 1, pkt); + } + + private static class PacketDef { + + private final int id; + private final int dir; + private final Class pkt; + + private PacketDef(int id, int dir, Class pkt) { + this.id = id; + this.dir = dir; + this.pkt = pkt; + } + + } + + public EaglerBackendRPCPacket readPacket(DataInput buffer, int dir) throws IOException { + int pktId = buffer.readUnsignedByte(); + if(pktId >= idMap.length) { + throw new IOException("Packet ID is out of range: 0x" + Integer.toHexString(pktId)); + } + PacketDef pp = idMap[pktId]; + if(pp == null || pp.dir != dir) { + throw new IOException("Unknown packet ID: 0x" + Integer.toHexString(pktId)); + } + EaglerBackendRPCPacket newPkt; + try { + newPkt = pp.pkt.newInstance(); + }catch(Throwable t) { + throw new RuntimeException("Reflection failed to call packet constructor for \"" + pp.pkt.getSimpleName() + "\"! (is it defined?)", t); + } + newPkt.readPacket(buffer); + return newPkt; + } + + public void writePacket(DataOutput buffer, int dir, EaglerBackendRPCPacket packet) throws IOException { + Class clazz = packet.getClass(); + PacketDef def = classMap.get(clazz); + if(def == null || def.dir != dir) { + throw new IOException("Unknown packet type or wrong direction: " + clazz); + } + buffer.writeByte(def.id); + packet.writePacket(buffer); + } + + public static EaglerBackendRPCProtocol getByID(int id) { + switch(id) { + case 0: return INIT; + case 1: return V1; + default: return null; + } + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/EaglerBackendRPCHandler.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/EaglerBackendRPCHandler.java new file mode 100644 index 0000000..4956d98 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/EaglerBackendRPCHandler.java @@ -0,0 +1,143 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.*; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server.*; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public interface EaglerBackendRPCHandler { + + default void handleClient(CPacketRPCEnabled packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCRequestPlayerInfo packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCSubscribeEvents packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCSetPlayerSkin packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCSetPlayerCape packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCSetPlayerCookie packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCSetPlayerFNAWEn packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCRedirectPlayer packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCResetPlayerMulti packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCSendWebViewMessage packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCSetPauseMenuCustom packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCNotifIconRegister packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCNotifIconRelease packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCNotifBadgeShow packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCNotifBadgeHide packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCDisabled packet) { + throw new WrongRPCPacketException(); + } + + default void handleClient(CPacketRPCSendRawMessage packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCEnabledSuccess packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCEnabledFailure packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCResponseTypeNull packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCResponseTypeBytes packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCResponseTypeString packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCResponseTypeUUID packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCResponseTypeCookie packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCResponseTypeVoiceStatus packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCResponseTypeWebViewStatus packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCResponseTypeError packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCEventWebViewOpenClose packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCEventWebViewMessage packet) { + throw new WrongRPCPacketException(); + } + + default void handleServer(SPacketRPCEventToggledVoice packet) { + throw new WrongRPCPacketException(); + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/EaglerBackendRPCPacket.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/EaglerBackendRPCPacket.java new file mode 100644 index 0000000..2d97b76 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/EaglerBackendRPCPacket.java @@ -0,0 +1,72 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public interface EaglerBackendRPCPacket { + + void readPacket(DataInput buffer) throws IOException; + + void writePacket(DataOutput buffer) throws IOException; + + void handlePacket(EaglerBackendRPCHandler handler); + + int length(); + + public static void writeString(DataOutput buffer, String str, boolean len16, Charset charset) throws IOException { + if(str == null || str.length() == 0) { + if(len16) { + buffer.writeShort(0); + }else { + buffer.writeByte(0); + } + return; + } + byte[] bytes = str.getBytes(charset); + if(bytes.length > (len16 ? 65535 : 255)) { + throw new IOException("String is too long!"); + } + if(len16) { + buffer.writeShort(bytes.length); + }else { + buffer.writeByte(bytes.length); + } + buffer.write(bytes); + } + + public static String readString(DataInput buffer, int maxLen, boolean len16, Charset charset) throws IOException { + int len = len16 ? buffer.readUnsignedShort() : buffer.readUnsignedByte(); + if(len > maxLen) { + throw new IOException("String is too long!"); + } + if(len == 0) { + return ""; + } + byte[] toRead = new byte[len]; + buffer.readFully(toRead); + String ret = new String(toRead, charset); + if(charset != StandardCharsets.US_ASCII && ret.length() > maxLen) { + throw new IOException("String is too long!"); + } + return ret; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/WrongRPCPacketException.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/WrongRPCPacketException.java new file mode 100644 index 0000000..cfb0402 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/WrongRPCPacketException.java @@ -0,0 +1,24 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class WrongRPCPacketException extends RuntimeException { + + public WrongRPCPacketException() { + super("Wrong RPC packet type recieved for the current handler!"); + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCDisabled.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCDisabled.java new file mode 100644 index 0000000..c74f37e --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCDisabled.java @@ -0,0 +1,48 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCDisabled implements EaglerBackendRPCPacket { + + public CPacketRPCDisabled() { + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 0; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCEnabled.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCEnabled.java new file mode 100644 index 0000000..ab44626 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCEnabled.java @@ -0,0 +1,62 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCEnabled implements EaglerBackendRPCPacket { + + public int[] supportedProtocols; + + public CPacketRPCEnabled() { + } + + public CPacketRPCEnabled(int[] supportedProtocols) { + this.supportedProtocols = supportedProtocols; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + supportedProtocols = new int[buffer.readUnsignedShort()]; + for(int i = 0; i < supportedProtocols.length; ++i) { + supportedProtocols[i] = buffer.readUnsignedShort(); + } + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeShort(supportedProtocols.length); + for(int i = 0; i < supportedProtocols.length; ++i) { + buffer.writeShort(supportedProtocols[i]); + } + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 2 + supportedProtocols.length * 2; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifBadgeHide.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifBadgeHide.java new file mode 100644 index 0000000..a74fb1c --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifBadgeHide.java @@ -0,0 +1,58 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.UUID; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCNotifBadgeHide implements EaglerBackendRPCPacket { + + public UUID badgeUUID; + + public CPacketRPCNotifBadgeHide() { + } + + public CPacketRPCNotifBadgeHide(UUID badgeUUID) { + this.badgeUUID = badgeUUID; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + badgeUUID = new UUID(buffer.readLong(), buffer.readLong()); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeLong(badgeUUID.getMostSignificantBits()); + buffer.writeLong(badgeUUID.getLeastSignificantBits()); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 16; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifBadgeShow.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifBadgeShow.java new file mode 100644 index 0000000..79af77f --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifBadgeShow.java @@ -0,0 +1,167 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +import static net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket.readString; +import static net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket.writeString; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCNotifBadgeShow implements EaglerBackendRPCPacket { + + public static enum EnumBadgePriority { + LOW(0), NORMAL(1), HIGHER(2), HIGHEST(3); + + public final int priority; + + private EnumBadgePriority(int priority) { + this.priority = priority; + } + + private static final EnumBadgePriority[] lookup = new EnumBadgePriority[4]; + + public static EnumBadgePriority getByID(int id) { + if(id >= 0 && id < lookup.length) { + return lookup[id]; + }else { + return NORMAL; + } + } + + static { + EnumBadgePriority[] _values = values(); + for(int i = 0; i < _values.length; ++i) { + lookup[_values[i].priority] = _values[i]; + } + } + } + + public UUID badgeUUID; + public String bodyComponent; + public String titleComponent; + public String sourceComponent; + public long originalTimestampSec; + public boolean silent; + public EnumBadgePriority priority; + public UUID mainIconUUID; + public UUID titleIconUUID; + public int hideAfterSec; + public int expireAfterSec; + public int backgroundColor; + public int bodyTxtColor; + public int titleTxtColor; + public int sourceTxtColor; + + public CPacketRPCNotifBadgeShow() { + } + + public CPacketRPCNotifBadgeShow(UUID badgeUUID, String bodyComponent, String titleComponent, String sourceComponent, + long originalTimestampSec, UUID mainIconUUID, UUID titleIconUUID, boolean silent, + EnumBadgePriority priority, int hideAfterSec, int expireAfterSec, int backgroundColor, int bodyTxtColor, + int titleTxtColor, int sourceTxtColor) { + this.badgeUUID = badgeUUID; + this.bodyComponent = bodyComponent; + this.titleComponent = titleComponent; + this.sourceComponent = sourceComponent; + this.originalTimestampSec = originalTimestampSec; + this.mainIconUUID = mainIconUUID; + this.titleIconUUID = titleIconUUID; + this.silent = silent; + this.priority = priority; + this.hideAfterSec = hideAfterSec; + this.expireAfterSec = expireAfterSec; + this.backgroundColor = backgroundColor; + this.bodyTxtColor = bodyTxtColor; + this.titleTxtColor = titleTxtColor; + this.sourceTxtColor = sourceTxtColor; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + badgeUUID = new UUID(buffer.readLong(), buffer.readLong()); + bodyComponent = readString(buffer, 32767, true, StandardCharsets.UTF_8); + titleComponent = readString(buffer, 255, false, StandardCharsets.UTF_8); + sourceComponent = readString(buffer, 255, false, StandardCharsets.UTF_8); + originalTimestampSec = ((long)buffer.readUnsignedShort() << 32l) | ((long)buffer.readInt() & 0xFFFFFFFFl); + int flags = buffer.readUnsignedByte(); + silent = (flags & 1) != 0; + priority = EnumBadgePriority.getByID((flags >>> 1) & 3); + hideAfterSec = buffer.readUnsignedByte(); + expireAfterSec = buffer.readUnsignedShort(); + mainIconUUID = (flags & 8) != 0 ? new UUID(buffer.readLong(), buffer.readLong()) : null; + titleIconUUID = (flags & 16) != 0 ? new UUID(buffer.readLong(), buffer.readLong()) : null; + backgroundColor = (buffer.readUnsignedByte() << 16) | (buffer.readUnsignedByte() << 8) | buffer.readUnsignedByte(); + bodyTxtColor = (buffer.readUnsignedByte() << 16) | (buffer.readUnsignedByte() << 8) | buffer.readUnsignedByte(); + titleTxtColor = (buffer.readUnsignedByte() << 16) | (buffer.readUnsignedByte() << 8) | buffer.readUnsignedByte(); + sourceTxtColor = (buffer.readUnsignedByte() << 16) | (buffer.readUnsignedByte() << 8) | buffer.readUnsignedByte(); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeLong(badgeUUID.getMostSignificantBits()); + buffer.writeLong(badgeUUID.getLeastSignificantBits()); + writeString(buffer, bodyComponent, true, StandardCharsets.UTF_8); + writeString(buffer, titleComponent, false, StandardCharsets.UTF_8); + writeString(buffer, sourceComponent, false, StandardCharsets.UTF_8); + buffer.writeShort((int)((originalTimestampSec >> 32l) & 0xFFFFl)); + buffer.writeInt((int)(originalTimestampSec & 0xFFFFFFFFl)); + int flags = (silent ? 1 : 0); + flags |= ((priority != null ? priority.priority : 1) << 1); + flags |= (mainIconUUID != null ? 8 : 0); + flags |= (titleIconUUID != null ? 16 : 0); + buffer.writeByte(flags); + buffer.writeByte(hideAfterSec); + buffer.writeShort(expireAfterSec); + if(mainIconUUID != null) { + buffer.writeLong(mainIconUUID.getMostSignificantBits()); + buffer.writeLong(mainIconUUID.getLeastSignificantBits()); + } + if(titleIconUUID != null) { + buffer.writeLong(titleIconUUID.getMostSignificantBits()); + buffer.writeLong(titleIconUUID.getLeastSignificantBits()); + } + buffer.writeByte((backgroundColor >>> 16) & 0xFF); + buffer.writeByte((backgroundColor >>> 8) & 0xFF); + buffer.writeByte(backgroundColor & 0xFF); + buffer.writeByte((bodyTxtColor >>> 16) & 0xFF); + buffer.writeByte((bodyTxtColor >>> 8) & 0xFF); + buffer.writeByte(bodyTxtColor & 0xFF); + buffer.writeByte((titleTxtColor >>> 16) & 0xFF); + buffer.writeByte((titleTxtColor >>> 8) & 0xFF); + buffer.writeByte(titleTxtColor & 0xFF); + buffer.writeByte((sourceTxtColor >>> 16) & 0xFF); + buffer.writeByte((sourceTxtColor >>> 8) & 0xFF); + buffer.writeByte(sourceTxtColor & 0xFF); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return -1; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifIconRegister.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifIconRegister.java new file mode 100644 index 0000000..f09fc8f --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifIconRegister.java @@ -0,0 +1,85 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.PacketImageData; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCNotifIconRegister implements EaglerBackendRPCPacket { + + public Map notifIcons; + + public CPacketRPCNotifIconRegister() { + } + + public CPacketRPCNotifIconRegister(Map notifIcons) { + this.notifIcons = notifIcons; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + notifIcons = new HashMap<>(); + int cnt = buffer.readUnsignedByte(); + for(int i = 0; i < cnt; ++i) { + UUID uuid = new UUID(buffer.readLong(), buffer.readLong()); + PacketImageData img = PacketImageData.readRGB16(buffer); + notifIcons.put(uuid, img); + } + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + if(notifIcons != null && !notifIcons.isEmpty()) { + int l = notifIcons.size(); + if(l > 255) { + throw new IOException("Too many notification icons in packet! (Max is 255, got " + l + " total)"); + } + buffer.writeByte(l); + for(Entry etr : notifIcons.entrySet()) { + UUID uuid = etr.getKey(); + buffer.writeLong(uuid.getMostSignificantBits()); + buffer.writeLong(uuid.getLeastSignificantBits()); + PacketImageData.writeRGB16(buffer, etr.getValue()); + } + }else { + buffer.writeByte(0); + } + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + int i = 1 + (notifIcons.size() << 4); + for(PacketImageData dat : notifIcons.values()) { + i += dat.getByteLengthRGB16(); + } + return i; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifIconRelease.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifIconRelease.java new file mode 100644 index 0000000..7f57289 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCNotifIconRelease.java @@ -0,0 +1,86 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.RandomAccess; +import java.util.UUID; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCNotifIconRelease implements EaglerBackendRPCPacket { + + public Collection iconsToRelease; + + public CPacketRPCNotifIconRelease() { + } + + public CPacketRPCNotifIconRelease(Collection iconsToRelease) { + this.iconsToRelease = iconsToRelease; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + int cnt = buffer.readUnsignedByte(); + iconsToRelease = new ArrayList<>(cnt); + for(int i = 0; i < cnt; ++i) { + iconsToRelease.add(new UUID(buffer.readLong(), buffer.readLong())); + } + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + if(iconsToRelease != null && !iconsToRelease.isEmpty()) { + int cnt = iconsToRelease.size(); + if(cnt > 255) { + throw new IOException("Too many notification icons in packet! (Max is 255, got " + cnt + " total)"); + } + buffer.writeByte(cnt); + if(iconsToRelease instanceof RandomAccess) { + List vigg = (List)iconsToRelease; + for(int i = 0; i < cnt; ++i) { + UUID uuid = vigg.get(i); + buffer.writeLong(uuid.getMostSignificantBits()); + buffer.writeLong(uuid.getLeastSignificantBits()); + } + }else { + for(UUID uuid : iconsToRelease) { + buffer.writeLong(uuid.getMostSignificantBits()); + buffer.writeLong(uuid.getLeastSignificantBits()); + } + } + }else { + buffer.writeByte(0); + } + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 1 + (iconsToRelease.size() << 4); + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCRedirectPlayer.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCRedirectPlayer.java new file mode 100644 index 0000000..e97042e --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCRedirectPlayer.java @@ -0,0 +1,64 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCRedirectPlayer implements EaglerBackendRPCPacket { + + public String redirectURI; + + public CPacketRPCRedirectPlayer() { + } + + public CPacketRPCRedirectPlayer(String redirectURI) { + this.redirectURI = redirectURI; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + byte[] redirectURIBytes = new byte[buffer.readUnsignedShort()]; + buffer.readFully(redirectURIBytes); + redirectURI = new String(redirectURIBytes, StandardCharsets.US_ASCII); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + if(redirectURI.length() > 65535) { + throw new IOException("Redirect URI is too long!"); + } + byte[] redirectURIBytes = redirectURI.getBytes(StandardCharsets.US_ASCII); + buffer.writeShort(redirectURIBytes.length); + buffer.write(redirectURIBytes); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 2 + redirectURI.length(); + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCRequestPlayerInfo.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCRequestPlayerInfo.java new file mode 100644 index 0000000..e5479e7 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCRequestPlayerInfo.java @@ -0,0 +1,74 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCRequestPlayerInfo implements EaglerBackendRPCPacket { + + public static final int REQUEST_PLAYER_REAL_UUID = 0; + public static final int REQUEST_PLAYER_REAL_IP = 1; + public static final int REQUEST_PLAYER_ORIGIN = 2; + public static final int REQUEST_PLAYER_USER_AGENT = 3; + public static final int REQUEST_PLAYER_SKIN_DATA = 4; + public static final int REQUEST_PLAYER_CAPE_DATA = 5; + public static final int REQUEST_PLAYER_COOKIE = 6; + public static final int REQUEST_PLAYER_CLIENT_BRAND_STR = 7; + public static final int REQUEST_PLAYER_CLIENT_VERSION_STR = 8; + public static final int REQUEST_PLAYER_CLIENT_BRAND_VERSION_STR = 9; + public static final int REQUEST_PLAYER_CLIENT_BRAND_UUID = 10; + public static final int REQUEST_PLAYER_CLIENT_VOICE_STATUS = 11; + public static final int REQUEST_PLAYER_CLIENT_WEBVIEW_STATUS = 12; + + public int requestID; + public int requestType; + + public CPacketRPCRequestPlayerInfo() { + } + + public CPacketRPCRequestPlayerInfo(int requestID, int requestType) { + this.requestID = requestID; + this.requestType = requestType; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + requestID = buffer.readInt(); + requestType = buffer.readUnsignedByte(); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeInt(requestID); + buffer.writeByte(requestType); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 5; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCResetPlayerMulti.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCResetPlayerMulti.java new file mode 100644 index 0000000..32d5b7c --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCResetPlayerMulti.java @@ -0,0 +1,68 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCResetPlayerMulti implements EaglerBackendRPCPacket { + + public boolean resetSkin; + public boolean resetCape; + public boolean resetFNAWForce; + public boolean notifyOtherPlayers; + + public CPacketRPCResetPlayerMulti() { + } + + public CPacketRPCResetPlayerMulti(boolean resetSkin, boolean resetCape, boolean resetFNAWForce, + boolean notifyOtherPlayers) { + this.resetSkin = resetSkin; + this.resetCape = resetCape; + this.resetFNAWForce = resetFNAWForce; + this.notifyOtherPlayers = notifyOtherPlayers; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + int flags = buffer.readUnsignedByte(); + resetSkin = (flags & 1) != 0; + resetCape = (flags & 2) != 0; + resetFNAWForce = (flags & 4) != 0; + notifyOtherPlayers = (flags & 8) != 0; + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeByte((resetSkin ? 1 : 0) | (resetCape ? 2 : 0) | + (resetFNAWForce ? 4 : 0) | (notifyOtherPlayers ? 8 : 0)); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 1; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSendRawMessage.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSendRawMessage.java new file mode 100644 index 0000000..cea5ce4 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSendRawMessage.java @@ -0,0 +1,72 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +import static net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket.readString; +import static net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket.writeString; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCSendRawMessage implements EaglerBackendRPCPacket { + + public String messageChannel; + public byte[] messageData; + + public CPacketRPCSendRawMessage() { + } + + public CPacketRPCSendRawMessage(String messageChannel, byte[] messageData) { + this.messageChannel = messageChannel; + this.messageData = messageData; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + messageChannel = readString(buffer, 32, false, StandardCharsets.US_ASCII); + messageData = new byte[buffer.readUnsignedShort()]; + buffer.readFully(messageData); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + if(messageChannel.length() > 32) { + throw new IOException("Message channel name cannot be longer than 32 chars!"); + } + if(messageData.length > 32720) { + throw new IOException("Message data cannot be longer than 32720 bytes!"); + } + writeString(buffer, messageChannel, false, StandardCharsets.US_ASCII); + buffer.writeShort(messageData.length); + buffer.write(messageData); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 1 + messageChannel.length() + 2 + messageData.length; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSendWebViewMessage.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSendWebViewMessage.java new file mode 100644 index 0000000..e50025c --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSendWebViewMessage.java @@ -0,0 +1,86 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCSendWebViewMessage implements EaglerBackendRPCPacket { + + public static final int MESSAGE_TYPE_STRING = 0; + public static final int MESSAGE_TYPE_BINARY = 1; + + public String channelName; + public int messageType; + public byte[] messageContent; + + public CPacketRPCSendWebViewMessage() { + } + + public CPacketRPCSendWebViewMessage(String channelName, int messageType, byte[] messageContent) { + this.channelName = channelName; + this.messageType = messageType; + this.messageContent = messageContent; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + byte[] nameBytes = new byte[buffer.readUnsignedByte()]; + buffer.readFully(nameBytes); + channelName = new String(nameBytes, StandardCharsets.US_ASCII); + messageType = buffer.readUnsignedByte(); + messageContent = new byte[buffer.readUnsignedShort()]; + buffer.readFully(messageContent); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + if(channelName == null || channelName.length() == 0) { + throw new IOException("Channel name cannot be empty!"); + } + if(channelName.length() > 255) { + throw new IOException("Channel name cannot be more than 255 chars! (got " + channelName.length() + " chars)"); + } + if(messageContent == null) { + throw new IOException("Message contents cannot be null!"); + } + if(messageContent.length > 32720) { + throw new IOException("Message contents cannot be more then 32720 bytes! (got " + messageContent.length + " bytes)"); + } + byte[] nameBytes = channelName.getBytes(StandardCharsets.US_ASCII); + buffer.writeByte(nameBytes.length); + buffer.write(nameBytes); + buffer.writeByte(messageType); + buffer.writeShort(messageContent.length); + buffer.write(messageContent); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 4 + channelName.length() + messageContent.length; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPauseMenuCustom.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPauseMenuCustom.java new file mode 100644 index 0000000..1124cc7 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPauseMenuCustom.java @@ -0,0 +1,217 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util.PacketImageData; + +import static net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket.readString; +import static net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket.writeString; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCSetPauseMenuCustom implements EaglerBackendRPCPacket { + + public static final int SERVER_INFO_MODE_NONE = 0; + public static final int SERVER_INFO_MODE_EXTERNAL_URL = 1; + public static final int SERVER_INFO_MODE_SHOW_EMBED_OVER_HTTP = 2; + public static final int SERVER_INFO_MODE_SHOW_EMBED_OVER_WS = 3; + public static final int SERVER_INFO_MODE_INHERIT_DEFAULT = 4; + + public static final int SERVER_INFO_EMBED_PERMS_JAVASCRIPT = 1; + public static final int SERVER_INFO_EMBED_PERMS_MESSAGE_API = 2; + public static final int SERVER_INFO_EMBED_PERMS_STRICT_CSP = 4; + + public static final int DISCORD_MODE_NONE = 0; + public static final int DISCORD_MODE_INVITE_URL = 1; + public static final int DISCORD_MODE_INHERIT_DEFAULT = 2; + + public int serverInfoMode; + public String serverInfoButtonText; + public String serverInfoURL; + public byte[] serverInfoHash; + public int serverInfoEmbedPerms; + public String serverInfoEmbedTitle; + public int discordButtonMode; + public String discordButtonText; + public String discordInviteURL; + + public Map imageMappings; + public List imageData; + + public CPacketRPCSetPauseMenuCustom() { + } + + public CPacketRPCSetPauseMenuCustom(int serverInfoMode, String serverInfoButtonText, String serverInfoURL, + byte[] serverInfoHash, int serverInfoEmbedPerms, String serverInfoEmbedTitle, int discordButtonMode, + String discordButtonText, String discordInviteURL, Map imageMappings, + List imageData) { + this.serverInfoMode = serverInfoMode; + this.serverInfoButtonText = serverInfoButtonText; + this.serverInfoURL = serverInfoURL; + this.serverInfoHash = serverInfoHash; + this.serverInfoEmbedPerms = serverInfoEmbedPerms; + this.serverInfoEmbedTitle = serverInfoEmbedTitle; + this.discordButtonMode = discordButtonMode; + this.discordButtonText = discordButtonText; + this.discordInviteURL = discordInviteURL; + this.imageMappings = imageMappings; + this.imageData = imageData; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + imageMappings = null; + imageData = null; + int flags = buffer.readUnsignedByte(); + serverInfoMode = (flags & 15); + discordButtonMode = ((flags >> 4) & 15); + switch(serverInfoMode) { + case SERVER_INFO_MODE_EXTERNAL_URL: + serverInfoButtonText = readString(buffer, 127, false, StandardCharsets.UTF_8); + serverInfoURL = readString(buffer, 65535, true, StandardCharsets.US_ASCII); + serverInfoEmbedPerms = 0; + serverInfoHash = null; + break; + case SERVER_INFO_MODE_SHOW_EMBED_OVER_HTTP: + serverInfoButtonText = readString(buffer, 127, false, StandardCharsets.UTF_8); + serverInfoURL = readString(buffer, 65535, true, StandardCharsets.US_ASCII); + serverInfoEmbedPerms = buffer.readUnsignedByte(); + serverInfoHash = null; + serverInfoEmbedTitle = readString(buffer, 127, false, StandardCharsets.UTF_8); + break; + case SERVER_INFO_MODE_SHOW_EMBED_OVER_WS: + serverInfoButtonText = readString(buffer, 127, false, StandardCharsets.UTF_8); + serverInfoURL = null; + serverInfoEmbedPerms = buffer.readUnsignedByte(); + serverInfoHash = new byte[20]; + serverInfoEmbedTitle = readString(buffer, 127, false, StandardCharsets.UTF_8); + buffer.readFully(serverInfoHash); + break; + case SERVER_INFO_MODE_INHERIT_DEFAULT: + default: + serverInfoButtonText = null; + serverInfoURL = null; + serverInfoEmbedPerms = 0; + serverInfoHash = null; + break; + } + if(discordButtonMode == DISCORD_MODE_INVITE_URL) { + discordButtonText = readString(buffer, 127, false, StandardCharsets.UTF_8); + discordInviteURL = readString(buffer, 65535, true, StandardCharsets.US_ASCII); + }else { + discordButtonText = null; + discordInviteURL = null; + } + int mappingsCount = buffer.readUnsignedShort(); + if(mappingsCount > 0) { + imageMappings = new HashMap<>(); + imageData = new ArrayList<>(); + for(int i = 0; i < mappingsCount; ++i) { + imageMappings.put(readString(buffer, 255, false, StandardCharsets.US_ASCII), buffer.readUnsignedShort()); + } + int imageDataCount = buffer.readUnsignedShort(); + for(int i = 0; i < imageDataCount; ++i) { + int w = buffer.readUnsignedByte(); + int h = buffer.readUnsignedByte(); + int pixelCount = w * h; + int[] pixels = new int[pixelCount]; + for(int j = 0, p, pR, pG, pB; j < pixelCount; ++j) { + p = buffer.readUnsignedShort(); + pR = (p >>> 11) & 0x1F; + pG = (p >>> 5) & 0x3F; + pB = p & 0x1F; + if(pR + pG + pB > 0) { + pB = (pB - 1) * 31 / 30; + pixels[j] = 0xFF000000 | (pR << 19) | (pG << 10) | (pB << 3); + }else { + pixels[j] = 0; + } + } + imageData.add(new PacketImageData(w, h, pixels)); + } + } + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeByte(serverInfoMode | (discordButtonMode << 4)); + switch(serverInfoMode) { + case SERVER_INFO_MODE_EXTERNAL_URL: + writeString(buffer, serverInfoButtonText, false, StandardCharsets.UTF_8); + writeString(buffer, serverInfoURL, true, StandardCharsets.US_ASCII); + break; + case SERVER_INFO_MODE_SHOW_EMBED_OVER_HTTP: + writeString(buffer, serverInfoButtonText, false, StandardCharsets.UTF_8); + writeString(buffer, serverInfoURL, true, StandardCharsets.US_ASCII); + buffer.writeByte(serverInfoEmbedPerms); + writeString(buffer, serverInfoEmbedTitle, false, StandardCharsets.UTF_8); + break; + case SERVER_INFO_MODE_SHOW_EMBED_OVER_WS: + writeString(buffer, serverInfoButtonText, false, StandardCharsets.UTF_8); + buffer.writeByte(serverInfoEmbedPerms); + writeString(buffer, serverInfoEmbedTitle, false, StandardCharsets.UTF_8); + if(serverInfoHash.length != 20) { + throw new IOException("Hash must be 20 bytes! (" + serverInfoHash.length + " given)"); + } + buffer.write(serverInfoHash); + break; + case SERVER_INFO_MODE_INHERIT_DEFAULT: + default: + break; + } + if(discordButtonMode == DISCORD_MODE_INVITE_URL) { + writeString(buffer, discordButtonText, false, StandardCharsets.UTF_8); + writeString(buffer, discordInviteURL, true, StandardCharsets.US_ASCII); + } + if(imageMappings != null && !imageMappings.isEmpty()) { + buffer.writeShort(imageMappings.size()); + for(Entry etr : imageMappings.entrySet()) { + writeString(buffer, etr.getKey(), false, StandardCharsets.US_ASCII); + buffer.writeShort(etr.getValue().intValue()); + } + buffer.writeShort(imageData.size()); + for(PacketImageData etr : imageData) { + if(etr.width < 1 || etr.width > 64 || etr.height < 1 || etr.height > 64) { + throw new IOException("Invalid image dimensions in packet, must be between 1x1 and 64x64, got " + etr.width + "x" + etr.height); + } + PacketImageData.writeRGB16(buffer, etr); + } + }else { + buffer.writeByte(0); + } + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return -1; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerCape.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerCape.java new file mode 100644 index 0000000..3b6628e --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerCape.java @@ -0,0 +1,65 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCSetPlayerCape implements EaglerBackendRPCPacket { + + public boolean notifyOthers; + public byte[] capePacket; + + public CPacketRPCSetPlayerCape() { + } + + public CPacketRPCSetPlayerCape(boolean notifyOthers, byte[] capePacket) { + this.notifyOthers = notifyOthers; + this.capePacket = capePacket; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + notifyOthers = buffer.readBoolean(); + capePacket = new byte[buffer.readUnsignedShort()]; + buffer.readFully(capePacket); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + if(capePacket.length > 32720) { + throw new IOException("Cape data cannot be longer than 32720 bytes!"); + } + buffer.writeBoolean(notifyOthers); + buffer.writeShort(capePacket.length); + buffer.write(capePacket); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 3 + capePacket.length; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerCookie.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerCookie.java new file mode 100644 index 0000000..121d084 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerCookie.java @@ -0,0 +1,83 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCSetPlayerCookie implements EaglerBackendRPCPacket { + + public boolean revokeQuerySupported; + public boolean saveToDisk; + public int expires; + public byte[] cookieData; + + public CPacketRPCSetPlayerCookie() { + } + + public CPacketRPCSetPlayerCookie(boolean revokeQuerySupported, boolean saveToDisk, int expires, + byte[] cookieData) { + this.revokeQuerySupported = revokeQuerySupported; + this.saveToDisk = saveToDisk; + this.expires = expires; + this.cookieData = cookieData; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + int flags = buffer.readUnsignedByte(); + revokeQuerySupported = (flags & 1) == 1; + saveToDisk = (flags & 2) == 2; + expires = buffer.readInt(); + int cookieLen = buffer.readUnsignedByte(); + if(cookieLen > 0) { + cookieData = new byte[cookieLen]; + buffer.readFully(cookieData); + }else { + cookieData = null; + } + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + if(cookieData != null && cookieData.length > 255) { + throw new IOException("Cookie cannot be longer than 255 bytes!"); + } + buffer.writeByte((revokeQuerySupported ? 1 : 0) | (saveToDisk ? 2 : 0)); + buffer.writeInt(expires); + if(cookieData != null) { + buffer.writeByte(cookieData.length); + buffer.write(cookieData); + }else { + buffer.writeByte(0); + } + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 6 + (cookieData != null ? cookieData.length : 0); + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerFNAWEn.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerFNAWEn.java new file mode 100644 index 0000000..70a1346 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerFNAWEn.java @@ -0,0 +1,60 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCSetPlayerFNAWEn implements EaglerBackendRPCPacket { + + public boolean enable; + public boolean force; + + public CPacketRPCSetPlayerFNAWEn() { + } + + public CPacketRPCSetPlayerFNAWEn(boolean enable, boolean force) { + this.enable = enable; + this.force = force; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + int flags = buffer.readUnsignedByte(); + enable = (flags & 1) != 0; + force = (flags & 2) != 0; + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeByte((enable ? 1 : 0) | (force ? 2 : 0)); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 1; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerSkin.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerSkin.java new file mode 100644 index 0000000..57909ba --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSetPlayerSkin.java @@ -0,0 +1,65 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCSetPlayerSkin implements EaglerBackendRPCPacket { + + public boolean notifyOthers; + public byte[] skinPacket; + + public CPacketRPCSetPlayerSkin() { + } + + public CPacketRPCSetPlayerSkin(boolean notifyOthers, byte[] skinPacket) { + this.notifyOthers = notifyOthers; + this.skinPacket = skinPacket; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + notifyOthers = buffer.readBoolean(); + skinPacket = new byte[buffer.readUnsignedShort()]; + buffer.readFully(skinPacket); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + if(skinPacket.length > 32720) { + throw new IOException("Skin data cannot be longer than 32720 bytes!"); + } + buffer.writeBoolean(notifyOthers); + buffer.writeShort(skinPacket.length); + buffer.write(skinPacket); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 3 + skinPacket.length; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSubscribeEvents.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSubscribeEvents.java new file mode 100644 index 0000000..7cab0cf --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/client/CPacketRPCSubscribeEvents.java @@ -0,0 +1,60 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class CPacketRPCSubscribeEvents implements EaglerBackendRPCPacket { + + public static final int SUBSCRIBE_EVENT_WEBVIEW_OPEN_CLOSE = 1; + public static final int SUBSCRIBE_EVENT_WEBVIEW_MESSAGE = 2; + public static final int SUBSCRIBE_EVENT_TOGGLE_VOICE = 4; + + public int eventsToEnable; + + public CPacketRPCSubscribeEvents() { + } + + public CPacketRPCSubscribeEvents(int eventsToEnable) { + this.eventsToEnable = eventsToEnable; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + eventsToEnable = buffer.readUnsignedShort(); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeShort(eventsToEnable); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleClient(this); + } + + @Override + public int length() { + return 2; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEnabledFailure.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEnabledFailure.java new file mode 100644 index 0000000..22f4e0a --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEnabledFailure.java @@ -0,0 +1,62 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCEnabledFailure implements EaglerBackendRPCPacket { + + public static final int FAILURE_CODE_NOT_ENABLED = 0; + public static final int FAILURE_CODE_NOT_EAGLER_PLAYER = 1; + public static final int FAILURE_CODE_OUTDATED_SERVER = 2; + public static final int FAILURE_CODE_OUTDATED_CLIENT = 3; + public static final int FAILURE_CODE_INTERNAL_ERROR = 0xFF; + + public int failureCode; + + public SPacketRPCEnabledFailure() { + } + + public SPacketRPCEnabledFailure(int failureCode) { + this.failureCode = failureCode; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + failureCode = buffer.readUnsignedByte(); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeByte(failureCode); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return 1; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEnabledSuccess.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEnabledSuccess.java new file mode 100644 index 0000000..d60997e --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEnabledSuccess.java @@ -0,0 +1,60 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCEnabledSuccess implements EaglerBackendRPCPacket { + + public int selectedRPCProtocol; + public int playerClientProtocol; + + public SPacketRPCEnabledSuccess() { + } + + public SPacketRPCEnabledSuccess(int selectedRPCProtocol, int playerClientProtocol) { + this.selectedRPCProtocol = selectedRPCProtocol; + this.playerClientProtocol = playerClientProtocol; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + selectedRPCProtocol = buffer.readUnsignedShort(); + playerClientProtocol = buffer.readUnsignedShort(); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeShort(selectedRPCProtocol); + buffer.writeShort(playerClientProtocol); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return 4; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEventToggledVoice.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEventToggledVoice.java new file mode 100644 index 0000000..2d4276d --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEventToggledVoice.java @@ -0,0 +1,64 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCEventToggledVoice implements EaglerBackendRPCPacket { + + public static final int VOICE_STATE_SERVER_DISABLE = 0; + public static final int VOICE_STATE_DISABLED = 1; + public static final int VOICE_STATE_ENABLED = 2; + + public int oldVoiceState; + public int newVoiceState; + + public SPacketRPCEventToggledVoice() { + } + + public SPacketRPCEventToggledVoice(int oldVoiceState, int newVoiceState) { + this.oldVoiceState = oldVoiceState; + this.newVoiceState = newVoiceState; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + int i = buffer.readUnsignedByte(); + oldVoiceState = (i >>> 4) & 15; + newVoiceState = i & 15; + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeByte((oldVoiceState << 4) | newVoiceState); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return 1; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEventWebViewMessage.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEventWebViewMessage.java new file mode 100644 index 0000000..5254134 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEventWebViewMessage.java @@ -0,0 +1,86 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCEventWebViewMessage implements EaglerBackendRPCPacket { + + public static final int MESSAGE_TYPE_STRING = 0; + public static final int MESSAGE_TYPE_BINARY = 1; + + public String channelName; + public int messageType; + public byte[] messageContent; + + public SPacketRPCEventWebViewMessage() { + } + + public SPacketRPCEventWebViewMessage(String channelName, int messageType, byte[] messageContent) { + this.channelName = channelName; + this.messageType = messageType; + this.messageContent = messageContent; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + byte[] nameBytes = new byte[buffer.readUnsignedByte()]; + buffer.readFully(nameBytes); + channelName = new String(nameBytes, StandardCharsets.US_ASCII); + messageType = buffer.readUnsignedByte(); + messageContent = new byte[buffer.readUnsignedShort()]; + buffer.readFully(messageContent); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + if(channelName == null || channelName.length() == 0) { + throw new IOException("Channel name cannot be empty!"); + } + if(channelName.length() > 255) { + throw new IOException("Channel name cannot be more than 255 chars! (got " + channelName.length() + " chars)"); + } + if(messageContent == null) { + throw new IOException("Message contents cannot be null!"); + } + if(messageContent.length > 32720) { + throw new IOException("Message contents cannot be more then 32720 bytes! (got " + messageContent.length + " bytes)"); + } + byte[] nameBytes = channelName.getBytes(StandardCharsets.US_ASCII); + buffer.writeByte(nameBytes.length); + buffer.write(nameBytes); + buffer.writeByte(messageType); + buffer.writeShort(messageContent.length); + buffer.write(messageContent); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return 4 + channelName.length() + messageContent.length; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEventWebViewOpenClose.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEventWebViewOpenClose.java new file mode 100644 index 0000000..7fbc821 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCEventWebViewOpenClose.java @@ -0,0 +1,71 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCEventWebViewOpenClose implements EaglerBackendRPCPacket { + + public boolean channelOpen; + public String channelName; + + public SPacketRPCEventWebViewOpenClose() { + } + + public SPacketRPCEventWebViewOpenClose(boolean channelOpen, String channelName) { + this.channelOpen = channelOpen; + this.channelName = channelName; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + channelOpen = buffer.readBoolean(); + byte[] nameBytes = new byte[buffer.readUnsignedByte()]; + buffer.readFully(nameBytes); + channelName = new String(nameBytes, StandardCharsets.US_ASCII); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + if(channelName == null || channelName.length() == 0) { + throw new IOException("Channel name cannot be empty!"); + } + if(channelName.length() > 255) { + throw new IOException("Channel name cannot be more than 255 chars! (got " + channelName.length() + " chars)"); + } + buffer.writeBoolean(channelOpen); + byte[] nameBytes = channelName.getBytes(StandardCharsets.US_ASCII); + buffer.writeByte(nameBytes.length); + buffer.write(nameBytes); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return 2 + channelName.length(); + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeBytes.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeBytes.java new file mode 100644 index 0000000..7100f74 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeBytes.java @@ -0,0 +1,65 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCResponseTypeBytes implements EaglerBackendRPCPacket { + + public int requestID; + public byte[] response; + + public SPacketRPCResponseTypeBytes() { + } + + public SPacketRPCResponseTypeBytes(int requestID, byte[] response) { + this.requestID = requestID; + this.response = response; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + requestID = buffer.readInt(); + response = new byte[buffer.readUnsignedShort()]; + buffer.readFully(response); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + if(response.length > 32720) { + throw new IOException("Response is too long, max is 32720 bytes! (got " + response.length + " bytes)"); + } + buffer.writeInt(requestID); + buffer.writeShort(response.length); + buffer.write(response); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return 6 + response.length; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeCookie.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeCookie.java new file mode 100644 index 0000000..58f8eef --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeCookie.java @@ -0,0 +1,83 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCResponseTypeCookie implements EaglerBackendRPCPacket { + + public int requestID; + public boolean cookiesEnabled; + public byte[] cookieData; + + public SPacketRPCResponseTypeCookie() { + } + + public SPacketRPCResponseTypeCookie(int requestID, boolean cookiesEnabled, byte[] cookieData) { + this.requestID = requestID; + this.cookiesEnabled = cookiesEnabled; + this.cookieData = cookieData; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + requestID = buffer.readInt(); + int flags = buffer.readUnsignedByte(); + cookiesEnabled = (flags & 1) != 0; + int len = cookiesEnabled ? buffer.readUnsignedByte() : 0; + if(cookiesEnabled && len > 0) { + cookieData = new byte[len]; + buffer.readFully(cookieData); + }else { + cookieData = null; + } + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeInt(requestID); + if(cookiesEnabled) { + buffer.writeByte(1); + if(cookieData != null && cookieData.length > 0) { + if(cookieData.length > 255) { + throw new IOException("Cookie is too long, max is 255 bytes! (got " + cookieData.length + " bytes)"); + } + buffer.writeByte(cookieData.length); + buffer.write(cookieData); + }else { + buffer.writeByte(0); + } + }else { + buffer.writeByte(0); + } + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return cookiesEnabled ? (cookieData != null ? (6 + cookieData.length) : 6) : 5; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeError.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeError.java new file mode 100644 index 0000000..4ed0579 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeError.java @@ -0,0 +1,60 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCResponseTypeError implements EaglerBackendRPCPacket { + + public int requestID; + public String errorMessage; + + public SPacketRPCResponseTypeError() { + } + + public SPacketRPCResponseTypeError(int requestID, String errorMessage) { + this.requestID = requestID; + this.errorMessage = errorMessage; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + requestID = buffer.readInt(); + errorMessage = buffer.readUTF(); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeInt(requestID); + buffer.writeUTF(errorMessage); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return -1; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeNull.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeNull.java new file mode 100644 index 0000000..bb17b8c --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeNull.java @@ -0,0 +1,56 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCResponseTypeNull implements EaglerBackendRPCPacket { + + public int requestID; + + public SPacketRPCResponseTypeNull() { + } + + public SPacketRPCResponseTypeNull(int requestID) { + this.requestID = requestID; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + requestID = buffer.readInt(); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeInt(requestID); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return 4; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeString.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeString.java new file mode 100644 index 0000000..e6e963e --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeString.java @@ -0,0 +1,68 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCResponseTypeString implements EaglerBackendRPCPacket { + + public int requestID; + public String response; + + public SPacketRPCResponseTypeString() { + } + + public SPacketRPCResponseTypeString(int requestID, String response) { + this.requestID = requestID; + this.response = response; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + requestID = buffer.readInt(); + byte[] responseBytes = new byte[buffer.readUnsignedShort()]; + buffer.readFully(responseBytes); + response = new String(responseBytes, StandardCharsets.UTF_8); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + byte[] responseBytes = response.getBytes(StandardCharsets.UTF_8); + if(responseBytes.length > 32720) { + throw new IOException("Response is too long, max is 32720 bytes! (got " + responseBytes.length + " bytes)"); + } + buffer.writeInt(requestID); + buffer.writeShort(responseBytes.length); + buffer.write(responseBytes); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return -1; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeUUID.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeUUID.java new file mode 100644 index 0000000..3e9aa9d --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeUUID.java @@ -0,0 +1,62 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.UUID; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCResponseTypeUUID implements EaglerBackendRPCPacket { + + public int requestID; + public UUID uuid; + + public SPacketRPCResponseTypeUUID() { + } + + public SPacketRPCResponseTypeUUID(int requestID, UUID uuid) { + this.requestID = requestID; + this.uuid = uuid; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + requestID = buffer.readInt(); + uuid = new UUID(buffer.readLong(), buffer.readLong()); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeInt(requestID); + buffer.writeLong(uuid.getMostSignificantBits()); + buffer.writeLong(uuid.getLeastSignificantBits()); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return 20; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeVoiceStatus.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeVoiceStatus.java new file mode 100644 index 0000000..11a44b6 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeVoiceStatus.java @@ -0,0 +1,64 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCResponseTypeVoiceStatus implements EaglerBackendRPCPacket { + + public static final int VOICE_STATE_SERVER_DISABLE = 0; + public static final int VOICE_STATE_DISABLED = 1; + public static final int VOICE_STATE_ENABLED = 2; + + public int requestID; + public int voiceState; + + public SPacketRPCResponseTypeVoiceStatus() { + } + + public SPacketRPCResponseTypeVoiceStatus(int requestID, int voiceState) { + this.requestID = requestID; + this.voiceState = voiceState; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + requestID = buffer.readInt(); + voiceState = buffer.readUnsignedByte(); + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeInt(requestID); + buffer.writeByte(voiceState); + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return 5; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeWebViewStatus.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeWebViewStatus.java new file mode 100644 index 0000000..d8be128 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/pkt/server/SPacketRPCResponseTypeWebViewStatus.java @@ -0,0 +1,81 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.server; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.EaglerBackendRPCPacket; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SPacketRPCResponseTypeWebViewStatus implements EaglerBackendRPCPacket { + + public static final int WEBVIEW_STATE_NOT_SUPPORTED = 0; + public static final int WEBVIEW_STATE_SERVER_DISABLE = 1; + public static final int WEBVIEW_STATE_CHANNEL_CLOSED = 2; + public static final int WEBVIEW_STATE_CHANNEL_OPEN = 3; + + public int requestID; + public int webviewState; + public String channelName; + + public SPacketRPCResponseTypeWebViewStatus() { + } + + public SPacketRPCResponseTypeWebViewStatus(int requestID, int webviewState, String channelName) { + this.requestID = requestID; + this.webviewState = webviewState; + this.channelName = channelName; + } + + @Override + public void readPacket(DataInput buffer) throws IOException { + requestID = buffer.readInt(); + webviewState = buffer.readUnsignedByte(); + if(webviewState == WEBVIEW_STATE_CHANNEL_OPEN) { + byte[] nameBytes = new byte[buffer.readUnsignedByte()]; + buffer.readFully(nameBytes); + channelName = new String(nameBytes, StandardCharsets.US_ASCII); + } + } + + @Override + public void writePacket(DataOutput buffer) throws IOException { + buffer.writeInt(requestID); + buffer.writeByte(webviewState); + if(webviewState == WEBVIEW_STATE_CHANNEL_OPEN) { + if(channelName.length() > 255) { + throw new IOException("Channel name cannot be more than 255 chars! (got " + channelName.length() + " chars)"); + } + byte[] nameBytes = channelName.getBytes(StandardCharsets.US_ASCII); + buffer.writeByte(nameBytes.length); + buffer.write(nameBytes); + } + } + + @Override + public void handlePacket(EaglerBackendRPCHandler handler) { + handler.handleServer(this); + } + + @Override + public int length() { + return webviewState == WEBVIEW_STATE_CHANNEL_OPEN ? (6 + channelName.length()) : 5; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/util/NotificationBadgeBuilder.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/util/NotificationBadgeBuilder.java new file mode 100644 index 0000000..08dc1d5 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/util/NotificationBadgeBuilder.java @@ -0,0 +1,372 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util; + +import java.util.UUID; + +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.CPacketRPCNotifBadgeShow; +import net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.pkt.client.CPacketRPCNotifBadgeShow.EnumBadgePriority; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.chat.ComponentSerializer; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class NotificationBadgeBuilder { + + public static enum BadgePriority { + LOW, NORMAL, HIGHER, HIGHEST; + } + + private UUID badgeUUID = null; + private BaseComponent bodyComponent = null; + private BaseComponent titleComponent = null; + private BaseComponent sourceComponent = null; + private long originalTimestampSec = 0l; + private boolean silent = false; + private BadgePriority priority = BadgePriority.NORMAL; + private UUID mainIconUUID = null; + private UUID titleIconUUID = null; + private int hideAfterSec = 10; + private int expireAfterSec = 3600; + private int backgroundColor = 0xFFFFFF; + private int bodyTxtColor = 0xFFFFFF; + private int titleTxtColor = 0xFFFFFF; + private int sourceTxtColor = 0xFFFFFF; + + private CPacketRPCNotifBadgeShow packetCache = null; + private boolean packetDirty = true; + + public NotificationBadgeBuilder() { + originalTimestampSec = System.currentTimeMillis() / 1000l; + } + + public NotificationBadgeBuilder(NotificationBadgeBuilder builder) { + badgeUUID = builder.badgeUUID; + bodyComponent = builder.bodyComponent; + titleComponent = builder.titleComponent; + sourceComponent = builder.sourceComponent; + originalTimestampSec = builder.originalTimestampSec; + silent = builder.silent; + priority = builder.priority; + mainIconUUID = builder.mainIconUUID; + titleIconUUID = builder.titleIconUUID; + hideAfterSec = builder.hideAfterSec; + backgroundColor = builder.backgroundColor; + bodyTxtColor = builder.bodyTxtColor; + titleTxtColor = builder.titleTxtColor; + sourceTxtColor = builder.sourceTxtColor; + packetCache = !builder.packetDirty ? builder.packetCache : null; + packetDirty = builder.packetDirty; + } + + private static BaseComponent fixParsedComponent(BaseComponent[] comps) { + if(comps.length == 0) { + return null; + }else if(comps.length == 1) { + return comps[0]; + }else { + TextComponent cmp = new TextComponent(""); + for(int i = 0; i < comps.length; ++i) { + cmp.addExtra(comps[i]); + } + return cmp; + } + } + + public NotificationBadgeBuilder(CPacketRPCNotifBadgeShow packet) { + badgeUUID = packet.badgeUUID; + try { + bodyComponent = fixParsedComponent(ComponentSerializer.parse(packet.bodyComponent)); + }catch(Throwable t) { + bodyComponent = new TextComponent(packet.bodyComponent); + } + try { + titleComponent = fixParsedComponent(ComponentSerializer.parse(packet.titleComponent)); + }catch(Throwable t) { + titleComponent = new TextComponent(packet.titleComponent); + } + try { + sourceComponent = fixParsedComponent(ComponentSerializer.parse(packet.sourceComponent)); + }catch(Throwable t) { + sourceComponent = new TextComponent(packet.sourceComponent); + } + originalTimestampSec = packet.originalTimestampSec; + silent = packet.silent; + switch(packet.priority) { + case LOW: + default: + priority = BadgePriority.LOW; + break; + case NORMAL: + priority = BadgePriority.NORMAL; + break; + case HIGHER: + priority = BadgePriority.HIGHER; + break; + case HIGHEST: + priority = BadgePriority.HIGHEST; + break; + } + mainIconUUID = packet.mainIconUUID; + titleIconUUID = packet.titleIconUUID; + hideAfterSec = packet.hideAfterSec; + backgroundColor = packet.backgroundColor; + bodyTxtColor = packet.bodyTxtColor; + titleTxtColor = packet.titleTxtColor; + sourceTxtColor = packet.sourceTxtColor; + packetCache = packet; + packetDirty = false; + } + + public UUID getBadgeUUID() { + return badgeUUID; + } + + public NotificationBadgeBuilder setBadgeUUID(UUID badgeUUID) { + this.badgeUUID = badgeUUID; + this.packetDirty = true; + return this; + } + + public NotificationBadgeBuilder setBadgeUUIDRandom() { + this.badgeUUID = UUID.randomUUID(); + this.packetDirty = true; + return this; + } + + public BaseComponent getBodyComponent() { + return bodyComponent; + } + + public NotificationBadgeBuilder setBodyComponent(BaseComponent bodyComponent) { + this.bodyComponent = bodyComponent; + this.packetDirty = true; + return this; + } + + public NotificationBadgeBuilder setBodyComponent(String bodyText) { + this.bodyComponent = new TextComponent(bodyText); + this.packetDirty = true; + return this; + } + + public BaseComponent getTitleComponent() { + return titleComponent; + } + + public NotificationBadgeBuilder setTitleComponent(BaseComponent titleComponent) { + this.titleComponent = titleComponent; + this.packetDirty = true; + return this; + } + + public NotificationBadgeBuilder setTitleComponent(String titleText) { + this.titleComponent = new TextComponent(titleText); + this.packetDirty = true; + return this; + } + + public BaseComponent getSourceComponent() { + return sourceComponent; + } + + public NotificationBadgeBuilder setSourceComponent(BaseComponent sourceComponent) { + this.sourceComponent = sourceComponent; + this.packetDirty = true; + return this; + } + + public NotificationBadgeBuilder setSourceComponent(String sourceText) { + this.sourceComponent = new TextComponent(sourceText); + this.packetDirty = true; + return this; + } + + public long getOriginalTimestampSec() { + return originalTimestampSec; + } + + public NotificationBadgeBuilder setOriginalTimestampSec(long originalTimestampSec) { + this.originalTimestampSec = originalTimestampSec; + this.packetDirty = true; + return this; + } + + public boolean isSilent() { + return silent; + } + + public NotificationBadgeBuilder setSilent(boolean silent) { + this.silent = silent; + this.packetDirty = true; + return this; + } + + public BadgePriority getPriority() { + return priority; + } + + public NotificationBadgeBuilder setPriority(BadgePriority priority) { + this.priority = priority; + this.packetDirty = true; + return this; + } + + public UUID getMainIconUUID() { + return mainIconUUID; + } + + public NotificationBadgeBuilder setMainIconUUID(UUID mainIconUUID) { + this.mainIconUUID = mainIconUUID; + this.packetDirty = true; + return this; + } + + public UUID getTitleIconUUID() { + return titleIconUUID; + } + + public NotificationBadgeBuilder setTitleIconUUID(UUID titleIconUUID) { + this.titleIconUUID = titleIconUUID; + this.packetDirty = true; + return this; + } + + public int getHideAfterSec() { + return hideAfterSec; + } + + public NotificationBadgeBuilder setHideAfterSec(int hideAfterSec) { + this.hideAfterSec = hideAfterSec; + this.packetDirty = true; + return this; + } + + public int getExpireAfterSec() { + return expireAfterSec; + } + + public NotificationBadgeBuilder setExpireAfterSec(int expireAfterSec) { + this.expireAfterSec = expireAfterSec; + this.packetDirty = true; + return this; + } + + public int getBackgroundColor() { + return backgroundColor; + } + + public NotificationBadgeBuilder setBackgroundColor(int backgroundColor) { + this.backgroundColor = backgroundColor; + this.packetDirty = true; + return this; + } + + public int getBodyTxtColorRGB() { + return bodyTxtColor; + } + + public NotificationBadgeBuilder setBodyTxtColorRGB(int colorRGB) { + this.bodyTxtColor = colorRGB; + this.packetDirty = true; + return this; + } + + public NotificationBadgeBuilder setBodyTxtColorRGB(int colorR, int colorG, int colorB) { + this.bodyTxtColor = (colorR << 16) | (colorG << 8) | colorB; + this.packetDirty = true; + return this; + } + + public int getTitleTxtColorRGB() { + return titleTxtColor; + } + + public NotificationBadgeBuilder setTitleTxtColorRGB(int colorRGB) { + this.titleTxtColor = colorRGB; + this.packetDirty = true; + return this; + } + + public NotificationBadgeBuilder setTitleTxtColorRGB(int colorR, int colorG, int colorB) { + this.titleTxtColor = (colorR << 16) | (colorG << 8) | colorB; + this.packetDirty = true; + return this; + } + + public int getSourceTxtColorRGB() { + return sourceTxtColor; + } + + public NotificationBadgeBuilder setSourceTxtColorRGB(int colorRGB) { + this.sourceTxtColor = colorRGB; + this.packetDirty = true; + return this; + } + + public NotificationBadgeBuilder setSourceTxtColorRGB(int colorR, int colorG, int colorB) { + this.sourceTxtColor = (colorR << 16) | (colorG << 8) | colorB; + this.packetDirty = true; + return this; + } + + public Object clone() { + return new NotificationBadgeBuilder(this); + } + + public CPacketRPCNotifBadgeShow buildPacket() { + if(packetDirty || packetCache == null) { + if(badgeUUID == null) { + badgeUUID = UUID.randomUUID(); + }else if(badgeUUID.getMostSignificantBits() == 0l && badgeUUID.getLeastSignificantBits() == 0l) { + throw new IllegalStateException("Badge UUID cannot be 0!"); + } + EnumBadgePriority internalPriority; + switch(priority) { + case LOW: + default: + internalPriority = EnumBadgePriority.LOW; + break; + case NORMAL: + internalPriority = EnumBadgePriority.NORMAL; + break; + case HIGHER: + internalPriority = EnumBadgePriority.HIGHER; + break; + case HIGHEST: + internalPriority = EnumBadgePriority.HIGHEST; + break; + } + String bodyComp = bodyComponent != null ? ComponentSerializer.toString(bodyComponent) : ""; + if(bodyComp.length() > 32767) { + throw new IllegalStateException("Body component is longer than 32767 chars serialized!"); + } + String titleComp = titleComponent != null ? ComponentSerializer.toString(titleComponent) : ""; + if(titleComp.length() > 255) { + throw new IllegalStateException("Title component is longer than 255 chars serialized!"); + } + String sourceComp = sourceComponent != null ? ComponentSerializer.toString(sourceComponent) : ""; + if(sourceComp.length() > 255) { + throw new IllegalStateException("Body component is longer than 255 chars serialized!"); + } + packetCache = new CPacketRPCNotifBadgeShow(badgeUUID, bodyComp, titleComp, sourceComp, originalTimestampSec, + mainIconUUID, titleIconUUID, silent, internalPriority, hideAfterSec, expireAfterSec, + backgroundColor, bodyTxtColor, titleTxtColor, sourceTxtColor); + packetDirty = false; + } + return packetCache; + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/util/PacketImageData.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/util/PacketImageData.java new file mode 100644 index 0000000..a2f7c1d --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/util/PacketImageData.java @@ -0,0 +1,78 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class PacketImageData { + + public final int width; + public final int height; + public final int[] rgba; + + public PacketImageData(int width, int height, int[] rgba) { + this.width = width; + this.height = height; + this.rgba = rgba; + } + + public int getByteLengthRGB16() { + return 2 + (rgba.length << 1); + } + + public static PacketImageData readRGB16(DataInput buffer) throws IOException { + int w = buffer.readUnsignedByte(); + int h = buffer.readUnsignedByte(); + int pixelCount = w * h; + int[] pixels = new int[pixelCount]; + for(int j = 0, p, pR, pG, pB; j < pixelCount; ++j) { + p = buffer.readUnsignedShort(); + pR = (p >>> 11) & 0x1F; + pG = (p >>> 5) & 0x3F; + pB = p & 0x1F; + if(pR + pG + pB > 0) { + pB = (int)((pB - 1) * 8.5f); + pixels[j] = 0xFF000000 | (pR << 19) | (pG << 10) | pB; + }else { + pixels[j] = 0; + } + } + return new PacketImageData(w, h, pixels); + } + + public static void writeRGB16(DataOutput buffer, PacketImageData imageData) throws IOException { + if(imageData.width < 1 || imageData.width > 255 || imageData.height < 1 || imageData.height > 255) { + throw new IOException("Invalid image dimensions in packet, must be between 1x1 and 255x255, got " + imageData.width + "x" + imageData.height); + } + buffer.writeByte(imageData.width); + buffer.writeByte(imageData.height); + int pixelCount = imageData.width * imageData.height; + for(int j = 0, p, pR, pG, pB; j < pixelCount; ++j) { + p = imageData.rgba[j]; + if((p >>> 24) > 0x7F) { + pR = (p >>> 19) & 0x1F; + pG = (p >>> 10) & 0x3F; + pB = (int)((p & 0xFF) * 0.1176471f) + 1; + buffer.writeShort((pR << 11) | (pG << 5) | pB); + }else { + buffer.writeShort(0); + } + } + } + +} diff --git a/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/util/SkinPacketHelper.java b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/util/SkinPacketHelper.java new file mode 100644 index 0000000..632dda1 --- /dev/null +++ b/gateway/backend-rpc-protocol/src/backend-rpc-protocol/java/net/lax1dude/eaglercraft/v1_8/plugin/backend_rpc_protocol/util/SkinPacketHelper.java @@ -0,0 +1,214 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.backend_rpc_protocol.util; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import javax.imageio.ImageIO; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class SkinPacketHelper { + + public static byte[] writePresetSkinPacket(int presetId) { + byte[] tex = new byte[5]; + tex[0] = (byte)1; + tex[1] = (byte)(presetId >>> 24); + tex[2] = (byte)(presetId >>> 16); + tex[3] = (byte)(presetId >>> 8); + tex[4] = (byte)(presetId & 0xFF); + return tex; + } + + public static byte[] loadCustomSkin(File texture64x64) throws IOException { + return loadCustomSkin(ImageIO.read(texture64x64)); + } + + public static byte[] loadCustomSkin(InputStream texture64x64) throws IOException { + return loadCustomSkin(ImageIO.read(texture64x64)); + } + + public static byte[] loadCustomSkin(BufferedImage texture64x64) { + if(texture64x64.getWidth() != 64 || texture64x64.getHeight() != 64) { + throw new IllegalArgumentException("Image is not 64x64!"); + } + byte[] tex = new byte[16384]; + for(int y = 0; y < 64; ++y) { + for(int x = 0; x < 64; ++x) { + int idx = (y << 8) | (x << 2); + int rgba = texture64x64.getRGB(x, y); + tex[idx] = (byte)(rgba >>> 24); + tex[idx + 1] = (byte)(rgba & 0xFF); + tex[idx + 2] = (byte)(rgba >>> 8); + tex[idx + 3] = (byte)(rgba >>> 16); + } + } + return tex; + } + + public static byte[] writeCustomSkinPacket(int modelId, byte[] texture64x64) { + if(texture64x64.length != 16384) { + throw new IllegalArgumentException("Wrong array length for 64x64 RGBA texture!"); + } + byte[] tex = new byte[2 + texture64x64.length]; + tex[0] = (byte)2; + tex[1] = (byte)modelId; + System.arraycopy(texture64x64, 0, tex, 2, texture64x64.length); + return tex; + } + + public static byte[] writeCustomSkinPacket(int modelId, File texture64x64) throws IOException { + return writeCustomSkinPacket(modelId, ImageIO.read(texture64x64)); + } + + public static byte[] writeCustomSkinPacket(int modelId, InputStream texture64x64) throws IOException { + return writeCustomSkinPacket(modelId, ImageIO.read(texture64x64)); + } + + public static byte[] writeCustomSkinPacket(int modelId, BufferedImage texture64x64) { + if(texture64x64.getWidth() != 64 || texture64x64.getHeight() != 64) { + throw new IllegalArgumentException("Image is not 64x64!"); + } + byte[] tex = new byte[16386]; + tex[0] = (byte)2; + tex[1] = (byte)modelId; + for(int y = 0; y < 64; ++y) { + for(int x = 0; x < 64; ++x) { + int idx = (y << 8) | (x << 2); + int rgba = texture64x64.getRGB(x, y); + tex[idx + 2] = (byte)(rgba >>> 24); + tex[idx + 3] = (byte)(rgba & 0xFF); + tex[idx + 4] = (byte)(rgba >>> 8); + tex[idx + 5] = (byte)(rgba >>> 16); + } + } + return tex; + } + + public static byte[] writePresetCapePacket(int presetId) { + byte[] tex = new byte[5]; + tex[0] = (byte)1; + tex[1] = (byte)(presetId >>> 24); + tex[2] = (byte)(presetId >>> 16); + tex[3] = (byte)(presetId >>> 8); + tex[4] = (byte)(presetId & 0xFF); + return tex; + } + + public static byte[] loadCustomCape(File textureNx32) throws IOException { + return loadCustomCape(ImageIO.read(textureNx32)); + } + + public static byte[] loadCustomCape(InputStream textureNx32) throws IOException { + return loadCustomCape(ImageIO.read(textureNx32)); + } + + public static byte[] loadCustomCape(BufferedImage textureNx32) { + if((textureNx32.getWidth() != 32 && textureNx32.getWidth() != 64) || textureNx32.getHeight() != 32) { + throw new IllegalArgumentException("Image is not 32x32 or 64x32!"); + } + byte[] tex = new byte[4096]; + for(int y = 0; y < 32; ++y) { + for(int x = 0; x < 32; ++x) { + int idx = (y << 7) | (x << 2); + int rgba = textureNx32.getRGB(x, y); + tex[idx] = (byte)(rgba >>> 24); + tex[idx + 1] = (byte)(rgba & 0xFF); + tex[idx + 2] = (byte)(rgba >>> 8); + tex[idx + 3] = (byte)(rgba >>> 16); + } + } + return tex; + } + + public static byte[] writeCustomCapePacket(File textureNx32) throws IOException { + return writeCustomCapePacket(ImageIO.read(textureNx32)); + } + + public static byte[] writeCustomCapePacket(InputStream textureNx32) throws IOException { + return writeCustomCapePacket(ImageIO.read(textureNx32)); + } + + public static byte[] writeCustomCapePacket(BufferedImage textureNx32) { + byte[] tex = loadCustomCape(textureNx32); + byte[] ret = new byte[1174]; + ret[0] = (byte)2; + convertCape32x32RGBAto23x17RGB(tex, 0, ret, 1); + return ret; + } + + public static byte[] writeCustomCapePacket(byte[] texture32x32) { + if(texture32x32.length != 4096) { + throw new IllegalArgumentException("Wrong array length for 32x32 RGBA texture!"); + } + byte[] tex = new byte[1174]; + tex[0] = (byte)2; + convertCape32x32RGBAto23x17RGB(texture32x32, 0, tex, 1); + return tex; + } + + public static void convertCape32x32RGBAto23x17RGB(byte[] skinIn, byte[] skinOut) { + convertCape32x32RGBAto23x17RGB(skinIn, 0, skinOut, 0); + } + + public static void convertCape32x32RGBAto23x17RGB(byte[] skinIn, int inOffset, byte[] skinOut, int outOffset) { + int i, j; + for(int y = 0; y < 17; ++y) { + for(int x = 0; x < 22; ++x) { + i = inOffset + ((y * 32 + x) << 2); + j = outOffset + ((y * 23 + x) * 3); + skinOut[j] = skinIn[i + 1]; + skinOut[j + 1] = skinIn[i + 2]; + skinOut[j + 2] = skinIn[i + 3]; + } + } + for(int y = 0; y < 11; ++y) { + i = inOffset + (((y + 11) * 32 + 22) << 2); + j = outOffset + (((y + 6) * 23 + 22) * 3); + skinOut[j] = skinIn[i + 1]; + skinOut[j + 1] = skinIn[i + 2]; + skinOut[j + 2] = skinIn[i + 3]; + } + } + + public static void convertCape23x17RGBto32x32RGBA(byte[] skinIn, byte[] skinOut) { + convertCape23x17RGBto32x32RGBA(skinIn, 0, skinOut, 0); + } + + public static void convertCape23x17RGBto32x32RGBA(byte[] skinIn, int inOffset, byte[] skinOut, int outOffset) { + int i, j; + for(int y = 0; y < 17; ++y) { + for(int x = 0; x < 22; ++x) { + i = outOffset + ((y * 32 + x) << 2); + j = inOffset + ((y * 23 + x) * 3); + skinOut[i] = (byte)0xFF; + skinOut[i + 1] = skinIn[j]; + skinOut[i + 2] = skinIn[j + 1]; + skinOut[i + 3] = skinIn[j + 2]; + } + } + for(int y = 0; y < 11; ++y) { + i = outOffset + (((y + 11) * 32 + 22) << 2); + j = inOffset + (((y + 6) * 23 + 22) * 3); + skinOut[i] = (byte)0xFF; + skinOut[i + 1] = skinIn[j]; + skinOut[i + 2] = skinIn[j + 1]; + skinOut[i + 3] = skinIn[j + 2]; + } + } + +}