From 1c49036e3a5920f075fa4885f54c1f9efee62ef4 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 6 Nov 2022 21:32:55 -0500 Subject: [PATCH 1/2] Proof-of-concept for Geyser-Floodgate merge --- api/base/build.gradle.kts | 7 - .../main/java/org/geysermc/api/Geyser.java | 95 ------------- .../java/org/geysermc/api/GeyserApiBase.java | 130 ------------------ .../geysermc/api/connection/Connection.java | 121 ---------------- .../java/org/geysermc/api/util/InputMode.java | 49 ------- api/geyser/build.gradle.kts | 2 +- bootstrap/bungeecord/build.gradle.kts | 2 + .../bungeecord/BungeeHybridListener.java | 122 ++++++++++++++++ .../bungeecord/GeyserBungeeConfiguration.java | 1 + .../bungeecord/GeyserBungeePlugin.java | 35 +++-- bootstrap/spigot/build.gradle.kts | 3 + .../spigot/GeyserSpigotConfiguration.java | 1 + .../platform/spigot/GeyserSpigotInjector.java | 11 +- .../platform/spigot/GeyserSpigotPlugin.java | 64 +++------ .../spigot/SpigotHybridChannelHandler.java | 88 ++++++++++++ .../standalone/gui/GeyserStandaloneGUI.java | 2 +- build.gradle.kts | 6 +- .../org/geysermc/floodgate/util/DeviceOs.java | 73 ---------- .../geysermc/floodgate/util/InputMode.java | 46 ------- core/build.gradle.kts | 4 + .../org/geysermc/geyser/GeyserBootstrap.java | 17 +++ .../java/org/geysermc/geyser/GeyserImpl.java | 25 ++-- .../configuration/GeyserConfiguration.java | 9 ++ .../GeyserJacksonConfiguration.java | 12 ++ .../org/geysermc/geyser/dump/DumpInfo.java | 6 +- .../geyser/entity/type/FireworkEntity.java | 8 -- .../hybrid/FloodgateHybridProvider.java | 37 +++-- .../geyser/hybrid/HybridProvider.java | 90 ++++++++++++ .../hybrid/IntegratedHybridProvider.java | 37 +++-- .../geyser/hybrid/ProxyHybridProvider.java | 65 ++++----- .../netty/LocalServerChannelWrapper.java | 14 +- .../geyser/network/netty/LocalSession.java | 15 +- .../geyser/session/GeyserSession.java | 22 +-- .../session/auth/BedrockClientData.java | 12 +- ...Uploader.java => BedrockSkinUploader.java} | 19 +-- .../BedrockNetworkStackLatencyTranslator.java | 4 +- core/src/main/resources/config.yml | 6 - gradle.properties | 4 +- gradle/libs.versions.toml | 3 + settings.gradle.kts | 4 +- 40 files changed, 545 insertions(+), 726 deletions(-) delete mode 100644 api/base/build.gradle.kts delete mode 100644 api/base/src/main/java/org/geysermc/api/Geyser.java delete mode 100644 api/base/src/main/java/org/geysermc/api/GeyserApiBase.java delete mode 100644 api/base/src/main/java/org/geysermc/api/connection/Connection.java delete mode 100644 api/base/src/main/java/org/geysermc/api/util/InputMode.java create mode 100644 bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/BungeeHybridListener.java create mode 100644 bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/SpigotHybridChannelHandler.java delete mode 100644 common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java delete mode 100644 common/src/main/java/org/geysermc/floodgate/util/InputMode.java rename api/base/src/main/java/org/geysermc/api/util/UiProfile.java => core/src/main/java/org/geysermc/geyser/hybrid/FloodgateHybridProvider.java (56%) create mode 100644 core/src/main/java/org/geysermc/geyser/hybrid/HybridProvider.java rename common/src/main/java/org/geysermc/floodgate/util/UiProfile.java => core/src/main/java/org/geysermc/geyser/hybrid/IntegratedHybridProvider.java (55%) rename api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java => core/src/main/java/org/geysermc/geyser/hybrid/ProxyHybridProvider.java (53%) rename core/src/main/java/org/geysermc/geyser/skin/{FloodgateSkinUploader.java => BedrockSkinUploader.java} (91%) diff --git a/api/base/build.gradle.kts b/api/base/build.gradle.kts deleted file mode 100644 index 6b6fb8f46..000000000 --- a/api/base/build.gradle.kts +++ /dev/null @@ -1,7 +0,0 @@ -dependencies { - api(libs.cumulus) - api(libs.events) { - exclude(group = "com.google.guava", module = "guava") - exclude(group = "org.lanternpowered", module = "lmbda") - } -} \ No newline at end of file diff --git a/api/base/src/main/java/org/geysermc/api/Geyser.java b/api/base/src/main/java/org/geysermc/api/Geyser.java deleted file mode 100644 index 7543d1661..000000000 --- a/api/base/src/main/java/org/geysermc/api/Geyser.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.api; - -import org.checkerframework.checker.nullness.qual.NonNull; - -/** - * General API class for Geyser. - */ -@NonNull -public class Geyser { - private static GeyserApiBase api; - - /** - * Returns the base api. - * - * @return the base api - */ - @NonNull - public static GeyserApiBase api() { - if (api == null) { - throw new RuntimeException("Api has not been registered yet!"); - } - - return api; - } - - /** - * Returns the api of the given type. - * - * @param apiClass the api class - * @param the type - * @return the api of the given type - */ - @SuppressWarnings("unchecked") - public static T api(@NonNull Class apiClass) { - if (apiClass.isInstance(api)) { - return (T) api; - } - - if (api == null) { - throw new RuntimeException("Api has not been registered yet!"); - } else { - throw new RuntimeException("Api was not an instance of " + apiClass + "! Was " + api.getClass().getCanonicalName()); - } - } - - /** - * Registers the given api type. The api cannot be - * registered if {@link #isRegistered()} is true as - * an api has already been specified. - * - * @param api the api - */ - public static void set(@NonNull GeyserApiBase api) { - if (Geyser.api != null) { - throw new RuntimeException("Cannot redefine already registered api!"); - } - - Geyser.api = api; - } - - /** - * Gets if the api has been registered and - * is ready for usage. - * - * @return if the api has been registered - */ - public static boolean isRegistered() { - return api != null; - } -} diff --git a/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java b/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java deleted file mode 100644 index a845e37fd..000000000 --- a/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.api; - -import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.common.value.qual.IntRange; -import org.geysermc.api.connection.Connection; -import org.geysermc.cumulus.form.Form; -import org.geysermc.cumulus.form.util.FormBuilder; - -import java.util.List; -import java.util.UUID; - -/** - * The base API class. - */ -public interface GeyserApiBase { - /** - * Gets the connection from the given UUID, if applicable. The player must be logged in to the Java server - * for this to return a non-null value. - * - * @param uuid the UUID of the connection - * @return the connection from the given UUID, if applicable - */ - @Nullable - Connection connectionByUuid(@NonNull UUID uuid); - - /** - * Gets the connection from the given XUID, if applicable. This method only works for online connections. - * - * @param xuid the XUID of the session - * @return the connection from the given UUID, if applicable - */ - @Nullable - Connection connectionByXuid(@NonNull String xuid); - - /** - * Method to determine if the given online player is a Bedrock player. - * - * @param uuid the uuid of the online player - * @return true if the given online player is a Bedrock player - */ - boolean isBedrockPlayer(@NonNull UUID uuid); - - /** - * Sends a form to the given connection and opens it. - * - * @param uuid the uuid of the connection to open it on - * @param form the form to send - * @return whether the form was successfully sent - */ - boolean sendForm(@NonNull UUID uuid, @NonNull Form form); - - /** - * Sends a form to the given connection and opens it. - * - * @param uuid the uuid of the connection to open it on - * @param formBuilder the formBuilder to send - * @return whether the form was successfully sent - */ - boolean sendForm(@NonNull UUID uuid, @NonNull FormBuilder formBuilder); - - /** - * Transfer the given connection to a server. A Bedrock player can successfully transfer to the same server they are - * currently playing on. - * - * @param uuid the uuid of the connection - * @param address the address of the server - * @param port the port of the server - * @return true if the transfer was a success - */ - boolean transfer(@NonNull UUID uuid, @NonNull String address, @IntRange(from = 0, to = 65535) int port); - - - /** - * Returns all the online connections. - */ - @NonNull - List onlineConnections(); - - /** - * Returns the amount of online connections. - */ - int onlineConnectionsCount(); - - /** - * Returns the prefix used by Floodgate. Will be null when the auth-type isn't Floodgate. - */ - @MonotonicNonNull - String usernamePrefix(); - - /** - * Returns the major API version. Bumped whenever a significant breaking change or feature addition is added. - */ - default int majorApiVersion() { - return 1; - } - - /** - * Returns the minor API version. May be bumped for new API additions. - */ - default int minorApiVersion() { - return 0; - } -} diff --git a/api/base/src/main/java/org/geysermc/api/connection/Connection.java b/api/base/src/main/java/org/geysermc/api/connection/Connection.java deleted file mode 100644 index 1cd7a9d13..000000000 --- a/api/base/src/main/java/org/geysermc/api/connection/Connection.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.api.connection; - -import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.common.value.qual.IntRange; -import org.geysermc.api.util.BedrockPlatform; -import org.geysermc.api.util.InputMode; -import org.geysermc.api.util.UiProfile; -import org.geysermc.cumulus.form.Form; -import org.geysermc.cumulus.form.util.FormBuilder; - -import java.util.UUID; - -/** - * Represents a player connection. - */ -public interface Connection { - /** - * Returns the bedrock name of the connection. - */ - @NonNull String bedrockUsername(); - - /** - * Returns the java name of the connection. - */ - @MonotonicNonNull - String javaUsername(); - - /** - * Returns the UUID of the connection. - */ - @MonotonicNonNull - UUID javaUuid(); - - /** - * Returns the XUID of the connection. - */ - @NonNull String xuid(); - - /** - * Returns the version of the Bedrock client. - */ - @NonNull String version(); - - /** - * Returns the platform that the connection is playing on. - */ - @NonNull BedrockPlatform platform(); - - /** - * Returns the language code of the connection. - */ - @NonNull String languageCode(); - - /** - * Returns the User Interface Profile of the connection. - */ - @NonNull UiProfile uiProfile(); - - /** - * Returns the Input Mode of the Bedrock client. - */ - @NonNull InputMode inputMode(); - - /** - * Returns whether the connection is linked. - * This will always return false when the auth-type isn't Floodgate. - */ - boolean isLinked(); - - /** - * Sends a form to the connection and opens it. - * - * @param form the form to send - * @return whether the form was successfully sent - */ - boolean sendForm(@NonNull Form form); - - /** - * Sends a form to the connection and opens it. - * - * @param formBuilder the formBuilder to send - * @return whether the form was successfully sent - */ - boolean sendForm(@NonNull FormBuilder formBuilder); - - /** - * Transfer the connection to a server. A Bedrock player can successfully transfer to the same server they are - * currently playing on. - * - * @param address the address of the server - * @param port the port of the server - * @return true if the transfer was a success - */ - boolean transfer(@NonNull String address, @IntRange(from = 0, to = 65535) int port); -} diff --git a/api/base/src/main/java/org/geysermc/api/util/InputMode.java b/api/base/src/main/java/org/geysermc/api/util/InputMode.java deleted file mode 100644 index 70346ffa5..000000000 --- a/api/base/src/main/java/org/geysermc/api/util/InputMode.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.api.util; - -import org.checkerframework.checker.nullness.qual.NonNull; - -public enum InputMode { - UNKNOWN, - KEYBOARD_MOUSE, - TOUCH, - CONTROLLER, - VR; - - private static final InputMode[] VALUES = values(); - - /** - * Get the InputMode from the identifier. - * - * @param id the InputMode identifier - * @return The InputMode or {@link #UNKNOWN} if the mode wasn't found - */ - @NonNull - public static InputMode fromId(int id) { - return VALUES.length > id ? VALUES[id] : VALUES[0]; - } -} \ No newline at end of file diff --git a/api/geyser/build.gradle.kts b/api/geyser/build.gradle.kts index dcde85337..6babe9874 100644 --- a/api/geyser/build.gradle.kts +++ b/api/geyser/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } dependencies { - api(projects.api) + api(libs.baseApi) } publishing { diff --git a/bootstrap/bungeecord/build.gradle.kts b/bootstrap/bungeecord/build.gradle.kts index 3e0e9c147..e95ddd618 100644 --- a/bootstrap/bungeecord/build.gradle.kts +++ b/bootstrap/bungeecord/build.gradle.kts @@ -2,6 +2,8 @@ dependencies { api(projects.core) implementation(libs.adventure.text.serializer.bungeecord) + + implementation("org.geysermc.floodgate", "bungee", "2.2.0-SNAPSHOT") } platformRelocate("net.md_5.bungee.jni") diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/BungeeHybridListener.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/BungeeHybridListener.java new file mode 100644 index 000000000..66fa0a211 --- /dev/null +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/BungeeHybridListener.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.platform.bungeecord; + +import io.netty.channel.Channel; +import net.md_5.bungee.api.connection.PendingConnection; +import net.md_5.bungee.api.event.PreLoginEvent; +import net.md_5.bungee.api.event.ServerConnectEvent; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.connection.InitialHandler; +import net.md_5.bungee.event.EventHandler; +import net.md_5.bungee.event.EventPriority; +import net.md_5.bungee.netty.ChannelWrapper; +import net.md_5.bungee.protocol.packet.Handshake; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.api.connection.Connection; +import org.geysermc.floodgate.player.FloodgatePlayerImpl; +import org.geysermc.floodgate.util.BedrockData; +import org.geysermc.floodgate.util.ReflectionUtils; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.hybrid.IntegratedHybridProvider; +import org.geysermc.geyser.hybrid.ProxyHybridProvider; + +import java.lang.reflect.Field; + +import static com.google.common.base.Preconditions.checkNotNull; + +public final class BungeeHybridListener implements Listener { + // TODO consolidate with Floodgate + private static final Field CHANNEL_WRAPPER; + private static final Field PLAYER_NAME; + + static { + CHANNEL_WRAPPER = + ReflectionUtils.getFieldOfType(InitialHandler.class, ChannelWrapper.class); + checkNotNull(CHANNEL_WRAPPER, "ChannelWrapper field cannot be null"); + + PLAYER_NAME = ReflectionUtils.getField(InitialHandler.class, "name"); + checkNotNull(PLAYER_NAME, "Initial name field cannot be null"); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPreLogin(PreLoginEvent event) { + // well, no reason to check if the player will be kicked anyway + if (event.isCancelled()) { + return; + } + + PendingConnection connection = event.getConnection(); + Connection player = getPlayer(connection); + if (player != null) { + connection.setOnlineMode(false); + connection.setUniqueId(player.javaUuid()); + ReflectionUtils.setValue(connection, PLAYER_NAME, player.javaUsername()); + } + } + + @EventHandler(priority = EventPriority.LOW) + public void onServerConnect(ServerConnectEvent event) { + boolean sendFloodgateData = false; // TODO + if (!sendFloodgateData) { + return; // TODO just don't register event? + } + + PendingConnection connection = event.getPlayer().getPendingConnection(); + Connection player = getPlayer(connection); + if (player != null) { + Handshake handshake = ReflectionUtils.getCastedValue(connection, "handshake"); + BedrockData data = ((FloodgatePlayerImpl) player).toBedrockData(); // FIXME + String encryptedData = ((ProxyHybridProvider) GeyserImpl.getInstance().getHybridProvider()) + .createEncryptedDataString(data); + + String address = handshake.getHost(); + + // our data goes before all the other data + int addressFinished = address.indexOf('\0'); + String originalAddress; + String remaining; + if (addressFinished != -1) { + originalAddress = address.substring(0, addressFinished); + remaining = address.substring(addressFinished); + } else { + originalAddress = address; + remaining = ""; + } + + handshake.setHost(originalAddress + '\0' + encryptedData + remaining); + // Bungeecord will add its data after our data + } + } + + @Nullable + private Connection getPlayer(PendingConnection connection) { + ChannelWrapper wrapper = ReflectionUtils.getCastedValue(connection, CHANNEL_WRAPPER); + Channel channel = wrapper.getHandle(); + + return channel.attr(IntegratedHybridProvider.SESSION_KEY).get(); // TODO re-use Floodgate's attribute key here? + } +} diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeConfiguration.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeConfiguration.java index bc084a34e..3b43f2cb7 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeConfiguration.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeConfiguration.java @@ -40,6 +40,7 @@ public final class GeyserBungeeConfiguration extends GeyserJacksonConfiguration @JsonIgnore private Path floodgateKeyPath; + // TODO remove public void loadFloodgate(GeyserBungeePlugin plugin) { Plugin floodgate = plugin.getProxy().getPluginManager().getPlugin("floodgate"); Path geyserDataFolder = plugin.getDataFolder().toPath(); diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index 1c460f4de..d4fff600e 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -32,6 +32,9 @@ import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.protocol.ProtocolConstants; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.common.PlatformType; +import org.geysermc.floodgate.BungeePlatform; +import org.geysermc.floodgate.pluginmessage.BungeeSkinApplier; +import org.geysermc.floodgate.skin.SkinApplier; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.command.Command; @@ -40,6 +43,8 @@ import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; +import org.geysermc.geyser.hybrid.HybridProvider; +import org.geysermc.geyser.hybrid.ProxyHybridProvider; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandExecutor; @@ -110,12 +115,6 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { @Override public void onEnable() { - // Remove this in like a year - if (getProxy().getPluginManager().getPlugin("floodgate-bungee") != null) { - geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/")); - return; - } - if (getProxy().getConfig().getListeners().size() == 1) { ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0]; @@ -154,16 +153,13 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { } } - if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && getProxy().getPluginManager().getPlugin("floodgate") == null) { - geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); - return; - } else if (geyserConfig.isAutoconfiguredRemote() && getProxy().getPluginManager().getPlugin("floodgate") != null) { - // Floodgate installed means that the user wants Floodgate authentication - geyserLogger.debug("Auto-setting to Floodgate authentication."); - geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE); + if (getProxy().getPluginManager().getPlugin("floodgate") != null) { + geyserLogger.warning("WHY DO YOU HAVE FLOODGATE INSTALLED???1/"); } - geyserConfig.loadFloodgate(this); + if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE) { + getProxy().getPluginManager().registerListener(this, new BungeeHybridListener()); + } // Big hack - Bungee does not provide us an event to listen to, so schedule a repeating // task that waits for a field to be filled which is set after the plugin enable @@ -274,4 +270,15 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { public SocketAddress getSocketAddress() { return this.geyserInjector.getServerSocketAddress(); } + + @Override + public HybridProvider createHybridProvider(GeyserImpl geyser) { + return new ProxyHybridProvider(geyser); + } + + @Override + public SkinApplier createSkinApplier() { + new BungeePlatform(this); // TODO hack to ensure ReflectionUtils prefix is applied and I don't forget about dealing with it + return new BungeeSkinApplier(null); // Also TODO + } } diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index b5ef4e69e..0a30dd1b7 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -18,6 +18,8 @@ dependencies { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) } } + + implementation("org.geysermc.floodgate", "spigot", "2.2.0-SNAPSHOT") } platformRelocate("it.unimi.dsi.fastutil") @@ -30,6 +32,7 @@ platformRelocate("io.netty.channel.kqueue") // These dependencies are already present on the platform provided(libs.viaversion) +provided("com.mojang", "authlib", "1.5.21") application { mainClass.set("org.geysermc.geyser.platform.spigot.GeyserSpigotMain") diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotConfiguration.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotConfiguration.java index 3320ffa65..a4db21371 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotConfiguration.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotConfiguration.java @@ -41,6 +41,7 @@ public final class GeyserSpigotConfiguration extends GeyserJacksonConfiguration @JsonIgnore private Path floodgateKeyPath; + // TODO REMOVE public void loadFloodgate(GeyserSpigotPlugin plugin) { Plugin floodgate = Bukkit.getPluginManager().getPlugin("floodgate"); Path geyserDataFolder = plugin.getDataFolder().toPath(); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java index c1d3b6871..77dfaf4d4 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java @@ -33,6 +33,8 @@ import io.netty.channel.local.LocalAddress; import io.netty.util.concurrent.DefaultThreadFactory; import org.bukkit.Bukkit; import org.geysermc.geyser.GeyserBootstrap; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.network.netty.GeyserInjector; import org.geysermc.geyser.network.netty.LocalServerChannelWrapper; import org.geysermc.geyser.network.netty.LocalSession; @@ -119,6 +121,13 @@ public class GeyserSpigotInjector extends GeyserInjector { @Override protected void initChannel(Channel ch) throws Exception { initChannel.invoke(childHandler, ch); + if (GeyserImpl.getInstance().getConfig().getRemote().authType() == AuthType.FLOODGATE) { + // we have to add the packet blocker in the data handler, otherwise ProtocolSupport breaks + ch.pipeline().addBefore( + "packet_handler", "geyser_data_handler", + new SpigotHybridChannelHandler() + ); + } } }) // Set to MAX_PRIORITY as MultithreadEventLoopGroup#newDefaultThreadFactory which DefaultEventLoopGroup implements does by default @@ -170,7 +179,7 @@ public class GeyserSpigotInjector extends GeyserInjector { */ private void workAroundWeirdBug(GeyserBootstrap bootstrap) { MinecraftProtocol protocol = new MinecraftProtocol(); - LocalSession session = new LocalSession(bootstrap.getGeyserConfig().getRemote().address(), + LocalSession session = new LocalSession(null, bootstrap.getGeyserConfig().getRemote().address(), bootstrap.getGeyserConfig().getRemote().port(), this.serverSocketAddress, InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper()); session.connect(); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 5f0061382..64a360a35 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -43,16 +43,20 @@ import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import org.geysermc.common.PlatformType; +import org.geysermc.floodgate.pluginmessage.SpigotSkinApplier; +import org.geysermc.floodgate.skin.SkinApplier; +import org.geysermc.floodgate.util.SpigotVersionSpecificMethods; import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.adapters.spigot.SpigotAdapters; import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.api.extension.Extension; -import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; +import org.geysermc.geyser.hybrid.HybridProvider; +import org.geysermc.geyser.hybrid.IntegratedHybridProvider; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; @@ -62,7 +66,9 @@ import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandExecutor; import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandManager; import org.geysermc.geyser.platform.spigot.world.GeyserPistonListener; import org.geysermc.geyser.platform.spigot.world.GeyserSpigotBlockPlaceListener; -import org.geysermc.geyser.platform.spigot.world.manager.*; +import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotLegacyNativeWorldManager; +import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotNativeWorldManager; +import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; @@ -163,13 +169,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { return; } - // Remove this in like a year - if (Bukkit.getPluginManager().getPlugin("floodgate-bukkit") != null) { - geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", Constants.FLOODGATE_DOWNLOAD_LOCATION)); - this.getPluginLoader().disablePlugin(this); - return; - } - // By default this should be localhost but may need to be changed in some circumstances if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) { geyserConfig.setAutoconfiguredRemote(true); @@ -184,17 +183,10 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserConfig.getBedrock().setPort(Bukkit.getPort()); } - if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && Bukkit.getPluginManager().getPlugin("floodgate") == null) { - geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); - this.getPluginLoader().disablePlugin(this); - } else if (geyserConfig.isAutoconfiguredRemote() && Bukkit.getPluginManager().getPlugin("floodgate") != null) { - // Floodgate installed means that the user wants Floodgate authentication - geyserLogger.debug("Auto-setting to Floodgate authentication."); - geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE); + if (Bukkit.getPluginManager().getPlugin("floodgate") != null) { + geyserLogger.severe("WHY DO YOU HAVE FLOODGATE INSTALLED!!!!!!! REMOVE IT!!!!"); } - geyserConfig.loadFloodgate(this); - if (!INITIALIZED) { // Needs to be an anonymous inner class otherwise Bukkit complains about missing classes Bukkit.getPluginManager().registerEvents(new Listener() { @@ -431,38 +423,14 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { return this.geyserInjector.getServerSocketAddress(); } - public boolean isCompatible(String version, String whichVersion) { - int[] currentVersion = parseVersion(version); - int[] otherVersion = parseVersion(whichVersion); - int length = Math.max(currentVersion.length, otherVersion.length); - for (int index = 0; index < length; index = index + 1) { - int self = (index < currentVersion.length) ? currentVersion[index] : 0; - int other = (index < otherVersion.length) ? otherVersion[index] : 0; - - if (self != other) { - return (self - other) > 0; - } - } - return true; + @Override + public HybridProvider createHybridProvider(GeyserImpl geyser) { + return new IntegratedHybridProvider(geyser); } - private int[] parseVersion(String versionParam) { - versionParam = (versionParam == null) ? "" : versionParam; - if (versionParam.contains("(MC: ")) { - versionParam = versionParam.split("\\(MC: ")[1]; - versionParam = versionParam.split("\\)")[0]; - } - String[] stringArray = versionParam.split("[_.-]"); - int[] temp = new int[stringArray.length]; - for (int index = 0; index <= (stringArray.length - 1); index = index + 1) { - String t = stringArray[index].replaceAll("\\D", ""); - try { - temp[index] = Integer.parseInt(t); - } catch (NumberFormatException ex) { - temp[index] = 0; - } - } - return temp; + @Override + public SkinApplier createSkinApplier() { + return new SpigotSkinApplier(new SpigotVersionSpecificMethods(this), this); } /** diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/SpigotHybridChannelHandler.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/SpigotHybridChannelHandler.java new file mode 100644 index 000000000..acfd30f40 --- /dev/null +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/SpigotHybridChannelHandler.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.platform.spigot; + +import com.mojang.authlib.GameProfile; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import org.geysermc.floodgate.util.ClassNames; +import org.geysermc.geyser.hybrid.IntegratedHybridProvider; +import org.geysermc.geyser.session.GeyserSession; + +import javax.annotation.Nonnull; + +import static org.geysermc.floodgate.util.ReflectionUtils.setValue; + +@ChannelHandler.Sharable +public final class SpigotHybridChannelHandler extends ChannelInboundHandlerAdapter { + + @Override + public void channelRead(@Nonnull ChannelHandlerContext ctx, @Nonnull Object packet) throws Exception { + GeyserSession session = ctx.channel().attr(IntegratedHybridProvider.SESSION_KEY).get(); + // TODO generify this code within Floodgate + if (ClassNames.LOGIN_START_PACKET.isInstance(packet)) { + Object networkManager = ctx.channel().pipeline().get("packet_handler"); + Object packetListener = ClassNames.PACKET_LISTENER.get(networkManager); + + setValue(networkManager, "spoofedUUID", session.javaUuid()); + + // check if the server is actually in the Login state + if (!ClassNames.LOGIN_LISTENER.isInstance(packetListener)) { + // player is not in the login state, abort + + // I would've liked to close the channel for security reasons, but our big friend + // ProtocolSupport, who likes to break things, doesn't work otherwise + ctx.pipeline().remove(this); + return; + } + + // set the player his GameProfile, we can't change the username without this + GameProfile gameProfile = new GameProfile( + // TODO testing only + session.javaUuid(), session.javaUsername() + ); + setValue(packetListener, ClassNames.LOGIN_PROFILE, gameProfile); + + // we have to fake the offline player (login) cycle + // just like on Spigot: + + // LoginListener#initUUID + // new LoginHandler().fireEvents(); + + // and the tick of LoginListener will do the rest + + ClassNames.INIT_UUID.invoke(packetListener); + + Object loginHandler = ClassNames.LOGIN_HANDLER_CONSTRUCTOR.newInstance(packetListener); + ClassNames.FIRE_LOGIN_EVENTS.invoke(loginHandler); + + ctx.pipeline().remove(this); + return; + } + ctx.fireChannelRead(packet); + } +} diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java index 41cbafb25..fed2f5a08 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java @@ -310,7 +310,7 @@ public class GeyserStandaloneGUI { for (GeyserSession player : GeyserImpl.getInstance().getSessionManager().getSessions().values()) { Vector row = new Vector<>(); - row.add(player.getSocketAddress().getHostName()); + row.add(player.socketAddress().getHostName()); row.add(player.getPlayerEntity().getUsername()); playerTableModel.addRow(row); diff --git a/build.gradle.kts b/build.gradle.kts index 06c2e987b..626f34224 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { allprojects { group = "org.geysermc" - version = "2.1.0-SNAPSHOT" + version = "3.0.0-SNAPSHOT" description = "Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers." tasks.withType { @@ -23,8 +23,6 @@ val platforms = setOf( projects.velocity ).map { it.dependencyProject } -val api: Project = projects.api.dependencyProject - subprojects { apply { plugin("java-library") @@ -40,7 +38,7 @@ subprojects { group = rootProject.group as String + ".geyser" when (this) { in platforms -> plugins.apply("geyser.platform-conventions") - api -> plugins.apply("geyser.publish-conventions") + //api -> plugins.apply("geyser.publish-conventions") FIXME else -> plugins.apply("geyser.base-conventions") } } diff --git a/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java b/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java deleted file mode 100644 index 406204759..000000000 --- a/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.floodgate.util; - -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; - -/** - * The Operation Systems where Bedrock players can connect with - */ -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) -public enum DeviceOs { - UNKNOWN("Unknown"), - GOOGLE("Android"), - IOS("iOS"), - OSX("macOS"), - AMAZON("Amazon"), - GEARVR("Gear VR"), - HOLOLENS("Hololens"), - UWP("Windows"), - WIN32("Windows x86"), - DEDICATED("Dedicated"), - TVOS("Apple TV"), - PS4("PS4"), - NX("Switch"), - XBOX("Xbox One"), - WINDOWS_PHONE("Windows Phone"); - - private static final DeviceOs[] VALUES = values(); - - private final String displayName; - - /** - * Get the DeviceOs instance from the identifier. - * - * @param id the DeviceOs identifier - * @return The DeviceOs or {@link #UNKNOWN} if the DeviceOs wasn't found - */ - public static DeviceOs fromId(int id) { - return id < VALUES.length ? VALUES[id] : VALUES[0]; - } - - /** - * @return friendly display name of platform. - */ - @Override - public String toString() { - return displayName; - } -} \ No newline at end of file diff --git a/common/src/main/java/org/geysermc/floodgate/util/InputMode.java b/common/src/main/java/org/geysermc/floodgate/util/InputMode.java deleted file mode 100644 index 2bcfb88fb..000000000 --- a/common/src/main/java/org/geysermc/floodgate/util/InputMode.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.floodgate.util; - -public enum InputMode { - UNKNOWN, - KEYBOARD_MOUSE, - TOUCH, - CONTROLLER, - VR; - - private static final InputMode[] VALUES = values(); - - /** - * Get the InputMode instance from the identifier. - * - * @param id the InputMode identifier - * @return The InputMode or {@link #UNKNOWN} if the DeviceOs wasn't found - */ - public static InputMode fromId(int id) { - return VALUES.length > id ? VALUES[id] : VALUES[0]; - } -} \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 994325ea0..2a17de51a 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -60,6 +60,10 @@ dependencies { compileOnly(projects.ap) annotationProcessor(projects.ap) + + implementation("org.geysermc.floodgate", "core", "2.2.0-SNAPSHOT") { + exclude("org.geysermc", "api") + } } configurations.api { diff --git a/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java b/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java index 261c7416b..2d0674db0 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java @@ -25,9 +25,12 @@ package org.geysermc.geyser; +import org.geysermc.floodgate.skin.SkinApplier; import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; +import org.geysermc.geyser.hybrid.FloodgateHybridProvider; +import org.geysermc.geyser.hybrid.HybridProvider; import org.geysermc.geyser.level.GeyserWorldManager; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.ping.IGeyserPingPassthrough; @@ -134,6 +137,20 @@ public interface GeyserBootstrap { return Paths.get("logs/latest.log"); } + /** + * Creates the hybrid provider for this platform. The provider will differ based on server access. + */ + default HybridProvider createHybridProvider(GeyserImpl geyser) { + return new FloodgateHybridProvider(geyser); + } + + /** + * Returns the skin applier for this platform, if the hybrid provider is integrated with the system. + */ + default SkinApplier createSkinApplier() { + throw new IllegalStateException(); + } + /** * Get an InputStream for the given resource path. * Overridden on platforms that have different class loader properties. diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index a10e54f90..8edae903e 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -50,10 +50,8 @@ import org.geysermc.api.Geyser; import org.geysermc.common.PlatformType; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; -import org.geysermc.floodgate.crypto.AesCipher; -import org.geysermc.floodgate.crypto.AesKeyProducer; -import org.geysermc.floodgate.crypto.Base64Topping; -import org.geysermc.floodgate.crypto.FloodgateCipher; +import org.geysermc.floodgate.api.InstanceHolder; +import org.geysermc.floodgate.api.impl.FloodgateApiWrapper; import org.geysermc.floodgate.news.NewsItemAction; import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.event.EventBus; @@ -69,6 +67,7 @@ import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.event.GeyserEventBus; import org.geysermc.geyser.extension.GeyserExtensionManager; +import org.geysermc.geyser.hybrid.HybridProvider; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.network.ConnectorServerEventHandler; import org.geysermc.geyser.pack.ResourcePack; @@ -78,7 +77,7 @@ import org.geysermc.geyser.scoreboard.ScoreboardUpdater; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.PendingMicrosoftAuthentication; import org.geysermc.geyser.session.SessionManager; -import org.geysermc.geyser.skin.FloodgateSkinUploader; +import org.geysermc.geyser.skin.BedrockSkinUploader; import org.geysermc.geyser.skin.SkinProvider; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; @@ -92,7 +91,6 @@ import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; -import java.security.Key; import java.text.DecimalFormat; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -134,8 +132,8 @@ public class GeyserImpl implements GeyserApi { @Setter private static boolean shouldStartListener = true; - private FloodgateCipher cipher; - private FloodgateSkinUploader skinUploader; + private HybridProvider hybridProvider; + private BedrockSkinUploader skinUploader; private NewsHandler newsHandler; private volatile boolean shuttingDown = false; @@ -161,6 +159,7 @@ public class GeyserImpl implements GeyserApi { instance = this; Geyser.set(this); + InstanceHolder.set(new FloodgateApiWrapper(this), null, null, null, null); // TODO this.platformType = platformType; this.bootstrap = bootstrap; @@ -325,16 +324,14 @@ public class GeyserImpl implements GeyserApi { } if (config.getRemote().authType() == AuthType.FLOODGATE) { + hybridProvider = bootstrap.createHybridProvider(this); try { - Key key = new AesKeyProducer().produceFrom(config.getFloodgateKeyPath()); - cipher = new AesCipher(new Base64Topping()); - cipher.init(key); - logger.debug(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.loaded_key")); // Note: this is positioned after the bind so the skin uploader doesn't try to run if Geyser fails // to load successfully. Spigot complains about class loader if the plugin is disabled. - skinUploader = new FloodgateSkinUploader(this).start(); + // TODO not Floodgate exclusive? + skinUploader = new BedrockSkinUploader(this).start(); } catch (Exception exception) { - logger.severe(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.bad_key"), exception); + logger.severe("Could not start the skin uploader!", exception); } } diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java index 109ad3211..2288a8a3d 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java @@ -46,6 +46,8 @@ public interface GeyserConfiguration { IRemoteConfiguration getRemote(); + HybridInfo getHybridInfo(); + List getSavedUserLogins(); @Deprecated @@ -152,6 +154,13 @@ public interface GeyserConfiguration { } } + // TODO this is definitely temporary + interface HybridInfo { + String usernamePrefix(); + + boolean replaceSpaces(); + } + interface IUserAuthenticationInfo { String getEmail(); diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java index 73e208963..af1d952fe 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -62,6 +62,18 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration private BedrockConfiguration bedrock = new BedrockConfiguration(); private RemoteConfiguration remote = new RemoteConfiguration(); + private HybridInfo hybridInfo = new HybridInfo() { + @Override + public String usernamePrefix() { + return "."; + } + + @Override + public boolean replaceSpaces() { + return true; + } + }; + @JsonProperty("saved-user-logins") private List savedUserLogins = Collections.emptyList(); diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index 5197f2107..f017d9195 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -36,7 +36,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import lombok.AllArgsConstructor; import lombok.Getter; -import org.geysermc.floodgate.util.DeviceOs; +import org.geysermc.api.util.BedrockPlatform; import org.geysermc.floodgate.util.FloodgateInfoHolder; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.GeyserApi; @@ -73,7 +73,7 @@ public class DumpInfo { private final GitInfo gitInfo; private final GeyserConfiguration config; private final Floodgate floodgate; - private final Object2IntMap userPlatforms; + private final Object2IntMap userPlatforms; private final HashInfo hashInfo; private final RamInfo ramInfo; private LogsInfo logsInfo; @@ -121,7 +121,7 @@ public class DumpInfo { this.userPlatforms = new Object2IntOpenHashMap<>(); for (GeyserSession session : GeyserImpl.getInstance().getSessionManager().getAllSessions()) { - DeviceOs device = session.getClientData().getDeviceOs(); + BedrockPlatform device = session.getClientData().getDeviceOs(); userPlatforms.put(device, userPlatforms.getOrDefault(device, 0) + 1); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java index 12498f752..b9443bee7 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java @@ -36,7 +36,6 @@ import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket; -import org.geysermc.floodgate.util.DeviceOs; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.level.FireworkColor; @@ -65,13 +64,6 @@ public class FireworkEntity extends Entity { return; } - // TODO: Remove once Mojang fixes bugs with fireworks crashing clients on these specific devices. - // https://bugs.mojang.com/browse/MCPE-89115 - if (session.getClientData().getDeviceOs() == DeviceOs.XBOX - || session.getClientData().getDeviceOs() == DeviceOs.PS4) { - return; - } - CompoundTag fireworks = tag.get("Fireworks"); if (fireworks == null) { // Thank you Mineplex very cool diff --git a/api/base/src/main/java/org/geysermc/api/util/UiProfile.java b/core/src/main/java/org/geysermc/geyser/hybrid/FloodgateHybridProvider.java similarity index 56% rename from api/base/src/main/java/org/geysermc/api/util/UiProfile.java rename to core/src/main/java/org/geysermc/geyser/hybrid/FloodgateHybridProvider.java index cddb97260..4bf653b77 100644 --- a/api/base/src/main/java/org/geysermc/api/util/UiProfile.java +++ b/core/src/main/java/org/geysermc/geyser/hybrid/FloodgateHybridProvider.java @@ -23,23 +23,32 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.api.util; +package org.geysermc.geyser.hybrid; -import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.floodgate.crypto.FloodgateCipher; +import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.PluginMessageUtils; -public enum UiProfile { - CLASSIC, POCKET; +import java.nio.charset.StandardCharsets; - private static final UiProfile[] VALUES = values(); +public final class FloodgateHybridProvider implements HybridProvider { + private final FloodgateCipher cipher; - /** - * Get the UiProfile from the identifier. - * - * @param id the UiProfile identifier - * @return The UiProfile or {@link #CLASSIC} if the profile wasn't found - */ - @NonNull - public static UiProfile fromId(int id) { - return VALUES.length > id ? VALUES[id] : VALUES[0]; + public FloodgateHybridProvider(GeyserImpl geyser) { + cipher = HybridProvider.getOrCreateKey(geyser); + } + + @Override + public void onSkinUpload(GeyserSession session, String value, String signature) { + byte[] bytes = (value + '\0' + signature) + .getBytes(StandardCharsets.UTF_8); + PluginMessageUtils.sendMessage(session, PluginMessageChannels.SKIN, bytes); + } + + @Override + public FloodgateCipher getCipher() { + return cipher; } } diff --git a/core/src/main/java/org/geysermc/geyser/hybrid/HybridProvider.java b/core/src/main/java/org/geysermc/geyser/hybrid/HybridProvider.java new file mode 100644 index 000000000..493f1e5e4 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/hybrid/HybridProvider.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.hybrid; + +import org.geysermc.floodgate.crypto.AesCipher; +import org.geysermc.floodgate.crypto.AesKeyProducer; +import org.geysermc.floodgate.crypto.Base64Topping; +import org.geysermc.floodgate.crypto.FloodgateCipher; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.configuration.GeyserConfiguration; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.GeyserLocale; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.Key; + +public interface HybridProvider { + void onSkinUpload(GeyserSession session, String value, String signature); + + FloodgateCipher getCipher(); + + static FloodgateCipher getOrCreateKey(GeyserImpl geyser) { + GeyserLogger logger = geyser.getLogger(); + GeyserConfiguration config = geyser.getConfig(); + try { + // TODO make this common code with Floodgate. Like, make sure Geyser's core and Floodgate's core points to the same thing + FloodgateCipher cipher = new AesCipher(new Base64Topping()); + + Path keyPath = config.getFloodgateKeyPath(); + if (!Files.exists(keyPath)) { + generateFloodgateKey(cipher, keyPath); // Should also init the cipher for us. + // TODO good? + logger.info("We just created a Floodgate key at " + keyPath + ". You will need to copy this file into " + + "your Floodgate config folder(s)."); + } else { + Key key = new AesKeyProducer().produceFrom(keyPath); + cipher.init(key); + } + logger.debug(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.loaded_key")); + return cipher; + } catch (Exception exception) { + logger.severe(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.bad_key"), exception); + return null; + } + } + + static void generateFloodgateKey(FloodgateCipher cipher, Path keyPath) throws Exception { + Key key = new AesKeyProducer().produce(); + cipher.init(key); + + String test = "abcdefghijklmnopqrstuvwxyz0123456789"; + byte[] encrypted = cipher.encryptFromString(test); + String decrypted = cipher.decryptToString(encrypted); + + if (!test.equals(decrypted)) { + throw new RuntimeException("Failed to decrypt test message.\n" + + "Original message: " + test + "." + + "Decrypted message: " + decrypted + ".\n" + + "The encrypted message itself: " + new String(encrypted) + ); + } + + Files.write(keyPath, key.getEncoded()); + } +} diff --git a/common/src/main/java/org/geysermc/floodgate/util/UiProfile.java b/core/src/main/java/org/geysermc/geyser/hybrid/IntegratedHybridProvider.java similarity index 55% rename from common/src/main/java/org/geysermc/floodgate/util/UiProfile.java rename to core/src/main/java/org/geysermc/geyser/hybrid/IntegratedHybridProvider.java index d93042277..b31bfd944 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/UiProfile.java +++ b/core/src/main/java/org/geysermc/geyser/hybrid/IntegratedHybridProvider.java @@ -23,21 +23,32 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.floodgate.util; +package org.geysermc.geyser.hybrid; -public enum UiProfile { - CLASSIC, - POCKET; +import io.netty.util.AttributeKey; +import org.geysermc.floodgate.crypto.FloodgateCipher; +import org.geysermc.floodgate.skin.SkinApplier; +import org.geysermc.floodgate.skin.SkinData; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.session.GeyserSession; - private static final UiProfile[] VALUES = values(); +public class IntegratedHybridProvider implements HybridProvider { + // TODO This will probably end up as its own class. + public static final AttributeKey SESSION_KEY = AttributeKey.valueOf("geyser-session"); - /** - * Get the UiProfile instance from the identifier. - * - * @param id the UiProfile identifier - * @return The UiProfile or {@link #CLASSIC} if the UiProfile wasn't found - */ - public static UiProfile fromId(int id) { - return VALUES.length > id ? VALUES[id] : VALUES[0]; + private final SkinApplier skinApplier; + + public IntegratedHybridProvider(GeyserImpl geyser) { + skinApplier = geyser.getBootstrap().createSkinApplier(); + } + + @Override + public void onSkinUpload(GeyserSession session, String value, String signature) { + skinApplier.applySkin(session, new SkinData(value, signature)); + } + + @Override + public FloodgateCipher getCipher() { + throw new UnsupportedOperationException(); } } diff --git a/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java b/core/src/main/java/org/geysermc/geyser/hybrid/ProxyHybridProvider.java similarity index 53% rename from api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java rename to core/src/main/java/org/geysermc/geyser/hybrid/ProxyHybridProvider.java index 15d0da027..101ac8834 100644 --- a/api/base/src/main/java/org/geysermc/api/util/BedrockPlatform.java +++ b/core/src/main/java/org/geysermc/geyser/hybrid/ProxyHybridProvider.java @@ -23,51 +23,38 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.api.util; +package org.geysermc.geyser.hybrid; -import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.floodgate.crypto.FloodgateCipher; +import org.geysermc.floodgate.util.BedrockData; +import org.geysermc.geyser.GeyserImpl; -public enum BedrockPlatform { - UNKNOWN("Unknown"), - GOOGLE("Android"), - IOS("iOS"), - OSX("macOS"), - AMAZON("Amazon"), - GEARVR("Gear VR"), - HOLOLENS("Hololens"), - UWP("Windows"), - WIN32("Windows x86"), - DEDICATED("Dedicated"), - TVOS("Apple TV"), - PS4("PS4"), - NX("Switch"), - XBOX("Xbox One"), - WINDOWS_PHONE("Windows Phone"); +import java.nio.charset.StandardCharsets; - private static final BedrockPlatform[] VALUES = values(); +public final class ProxyHybridProvider extends IntegratedHybridProvider { + private final FloodgateCipher cipher; - private final String displayName; - - BedrockPlatform(String displayName) { - this.displayName = displayName; + public ProxyHybridProvider(GeyserImpl geyser) { + super(geyser); + this.cipher = HybridProvider.getOrCreateKey(geyser); } - /** - * Get the BedrockPlatform from the identifier. - * - * @param id the BedrockPlatform identifier - * @return The BedrockPlatform or {@link #UNKNOWN} if the platform wasn't found - */ - @NonNull - public static BedrockPlatform fromId(int id) { - return id < VALUES.length ? VALUES[id] : VALUES[0]; - } - - /** - * @return friendly display name of platform. - */ @Override - public String toString() { - return displayName; + public FloodgateCipher getCipher() { + return cipher; + } + + // TODO copied from ProxyFloodgateApi + public byte[] createEncryptedData(BedrockData bedrockData) { + try { + return cipher.encryptFromString(bedrockData.toString()); + } catch (Exception exception) { + throw new IllegalStateException("We failed to create the encrypted data, " + + "but creating encrypted data is mandatory!", exception); + } + } + + public String createEncryptedDataString(BedrockData bedrockData) { + return new String(createEncryptedData(bedrockData), StandardCharsets.UTF_8); } } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalServerChannelWrapper.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalServerChannelWrapper.java index bb8ca754f..b91653611 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalServerChannelWrapper.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalServerChannelWrapper.java @@ -27,6 +27,10 @@ package org.geysermc.geyser.network.netty; import io.netty.channel.local.LocalChannel; import io.netty.channel.local.LocalServerChannel; +import io.netty.util.Attribute; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.hybrid.IntegratedHybridProvider; +import org.geysermc.geyser.session.GeyserSession; /** * If the incoming channel if an instance of LocalChannelWithRemoteAddress, this server creates a LocalChannelWrapper @@ -36,9 +40,17 @@ public class LocalServerChannelWrapper extends LocalServerChannel { @Override protected LocalChannel newLocalChannel(LocalChannel peer) { // LocalChannel here should be an instance of LocalChannelWithRemoteAddress, which we can use to set the "remote address" on the other end - if (peer instanceof LocalChannelWithRemoteAddress) { + if (peer instanceof LocalChannelWithRemoteAddress) { // TODO also use attribute for this LocalChannelWrapper channel = new LocalChannelWrapper(this, peer); channel.wrapper().remoteAddress(((LocalChannelWithRemoteAddress) peer).spoofedRemoteAddress()); + + if (GeyserImpl.getInstance().getHybridProvider() instanceof IntegratedHybridProvider) { + Attribute attribute = peer.attr(IntegratedHybridProvider.SESSION_KEY); + GeyserSession session = attribute.get(); + // Garbage collect since it's no longer relevant for the PacketLib side. + attribute.set(null); + channel.attr(IntegratedHybridProvider.SESSION_KEY).set(session); + } return channel; } return super.newLocalChannel(peer); diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index 370604db9..13f30a200 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -36,7 +36,12 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.channel.*; import io.netty.channel.unix.PreferredDirectByteBufAllocator; import io.netty.handler.codec.haproxy.*; +import io.netty.util.Attribute; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.hybrid.IntegratedHybridProvider; +import org.geysermc.geyser.session.GeyserSession; +import javax.annotation.Nullable; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -52,11 +57,14 @@ public final class LocalSession extends TcpSession { private final String clientIp; private final PacketCodecHelper codecHelper; - public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, PacketCodecHelper codecHelper) { + private final GeyserSession session; + + public LocalSession(@Nullable GeyserSession session, String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, PacketCodecHelper codecHelper) { super(host, port, protocol); this.targetAddress = targetAddress; this.clientIp = clientIp; this.codecHelper = codecHelper; + this.session = session; } @Override @@ -88,6 +96,11 @@ public final class LocalSession extends TcpSession { pipeline.addLast("manager", LocalSession.this); addHAProxySupport(pipeline); + + if (GeyserImpl.getInstance().getHybridProvider() instanceof IntegratedHybridProvider) { + Attribute attribute = channel.attr(IntegratedHybridProvider.SESSION_KEY); + attribute.set(session); + } } }).group(DEFAULT_EVENT_LOOP_GROUP).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getConnectTimeout() * 1000); diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 67aedec15..4a8ce0561 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -112,6 +112,8 @@ import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.entity.type.Tickable; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.geyser.hybrid.FloodgateHybridProvider; +import org.geysermc.geyser.hybrid.HybridProvider; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; @@ -128,7 +130,7 @@ import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.auth.AuthData; import org.geysermc.geyser.session.auth.BedrockClientData; import org.geysermc.geyser.session.cache.*; -import org.geysermc.geyser.skin.FloodgateSkinUploader; +import org.geysermc.geyser.skin.BedrockSkinUploader; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.text.TextDecoration; @@ -857,7 +859,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { if (geyser.getBootstrap().getSocketAddress() != null) { // We're going to connect through the JVM and not through TCP - downstream = new LocalSession(this.remoteServer.address(), this.remoteServer.port(), + downstream = new LocalSession(this, this.remoteServer.address(), this.remoteServer.port(), geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), this.protocol, this.protocol.createHelper()); } else { @@ -879,12 +881,13 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { //todo move this somewhere else if (event.getPacket() instanceof ClientIntentionPacket) { String addressSuffix; - if (floodgate) { + HybridProvider provider; + if (floodgate && (provider = geyser.getHybridProvider()) instanceof FloodgateHybridProvider) { byte[] encryptedData; try { - FloodgateSkinUploader skinUploader = geyser.getSkinUploader(); - FloodgateCipher cipher = geyser.getCipher(); + BedrockSkinUploader skinUploader = geyser.getSkinUploader(); + FloodgateCipher cipher = provider.getCipher(); String bedrockAddress = upstream.getAddress().getAddress().getHostAddress(); // both BungeeCord and Velocity remove the IPv6 scope (if there is one) for Spigot @@ -1377,7 +1380,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { upstream.sendPacket(chunkRadiusUpdatedPacket); } - public InetSocketAddress getSocketAddress() { + @Override + public InetSocketAddress socketAddress() { return this.upstream.getAddress(); } @@ -1857,7 +1861,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public @NonNull BedrockPlatform platform() { - return BedrockPlatform.values()[clientData.getDeviceOs().ordinal()]; //todo + return clientData.getDeviceOs(); } @Override @@ -1867,12 +1871,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public @NonNull UiProfile uiProfile() { - return UiProfile.values()[clientData.getUiProfile().ordinal()]; //todo + return clientData.getUiProfile(); } @Override public @NonNull InputMode inputMode() { - return InputMode.values()[clientData.getCurrentInputMode().ordinal()]; //todo + return clientData.getCurrentInputMode(); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/session/auth/BedrockClientData.java b/core/src/main/java/org/geysermc/geyser/session/auth/BedrockClientData.java index 07dd38491..4ce8d555e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/auth/BedrockClientData.java +++ b/core/src/main/java/org/geysermc/geyser/session/auth/BedrockClientData.java @@ -30,9 +30,9 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import lombok.Setter; -import org.geysermc.floodgate.util.DeviceOs; -import org.geysermc.floodgate.util.InputMode; -import org.geysermc.floodgate.util.UiProfile; +import org.geysermc.api.util.BedrockPlatform; +import org.geysermc.api.util.InputMode; +import org.geysermc.api.util.UiProfile; import java.util.UUID; @@ -80,7 +80,7 @@ public final class BedrockClientData { @JsonProperty(value = "DeviceModel") private String deviceModel; @JsonProperty(value = "DeviceOS") - private DeviceOs deviceOs; + private BedrockPlatform deviceOs; @JsonProperty(value = "UIProfile") private UiProfile uiProfile; @JsonProperty(value = "GuiScale") @@ -113,8 +113,8 @@ public final class BedrockClientData { @Setter private String originalString = null; - public DeviceOs getDeviceOs() { - return deviceOs != null ? deviceOs : DeviceOs.UNKNOWN; + public BedrockPlatform getDeviceOs() { + return deviceOs != null ? deviceOs : BedrockPlatform.UNKNOWN; } public InputMode getCurrentInputMode() { diff --git a/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java b/core/src/main/java/org/geysermc/geyser/skin/BedrockSkinUploader.java similarity index 91% rename from core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java rename to core/src/main/java/org/geysermc/geyser/skin/BedrockSkinUploader.java index 7b6dacd16..ac853d82d 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java +++ b/core/src/main/java/org/geysermc/geyser/skin/BedrockSkinUploader.java @@ -30,26 +30,23 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.Getter; -import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.floodgate.util.WebsocketEventType; import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.PluginMessageUtils; import org.java_websocket.client.WebSocketClient; import org.java_websocket.handshake.ServerHandshake; import javax.net.ssl.SSLException; import java.net.ConnectException; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; -public final class FloodgateSkinUploader { +public final class BedrockSkinUploader { private final ObjectMapper JACKSON = new ObjectMapper(); private final List skinQueue = new ArrayList<>(); @@ -59,9 +56,8 @@ public final class FloodgateSkinUploader { @Getter private int id; @Getter private String verifyCode; - @Getter private int subscribersCount; - public FloodgateSkinUploader(GeyserImpl geyser) { + public BedrockSkinUploader(GeyserImpl geyser) { this.logger = geyser.getLogger(); this.client = new WebSocketClient(Constants.GLOBAL_API_WS_URI) { @Override @@ -100,14 +96,11 @@ public final class FloodgateSkinUploader { verifyCode = node.get("verify_code").asText(); break; case SUBSCRIBER_COUNT: - subscribersCount = node.get("subscribers_count").asInt(); + logger.debug("Ignoring subscribers count message."); break; case SKIN_UPLOADED: // if Geyser is the only subscriber we have send it to the server manually // otherwise it's handled by the Floodgate plugin subscribers - if (subscribersCount != 1) { - break; - } String xuid = node.get("xuid").asText(); GeyserSession session = geyser.connectionByXuid(xuid); @@ -123,9 +116,7 @@ public final class FloodgateSkinUploader { String value = data.get("value").asText(); String signature = data.get("signature").asText(); - byte[] bytes = (value + '\0' + signature) - .getBytes(StandardCharsets.UTF_8); - PluginMessageUtils.sendMessage(session, PluginMessageChannels.SKIN, bytes); + geyser.getHybridProvider().onSkinUpload(session, value, signature); } break; case LOG_MESSAGE: @@ -222,7 +213,7 @@ public final class FloodgateSkinUploader { .schedule(client::reconnect, 8 + additionalTime, TimeUnit.SECONDS); } - public FloodgateSkinUploader start() { + public BedrockSkinUploader start() { client.connect(); return this; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockNetworkStackLatencyTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockNetworkStackLatencyTranslator.java index 876395114..4f0fb35fc 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockNetworkStackLatencyTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockNetworkStackLatencyTranslator.java @@ -29,7 +29,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundKe import com.nukkitx.protocol.bedrock.data.AttributeData; import com.nukkitx.protocol.bedrock.packet.NetworkStackLatencyPacket; import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket; -import org.geysermc.floodgate.util.DeviceOs; +import org.geysermc.api.util.BedrockPlatform; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; @@ -50,7 +50,7 @@ public class BedrockNetworkStackLatencyTranslator extends PacketTranslator Date: Thu, 10 Nov 2022 21:14:07 +0100 Subject: [PATCH 2/2] Allow Floodgate to be run in Geyser Velocity --- api/geyser/build.gradle.kts | 2 +- .../bungeecord/BungeeHybridListener.java | 161 ++++++++---------- .../bungeecord/GeyserBungeePlugin.java | 4 +- .../platform/fabric/GeyserFabricMod.java | 2 +- .../platform/spigot/GeyserSpigotPlugin.java | 4 +- .../platform/sponge/GeyserSpongePlugin.java | 10 +- .../standalone/GeyserStandaloneBootstrap.java | 4 +- bootstrap/velocity/build.gradle.kts | 1 + .../velocity/GeyserVelocityPlugin.java | 33 ++-- .../floodgate/FloodgateVelocityPlatform.java | 46 +++++ core/build.gradle.kts | 6 +- .../geysermc/connector/GeyserConnector.java | 2 +- .../java/org/geysermc/geyser/GeyserImpl.java | 23 ++- .../geyser/command/GeyserCommandManager.java | 22 +-- .../defaults/ConnectionTestCommand.java | 2 +- .../geyser/command/defaults/DumpCommand.java | 2 +- .../geyser/command/defaults/HelpCommand.java | 2 +- .../command/defaults/ReloadCommand.java | 2 +- .../geyser/command/defaults/StopCommand.java | 2 +- .../command/defaults/VersionCommand.java | 2 +- .../geyser/dump/BootstrapDumpInfo.java | 2 +- .../org/geysermc/geyser/dump/DumpInfo.java | 8 +- .../geyser/floodgate/GeyserLoadStage.java | 40 +++++ .../hybrid/FloodgateHybridProvider.java | 7 +- .../geyser/hybrid/HybridProvider.java | 55 ------ .../geyser/hybrid/ProxyHybridProvider.java | 19 +-- .../registry/PacketTranslatorRegistry.java | 2 +- .../geyser/session/GeyserSession.java | 6 +- .../level/block/entity/PistonBlockEntity.java | 2 +- .../BedrockCommandRequestTranslator.java | 2 +- .../java/JavaCustomPayloadTranslator.java | 153 ++++++++--------- .../java/JavaLoginDisconnectTranslator.java | 2 +- .../protocol/java/JavaLoginTranslator.java | 4 +- .../java/level/JavaBlockEventTranslator.java | 2 +- .../java/level/JavaBlockUpdateTranslator.java | 2 +- .../geysermc/geyser/util}/PlatformType.java | 2 +- 36 files changed, 308 insertions(+), 332 deletions(-) create mode 100644 bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/floodgate/FloodgateVelocityPlatform.java create mode 100644 core/src/main/java/org/geysermc/geyser/floodgate/GeyserLoadStage.java rename {common/src/main/java/org/geysermc/common => core/src/main/java/org/geysermc/geyser/util}/PlatformType.java (97%) diff --git a/api/geyser/build.gradle.kts b/api/geyser/build.gradle.kts index 6babe9874..27d21dfb9 100644 --- a/api/geyser/build.gradle.kts +++ b/api/geyser/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } dependencies { - api(libs.baseApi) + compileOnly(libs.baseApi) } publishing { diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/BungeeHybridListener.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/BungeeHybridListener.java index 66fa0a211..8d699ffd3 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/BungeeHybridListener.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/BungeeHybridListener.java @@ -25,98 +25,77 @@ package org.geysermc.geyser.platform.bungeecord; -import io.netty.channel.Channel; -import net.md_5.bungee.api.connection.PendingConnection; -import net.md_5.bungee.api.event.PreLoginEvent; -import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.plugin.Listener; -import net.md_5.bungee.connection.InitialHandler; -import net.md_5.bungee.event.EventHandler; -import net.md_5.bungee.event.EventPriority; -import net.md_5.bungee.netty.ChannelWrapper; -import net.md_5.bungee.protocol.packet.Handshake; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.api.connection.Connection; -import org.geysermc.floodgate.player.FloodgatePlayerImpl; -import org.geysermc.floodgate.util.BedrockData; -import org.geysermc.floodgate.util.ReflectionUtils; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.hybrid.IntegratedHybridProvider; -import org.geysermc.geyser.hybrid.ProxyHybridProvider; - -import java.lang.reflect.Field; - -import static com.google.common.base.Preconditions.checkNotNull; public final class BungeeHybridListener implements Listener { - // TODO consolidate with Floodgate - private static final Field CHANNEL_WRAPPER; - private static final Field PLAYER_NAME; - - static { - CHANNEL_WRAPPER = - ReflectionUtils.getFieldOfType(InitialHandler.class, ChannelWrapper.class); - checkNotNull(CHANNEL_WRAPPER, "ChannelWrapper field cannot be null"); - - PLAYER_NAME = ReflectionUtils.getField(InitialHandler.class, "name"); - checkNotNull(PLAYER_NAME, "Initial name field cannot be null"); - } - - @EventHandler(priority = EventPriority.LOWEST) - public void onPreLogin(PreLoginEvent event) { - // well, no reason to check if the player will be kicked anyway - if (event.isCancelled()) { - return; - } - - PendingConnection connection = event.getConnection(); - Connection player = getPlayer(connection); - if (player != null) { - connection.setOnlineMode(false); - connection.setUniqueId(player.javaUuid()); - ReflectionUtils.setValue(connection, PLAYER_NAME, player.javaUsername()); - } - } - - @EventHandler(priority = EventPriority.LOW) - public void onServerConnect(ServerConnectEvent event) { - boolean sendFloodgateData = false; // TODO - if (!sendFloodgateData) { - return; // TODO just don't register event? - } - - PendingConnection connection = event.getPlayer().getPendingConnection(); - Connection player = getPlayer(connection); - if (player != null) { - Handshake handshake = ReflectionUtils.getCastedValue(connection, "handshake"); - BedrockData data = ((FloodgatePlayerImpl) player).toBedrockData(); // FIXME - String encryptedData = ((ProxyHybridProvider) GeyserImpl.getInstance().getHybridProvider()) - .createEncryptedDataString(data); - - String address = handshake.getHost(); - - // our data goes before all the other data - int addressFinished = address.indexOf('\0'); - String originalAddress; - String remaining; - if (addressFinished != -1) { - originalAddress = address.substring(0, addressFinished); - remaining = address.substring(addressFinished); - } else { - originalAddress = address; - remaining = ""; - } - - handshake.setHost(originalAddress + '\0' + encryptedData + remaining); - // Bungeecord will add its data after our data - } - } - - @Nullable - private Connection getPlayer(PendingConnection connection) { - ChannelWrapper wrapper = ReflectionUtils.getCastedValue(connection, CHANNEL_WRAPPER); - Channel channel = wrapper.getHandle(); - - return channel.attr(IntegratedHybridProvider.SESSION_KEY).get(); // TODO re-use Floodgate's attribute key here? - } +// // TODO consolidate with Floodgate +// private static final Field CHANNEL_WRAPPER; +// private static final Field PLAYER_NAME; +// +// static { +// CHANNEL_WRAPPER = +// ReflectionUtils.getFieldOfType(InitialHandler.class, ChannelWrapper.class); +// checkNotNull(CHANNEL_WRAPPER, "ChannelWrapper field cannot be null"); +// +// PLAYER_NAME = ReflectionUtils.getField(InitialHandler.class, "name"); +// checkNotNull(PLAYER_NAME, "Initial name field cannot be null"); +// } +// +// @EventHandler(priority = EventPriority.LOWEST) +// public void onPreLogin(PreLoginEvent event) { +// // well, no reason to check if the player will be kicked anyway +// if (event.isCancelled()) { +// return; +// } +// +// PendingConnection connection = event.getConnection(); +// Connection player = getPlayer(connection); +// if (player != null) { +// connection.setOnlineMode(false); +// connection.setUniqueId(player.javaUuid()); +// ReflectionUtils.setValue(connection, PLAYER_NAME, player.javaUsername()); +// } +// } +// +// @EventHandler(priority = EventPriority.LOW) +// public void onServerConnect(ServerConnectEvent event) { +// boolean sendFloodgateData = false; // TODO +// if (!sendFloodgateData) { +// return; // TODO just don't register event? +// } +// +// PendingConnection connection = event.getPlayer().getPendingConnection(); +// Connection player = getPlayer(connection); +// if (player != null) { +// Handshake handshake = ReflectionUtils.getCastedValue(connection, "handshake"); +// BedrockData data = ((FloodgateConnection) player).toBedrockData(); // FIXME +// String encryptedData = ((ProxyHybridProvider) GeyserImpl.getInstance().getHybridProvider()) +// .createEncryptedDataString(data); +// +// String address = handshake.getHost(); +// +// // our data goes before all the other data +// int addressFinished = address.indexOf('\0'); +// String originalAddress; +// String remaining; +// if (addressFinished != -1) { +// originalAddress = address.substring(0, addressFinished); +// remaining = address.substring(addressFinished); +// } else { +// originalAddress = address; +// remaining = ""; +// } +// +// handshake.setHost(originalAddress + '\0' + encryptedData + remaining); +// // Bungeecord will add its data after our data +// } +// } +// +// @Nullable +// private Connection getPlayer(PendingConnection connection) { +// ChannelWrapper wrapper = ReflectionUtils.getCastedValue(connection, CHANNEL_WRAPPER); +// Channel channel = wrapper.getHandle(); +// +// return channel.attr(IntegratedHybridProvider.SESSION_KEY).get(); // TODO re-use Floodgate's attribute key here? +// } } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index d4fff600e..a98c45d68 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -31,7 +31,6 @@ import net.md_5.bungee.api.config.ListenerInfo; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.protocol.ProtocolConstants; import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.common.PlatformType; import org.geysermc.floodgate.BungeePlatform; import org.geysermc.floodgate.pluginmessage.BungeeSkinApplier; import org.geysermc.floodgate.skin.SkinApplier; @@ -50,6 +49,7 @@ import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandExecutor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; +import org.geysermc.geyser.util.PlatformType; import java.io.File; import java.io.IOException; @@ -110,7 +110,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this); + this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this, null); } @Override diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java index e5ff4b577..21af19b06 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java @@ -36,7 +36,6 @@ import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.server.MinecraftServer; import org.apache.logging.log4j.LogManager; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; @@ -53,6 +52,7 @@ import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor; import org.geysermc.geyser.platform.fabric.world.GeyserFabricWorldManager; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; +import org.geysermc.geyser.util.PlatformType; import org.jetbrains.annotations.Nullable; import java.io.File; diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 64a360a35..9c6c5b25c 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -42,7 +42,6 @@ import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; -import org.geysermc.common.PlatformType; import org.geysermc.floodgate.pluginmessage.SpigotSkinApplier; import org.geysermc.floodgate.skin.SkinApplier; import org.geysermc.floodgate.util.SpigotVersionSpecificMethods; @@ -71,6 +70,7 @@ import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotNativeWorld import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; +import org.geysermc.geyser.util.PlatformType; import java.io.File; import java.io.IOException; @@ -158,7 +158,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - this.geyser = GeyserImpl.load(PlatformType.SPIGOT, this); + this.geyser = GeyserImpl.load(PlatformType.SPIGOT, this, null); } @Override diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java index 1f9541631..f3f5e11d5 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.platform.sponge; import com.google.inject.Inject; import org.apache.logging.log4j.Logger; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.command.Command; @@ -37,10 +36,11 @@ import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; -import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandManager; -import org.geysermc.geyser.util.FileUtils; -import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandExecutor; +import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandManager; +import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.FileUtils; +import org.geysermc.geyser.util.PlatformType; import org.spongepowered.api.Server; import org.spongepowered.api.Sponge; import org.spongepowered.api.config.ConfigDir; @@ -141,7 +141,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap { GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode()); - this.geyser = GeyserImpl.load(PlatformType.SPONGE, this); + this.geyser = GeyserImpl.load(PlatformType.SPONGE, this, null); this.geyserCommandManager = new GeyserSpongeCommandManager(geyser); this.geyserCommandManager.init(); diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java index 5cbbab9d4..d9378008f 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java @@ -38,7 +38,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.appender.ConsoleAppender; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommandManager; @@ -51,6 +50,7 @@ import org.geysermc.geyser.platform.standalone.gui.GeyserStandaloneGUI; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.util.LoopbackUtil; +import org.geysermc.geyser.util.PlatformType; import java.io.File; import java.io.IOException; @@ -216,7 +216,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { // Allow libraries like Protocol to have their debug information passthrough logger.get().setLevel(geyserConfig.isDebugMode() ? Level.DEBUG : Level.INFO); - geyser = GeyserImpl.load(PlatformType.STANDALONE, this); + geyser = GeyserImpl.load(PlatformType.STANDALONE, this, null); GeyserImpl.start(); geyserCommandManager = new GeyserCommandManager(geyser); diff --git a/bootstrap/velocity/build.gradle.kts b/bootstrap/velocity/build.gradle.kts index 8908b2afd..ae5d7f5b8 100644 --- a/bootstrap/velocity/build.gradle.kts +++ b/bootstrap/velocity/build.gradle.kts @@ -1,5 +1,6 @@ dependencies { annotationProcessor(libs.velocity.api) + implementation("org.geysermc.floodgate", "velocity", "2.2.0-SNAPSHOT") api(projects.core) } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index 5ac09416c..9b8cf6357 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.platform.velocity; import com.google.inject.Inject; +import com.google.inject.Injector; import com.velocitypowered.api.command.CommandManager; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.proxy.ListenerBoundEvent; @@ -36,7 +37,7 @@ import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.proxy.ProxyServer; import lombok.Getter; import net.kyori.adventure.util.Codec; -import org.geysermc.common.PlatformType; +import org.geysermc.floodgate.FloodgatePlatform; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.command.Command; @@ -48,8 +49,10 @@ import org.geysermc.geyser.dump.BootstrapDumpInfo; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.platform.velocity.command.GeyserVelocityCommandExecutor; +import org.geysermc.geyser.platform.velocity.floodgate.FloodgateVelocityPlatform; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.FileUtils; +import org.geysermc.geyser.util.PlatformType; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -85,6 +88,9 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { @Getter private final Path configFolder = Paths.get("plugins/" + GeyserImpl.NAME + "-Velocity/"); + @Inject + private Injector guice; + @Override public void onEnable() { try { @@ -130,7 +136,12 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this); + FloodgatePlatform platform = null; + if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE) { + platform = guice.getInstance(FloodgateVelocityPlatform.class); + } + + this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this, platform); // Remove this in like a year try { @@ -142,15 +153,15 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { } catch (ClassNotFoundException ignored) { } - if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && proxyServer.getPluginManager().getPlugin("floodgate").isEmpty()) { - geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " - + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); - return; - } else if (geyserConfig.isAutoconfiguredRemote() && proxyServer.getPluginManager().getPlugin("floodgate").isPresent()) { - // Floodgate installed means that the user wants Floodgate authentication - geyserLogger.debug("Auto-setting to Floodgate authentication."); - geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE); - } +// if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && proxyServer.getPluginManager().getPlugin("floodgate").isEmpty()) { +// geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " +// + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); +// return; +// } else if (geyserConfig.isAutoconfiguredRemote() && proxyServer.getPluginManager().getPlugin("floodgate").isPresent()) { +// // Floodgate installed means that the user wants Floodgate authentication +// geyserLogger.debug("Auto-setting to Floodgate authentication."); +// geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE); +// } geyserConfig.loadFloodgate(this, proxyServer, configFolder.toFile()); diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/floodgate/FloodgateVelocityPlatform.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/floodgate/FloodgateVelocityPlatform.java new file mode 100644 index 000000000..e9ca5458c --- /dev/null +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/floodgate/FloodgateVelocityPlatform.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.platform.velocity.floodgate; + +import com.google.inject.Module; +import org.geysermc.floodgate.VelocityPlatform; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.floodgate.GeyserLoadStage; + +import java.nio.file.Paths; +import java.util.List; + +public class FloodgateVelocityPlatform extends VelocityPlatform { + @Override + protected List loadStageModules() { + // Geyser being a dumb dumb + super.dataDirectory = Paths.get("plugins/" + GeyserImpl.NAME + "-Velocity/"); + + var loaded = super.loadStageModules(); + loaded.add(new GeyserLoadStage()); + return loaded; + } +} diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 2a17de51a..814329909 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -7,8 +7,8 @@ plugins { } dependencies { + api("org.geysermc.floodgate", "core", "2.2.0-SNAPSHOT") api(projects.geyserApi) - api(projects.common) // Jackson JSON and YAML serialization api(libs.bundles.jackson) @@ -60,10 +60,6 @@ dependencies { compileOnly(projects.ap) annotationProcessor(projects.ap) - - implementation("org.geysermc.floodgate", "core", "2.2.0-SNAPSHOT") { - exclude("org.geysermc", "api") - } } configurations.api { diff --git a/core/src/main/java/org/geysermc/connector/GeyserConnector.java b/core/src/main/java/org/geysermc/connector/GeyserConnector.java index bd14ebb25..da48ce8f2 100644 --- a/core/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/core/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -27,9 +27,9 @@ package org.geysermc.connector; import com.nukkitx.protocol.bedrock.BedrockServer; import org.geysermc.api.Geyser; -import org.geysermc.common.PlatformType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.util.PlatformType; import java.util.UUID; diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 8edae903e..a588581cd 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -47,11 +47,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.api.Geyser; -import org.geysermc.common.PlatformType; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; -import org.geysermc.floodgate.api.InstanceHolder; -import org.geysermc.floodgate.api.impl.FloodgateApiWrapper; +import org.geysermc.floodgate.FloodgatePlatform; import org.geysermc.floodgate.news.NewsItemAction; import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.event.EventBus; @@ -155,11 +153,18 @@ public class GeyserImpl implements GeyserApi { private static GeyserImpl instance; - private GeyserImpl(PlatformType platformType, GeyserBootstrap bootstrap) { - instance = this; + private final FloodgatePlatform floodgatePlatform; - Geyser.set(this); - InstanceHolder.set(new FloodgateApiWrapper(this), null, null, null, null); // TODO + private GeyserImpl(PlatformType platformType, GeyserBootstrap bootstrap, FloodgatePlatform floodgatePlatform) { + instance = this; + this.floodgatePlatform = floodgatePlatform; + + if (floodgatePlatform != null) { + floodgatePlatform.load(); + floodgatePlatform.enable(); + } else { + Geyser.set(this); + } this.platformType = platformType; this.bootstrap = bootstrap; @@ -613,9 +618,9 @@ public class GeyserImpl implements GeyserApi { return Integer.parseInt(BUILD_NUMBER); } - public static GeyserImpl load(PlatformType platformType, GeyserBootstrap bootstrap) { + public static GeyserImpl load(PlatformType platformType, GeyserBootstrap bootstrap, FloodgatePlatform floodgatePlatform) { if (instance == null) { - return new GeyserImpl(platformType, bootstrap); + return new GeyserImpl(platformType, bootstrap, floodgatePlatform); } return instance; diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java index d28f9d24e..86f26bed4 100644 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommandManager.java @@ -29,38 +29,22 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.api.command.CommandExecutor; import org.geysermc.geyser.api.command.CommandSource; import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCommandsEvent; import org.geysermc.geyser.api.extension.Extension; -import org.geysermc.geyser.command.defaults.AdvancedTooltipsCommand; -import org.geysermc.geyser.command.defaults.AdvancementsCommand; -import org.geysermc.geyser.command.defaults.ConnectionTestCommand; -import org.geysermc.geyser.command.defaults.DumpCommand; -import org.geysermc.geyser.command.defaults.ExtensionsCommand; -import org.geysermc.geyser.command.defaults.HelpCommand; -import org.geysermc.geyser.command.defaults.ListCommand; -import org.geysermc.geyser.command.defaults.OffhandCommand; -import org.geysermc.geyser.command.defaults.ReloadCommand; -import org.geysermc.geyser.command.defaults.SettingsCommand; -import org.geysermc.geyser.command.defaults.StatisticsCommand; -import org.geysermc.geyser.command.defaults.StopCommand; -import org.geysermc.geyser.command.defaults.VersionCommand; +import org.geysermc.geyser.command.defaults.*; import org.geysermc.geyser.event.type.GeyserDefineCommandsEventImpl; import org.geysermc.geyser.extension.command.GeyserExtensionCommand; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.PlatformType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; +import java.util.*; @RequiredArgsConstructor public class GeyserCommandManager { diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java index 95c115769..6c381ad4b 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ConnectionTestCommand.java @@ -26,13 +26,13 @@ package org.geysermc.geyser.command.defaults; import com.fasterxml.jackson.databind.JsonNode; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.LoopbackUtil; +import org.geysermc.geyser.util.PlatformType; import org.geysermc.geyser.util.WebUtils; import org.jetbrains.annotations.Nullable; diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java index 60683d34a..0aa7f8445 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java @@ -30,7 +30,6 @@ import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; @@ -39,6 +38,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.AsteriskSerializer; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.PlatformType; import org.geysermc.geyser.util.WebUtils; import java.io.FileOutputStream; diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java index 6e7ad2f04..5308ac162 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.command.defaults; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.command.GeyserCommand; @@ -33,6 +32,7 @@ import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.PlatformType; import java.util.Collections; import java.util.Map; diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java index 843e93de0..2820e6677 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.command.defaults; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.PlatformType; public class ReloadCommand extends GeyserCommand { diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java index 151aa2d84..19ce88dea 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java @@ -25,12 +25,12 @@ package org.geysermc.geyser.command.defaults; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.PlatformType; import java.util.Collections; diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java index fbe4fb4f6..6c3818e65 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.command.defaults; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; @@ -34,6 +33,7 @@ import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.PlatformType; import org.geysermc.geyser.util.WebUtils; import java.io.IOException; diff --git a/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java index fda0566fd..1e97af527 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java @@ -27,9 +27,9 @@ package org.geysermc.geyser.dump; import lombok.AllArgsConstructor; import lombok.Getter; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.text.AsteriskSerializer; +import org.geysermc.geyser.util.PlatformType; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index f017d9195..de3e1bafc 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -37,7 +37,6 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import lombok.AllArgsConstructor; import lombok.Getter; import org.geysermc.api.util.BedrockPlatform; -import org.geysermc.floodgate.util.FloodgateInfoHolder; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.extension.Extension; @@ -233,8 +232,11 @@ public class DumpInfo { private final Object config; Floodgate() { - this.gitInfo = FloodgateInfoHolder.getGitProperties(); - this.config = FloodgateInfoHolder.getConfig(); + //todo we can get the information from Floodgate directly now + this.gitInfo = null; + this.config = null; +// this.gitInfo = FloodgateInfoHolder.getGitProperties(); +// this.config = FloodgateInfoHolder.getConfig(); } } diff --git a/core/src/main/java/org/geysermc/geyser/floodgate/GeyserLoadStage.java b/core/src/main/java/org/geysermc/geyser/floodgate/GeyserLoadStage.java new file mode 100644 index 000000000..f0551f76e --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/floodgate/GeyserLoadStage.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.floodgate; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.google.inject.name.Named; + +public class GeyserLoadStage extends AbstractModule { + @Provides + @Singleton + @Named("configFile") + private String floodgateConfigName() { + return "floodgate.yml"; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/hybrid/FloodgateHybridProvider.java b/core/src/main/java/org/geysermc/geyser/hybrid/FloodgateHybridProvider.java index 4bf653b77..f67d95a09 100644 --- a/core/src/main/java/org/geysermc/geyser/hybrid/FloodgateHybridProvider.java +++ b/core/src/main/java/org/geysermc/geyser/hybrid/FloodgateHybridProvider.java @@ -26,10 +26,8 @@ package org.geysermc.geyser.hybrid; import org.geysermc.floodgate.crypto.FloodgateCipher; -import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.PluginMessageUtils; import java.nio.charset.StandardCharsets; @@ -37,14 +35,15 @@ public final class FloodgateHybridProvider implements HybridProvider { private final FloodgateCipher cipher; public FloodgateHybridProvider(GeyserImpl geyser) { - cipher = HybridProvider.getOrCreateKey(geyser); + cipher = geyser.getFloodgatePlatform().getInstance(FloodgateCipher.class); } @Override public void onSkinUpload(GeyserSession session, String value, String signature) { byte[] bytes = (value + '\0' + signature) .getBytes(StandardCharsets.UTF_8); - PluginMessageUtils.sendMessage(session, PluginMessageChannels.SKIN, bytes); + //todo +// PluginMessageUtils.sendMessage(session, PluginMessageChannels.SKIN, bytes); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/hybrid/HybridProvider.java b/core/src/main/java/org/geysermc/geyser/hybrid/HybridProvider.java index 493f1e5e4..e84f81cb1 100644 --- a/core/src/main/java/org/geysermc/geyser/hybrid/HybridProvider.java +++ b/core/src/main/java/org/geysermc/geyser/hybrid/HybridProvider.java @@ -25,66 +25,11 @@ package org.geysermc.geyser.hybrid; -import org.geysermc.floodgate.crypto.AesCipher; -import org.geysermc.floodgate.crypto.AesKeyProducer; -import org.geysermc.floodgate.crypto.Base64Topping; import org.geysermc.floodgate.crypto.FloodgateCipher; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.GeyserLogger; -import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.GeyserLocale; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.Key; public interface HybridProvider { void onSkinUpload(GeyserSession session, String value, String signature); FloodgateCipher getCipher(); - - static FloodgateCipher getOrCreateKey(GeyserImpl geyser) { - GeyserLogger logger = geyser.getLogger(); - GeyserConfiguration config = geyser.getConfig(); - try { - // TODO make this common code with Floodgate. Like, make sure Geyser's core and Floodgate's core points to the same thing - FloodgateCipher cipher = new AesCipher(new Base64Topping()); - - Path keyPath = config.getFloodgateKeyPath(); - if (!Files.exists(keyPath)) { - generateFloodgateKey(cipher, keyPath); // Should also init the cipher for us. - // TODO good? - logger.info("We just created a Floodgate key at " + keyPath + ". You will need to copy this file into " + - "your Floodgate config folder(s)."); - } else { - Key key = new AesKeyProducer().produceFrom(keyPath); - cipher.init(key); - } - logger.debug(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.loaded_key")); - return cipher; - } catch (Exception exception) { - logger.severe(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.bad_key"), exception); - return null; - } - } - - static void generateFloodgateKey(FloodgateCipher cipher, Path keyPath) throws Exception { - Key key = new AesKeyProducer().produce(); - cipher.init(key); - - String test = "abcdefghijklmnopqrstuvwxyz0123456789"; - byte[] encrypted = cipher.encryptFromString(test); - String decrypted = cipher.decryptToString(encrypted); - - if (!test.equals(decrypted)) { - throw new RuntimeException("Failed to decrypt test message.\n" + - "Original message: " + test + "." + - "Decrypted message: " + decrypted + ".\n" + - "The encrypted message itself: " + new String(encrypted) - ); - } - - Files.write(keyPath, key.getEncoded()); - } } diff --git a/core/src/main/java/org/geysermc/geyser/hybrid/ProxyHybridProvider.java b/core/src/main/java/org/geysermc/geyser/hybrid/ProxyHybridProvider.java index 101ac8834..0bc9d9d50 100644 --- a/core/src/main/java/org/geysermc/geyser/hybrid/ProxyHybridProvider.java +++ b/core/src/main/java/org/geysermc/geyser/hybrid/ProxyHybridProvider.java @@ -26,35 +26,18 @@ package org.geysermc.geyser.hybrid; import org.geysermc.floodgate.crypto.FloodgateCipher; -import org.geysermc.floodgate.util.BedrockData; import org.geysermc.geyser.GeyserImpl; -import java.nio.charset.StandardCharsets; - public final class ProxyHybridProvider extends IntegratedHybridProvider { private final FloodgateCipher cipher; public ProxyHybridProvider(GeyserImpl geyser) { super(geyser); - this.cipher = HybridProvider.getOrCreateKey(geyser); + this.cipher = geyser.getFloodgatePlatform().getInstance(FloodgateCipher.class); } @Override public FloodgateCipher getCipher() { return cipher; } - - // TODO copied from ProxyFloodgateApi - public byte[] createEncryptedData(BedrockData bedrockData) { - try { - return cipher.encryptFromString(bedrockData.toString()); - } catch (Exception exception) { - throw new IllegalStateException("We failed to create the encrypted data, " + - "but creating encrypted data is mandatory!", exception); - } - } - - public String createEncryptedDataString(BedrockData bedrockData) { - return new String(createEncryptedData(bedrockData), StandardCharsets.UTF_8); - } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java index bf412bfaf..9eefd6503 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java @@ -29,12 +29,12 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundTa import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLightUpdatePacket; import com.nukkitx.protocol.bedrock.BedrockPacket; import io.netty.channel.EventLoop; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.registry.loader.RegistryLoaders; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.util.PlatformType; import java.util.Collections; import java.util.IdentityHashMap; diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 4a8ce0561..f9e6ede3e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -94,7 +94,6 @@ import org.checkerframework.common.value.qual.IntRange; import org.geysermc.api.util.BedrockPlatform; import org.geysermc.api.util.InputMode; import org.geysermc.api.util.UiProfile; -import org.geysermc.common.PlatformType; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.floodgate.crypto.FloodgateCipher; @@ -136,10 +135,7 @@ import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.ChunkUtils; -import org.geysermc.geyser.util.DimensionUtils; -import org.geysermc.geyser.util.LoginEncryptionUtils; -import org.geysermc.geyser.util.MathUtils; +import org.geysermc.geyser.util.*; import java.net.ConnectException; import java.net.InetSocketAddress; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index 28e30d6be..1163a0ae9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -36,7 +36,6 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import lombok.Getter; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.physics.Axis; import org.geysermc.geyser.level.physics.BoundingBox; @@ -49,6 +48,7 @@ import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.geyser.util.BlockUtils; import org.geysermc.geyser.util.ChunkUtils; +import org.geysermc.geyser.util.PlatformType; import java.util.LinkedList; import java.util.Map; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java index 3301f7b9f..ee42c674a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandRequestTranslator.java @@ -26,12 +26,12 @@ package org.geysermc.geyser.translator.protocol.bedrock; import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.geyser.util.PlatformType; @Translator(packet = CommandRequestPacket.class) public class BedrockCommandRequestTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java index aaedfa443..e886a136f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java @@ -26,16 +26,6 @@ package org.geysermc.geyser.translator.protocol.java; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCustomPayloadPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; -import com.google.common.base.Charsets; -import com.nukkitx.protocol.bedrock.packet.TransferPacket; -import com.nukkitx.protocol.bedrock.packet.UnknownPacket; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.geysermc.cumulus.Forms; -import org.geysermc.cumulus.form.Form; -import org.geysermc.cumulus.form.util.FormType; -import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.api.network.AuthType; @@ -43,8 +33,6 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import java.nio.charset.StandardCharsets; - @Translator(packet = ClientboundCustomPayloadPacket.class) public class JavaCustomPayloadTranslator extends PacketTranslator { private final GeyserLogger logger = GeyserImpl.getInstance().getLogger(); @@ -58,75 +46,76 @@ public class JavaCustomPayloadTranslator extends PacketTranslator { - byte[] finalData; - if (response == null) { - // Response data can be null as of 1.19.20 (same behaviour as empty response data) - // Only need to send the form id - finalData = new byte[]{data[1], data[2]}; - } else { - byte[] raw = response.getBytes(StandardCharsets.UTF_8); - finalData = new byte[raw.length + 2]; - - finalData[0] = data[1]; - finalData[1] = data[2]; - System.arraycopy(raw, 0, finalData, 2, raw.length); - } - - session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(channel, finalData)); - }); - session.sendForm(form); - - } else if (channel.equals(PluginMessageChannels.TRANSFER)) { - byte[] data = packet.getData(); - - // port (4 bytes), address (remaining data) - if (data.length < 5) { - throw new NullPointerException("Transfer data should be at least 5 bytes long"); - } - - int port = data[0] << 24 | (data[1] & 0xFF) << 16 | (data[2] & 0xFF) << 8 | data[3] & 0xFF; - String address = new String(data, 4, data.length - 4); - - if (logger.isDebug()) { - logger.info("Transferring client to: " + address + ":" + port); - } - - TransferPacket transferPacket = new TransferPacket(); - transferPacket.setAddress(address); - transferPacket.setPort(port); - session.sendUpstreamPacket(transferPacket); - - } else if (channel.equals(PluginMessageChannels.PACKET)) { - logger.debug("A packet has been sent using the Floodgate api"); - byte[] data = packet.getData(); - - // packet id, packet data - if (data.length < 2) { - throw new IllegalStateException("Packet data should be at least 2 bytes long"); - } - - int packetId = data[0] & 0xFF; - ByteBuf packetData = Unpooled.wrappedBuffer(data, 1, data.length - 1); - - var toSend = new UnknownPacket(); - toSend.setPacketId(packetId); - toSend.setPayload(packetData); - - session.sendUpstreamPacket(toSend); - } + //todo +// if (channel.equals(PluginMessageChannels.FORM)) { +// byte[] data = packet.getData(); +// +// // receive: first byte is form type, second and third are the id, remaining is the form data +// // respond: first and second byte id, remaining is form response data +// +// FormType type = FormType.fromOrdinal(data[0]); +// if (type == null) { +// throw new NullPointerException("Got type " + data[0] + " which isn't a valid form type!"); +// } +// +// String dataString = new String(data, 3, data.length - 3, Charsets.UTF_8); +// +// Form form = Forms.fromJson(dataString, type, (ignored, response) -> { +// byte[] finalData; +// if (response == null) { +// // Response data can be null as of 1.19.20 (same behaviour as empty response data) +// // Only need to send the form id +// finalData = new byte[]{data[1], data[2]}; +// } else { +// byte[] raw = response.getBytes(StandardCharsets.UTF_8); +// finalData = new byte[raw.length + 2]; +// +// finalData[0] = data[1]; +// finalData[1] = data[2]; +// System.arraycopy(raw, 0, finalData, 2, raw.length); +// } +// +// session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(channel, finalData)); +// }); +// session.sendForm(form); +// +// } else if (channel.equals(PluginMessageChannels.TRANSFER)) { +// byte[] data = packet.getData(); +// +// // port (4 bytes), address (remaining data) +// if (data.length < 5) { +// throw new NullPointerException("Transfer data should be at least 5 bytes long"); +// } +// +// int port = data[0] << 24 | (data[1] & 0xFF) << 16 | (data[2] & 0xFF) << 8 | data[3] & 0xFF; +// String address = new String(data, 4, data.length - 4); +// +// if (logger.isDebug()) { +// logger.info("Transferring client to: " + address + ":" + port); +// } +// +// TransferPacket transferPacket = new TransferPacket(); +// transferPacket.setAddress(address); +// transferPacket.setPort(port); +// session.sendUpstreamPacket(transferPacket); +// +// } else if (channel.equals(PluginMessageChannels.PACKET)) { +// logger.debug("A packet has been sent using the Floodgate api"); +// byte[] data = packet.getData(); +// +// // packet id, packet data +// if (data.length < 2) { +// throw new IllegalStateException("Packet data should be at least 2 bytes long"); +// } +// +// int packetId = data[0] & 0xFF; +// ByteBuf packetData = Unpooled.wrappedBuffer(data, 1, data.length - 1); +// +// var toSend = new UnknownPacket(); +// toSend.setPacketId(packetId); +// toSend.setPayload(packetData); +// +// session.sendUpstreamPacket(toSend); +// } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java index 0720963fb..1c5c2ade4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginDisconnectTranslator.java @@ -29,13 +29,13 @@ import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundLog import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TranslatableComponent; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.geyser.util.PlatformType; import java.util.List; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index d48d78439..905d2683d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -35,7 +35,6 @@ import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.level.JavaDimension; @@ -142,7 +141,8 @@ public class JavaLoginTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java index cd965e128..0263abdb7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java @@ -29,12 +29,12 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.Clientb import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; -import org.geysermc.common.PlatformType; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator; +import org.geysermc.geyser.util.PlatformType; @Translator(packet = ClientboundBlockUpdatePacket.class) public class JavaBlockUpdateTranslator extends PacketTranslator { diff --git a/common/src/main/java/org/geysermc/common/PlatformType.java b/core/src/main/java/org/geysermc/geyser/util/PlatformType.java similarity index 97% rename from common/src/main/java/org/geysermc/common/PlatformType.java rename to core/src/main/java/org/geysermc/geyser/util/PlatformType.java index 667d49a7a..8e2c927ad 100644 --- a/common/src/main/java/org/geysermc/common/PlatformType.java +++ b/core/src/main/java/org/geysermc/geyser/util/PlatformType.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.common; +package org.geysermc.geyser.util; import lombok.AllArgsConstructor; import lombok.Getter;