diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 72f50ff97..797d68767 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -2,15 +2,6 @@ name: Build Pull Request on: pull_request: - paths-ignore: - - '.github/ISSUE_TEMPLATE/*.yml' - - '.idea/copyright/*.xml' - - '.gitignore' - - 'CONTRIBUTING.md' - - 'LICENSE' - - 'Jenkinsfile ' - - 'README.md' - - 'licenseheader.txt' jobs: build: diff --git a/README.md b/README.md index 7f9f6fe9e..8a1f456c7 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.20.0 - 1.20.30 and Minecraft Java 1.20/1.20.1. +### Currently supporting Minecraft Bedrock 1.20.0 - 1.20.32 and Minecraft Java 1.20.2 ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. diff --git a/api/src/main/java/org/geysermc/geyser/api/extension/ExtensionManager.java b/api/src/main/java/org/geysermc/geyser/api/extension/ExtensionManager.java index a9d0d7376..5226221df 100644 --- a/api/src/main/java/org/geysermc/geyser/api/extension/ExtensionManager.java +++ b/api/src/main/java/org/geysermc/geyser/api/extension/ExtensionManager.java @@ -36,13 +36,13 @@ import java.util.Collection; public abstract class ExtensionManager { /** - * Gets an extension with the given name. + * Gets an extension by the given ID. * - * @param name the name of the extension - * @return an extension with the given name + * @param id the ID of the extension + * @return an extension with the given ID */ @Nullable - public abstract Extension extension(@NonNull String name); + public abstract Extension extension(@NonNull String id); /** * Enables the given {@link Extension}. 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 b521e04ac..391b5aafd 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 @@ -79,7 +79,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { // Copied from ViaVersion. // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 try { - ProtocolConstants.class.getField("MINECRAFT_1_19_3"); + ProtocolConstants.class.getField("MINECRAFT_1_20_2"); } catch (NoSuchFieldException e) { getLogger().warning(" / \\"); getLogger().warning(" / \\"); diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts index c260703a5..e392a4ef9 100644 --- a/bootstrap/fabric/build.gradle.kts +++ b/bootstrap/fabric/build.gradle.kts @@ -118,7 +118,7 @@ modrinth { syncBodyFrom.set(rootProject.file("README.md").readText()) uploadFile.set(tasks.getByPath("remapModrinthJar")) - gameVersions.addAll("1.20", "1.20.1") + gameVersions.addAll("1.20.2") loaders.add("fabric") failSilently.set(true) diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/fabric/src/main/resources/fabric.mod.json index 4c442017a..f401e8f23 100644 --- a/bootstrap/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/fabric/src/main/resources/fabric.mod.json @@ -25,7 +25,7 @@ "depends": { "fabricloader": ">=0.14.21", "fabric": "*", - "minecraft": ">=1.20", + "minecraft": ">=1.20.2", "fabric-permissions-api-v0": "*" } } 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 7395ecd7d..dd892bcf5 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 @@ -199,7 +199,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { commandMap.register(extension.description().id(), "geyserext", pluginCommand); } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) { - this.geyserLogger.error("Failed to construct PluginCommand for extension " + extension.description().name(), ex); + this.geyserLogger.error("Failed to construct PluginCommand for extension " + extension.name(), ex); } } } 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 6cbb9090b..001bb2497 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 @@ -128,16 +128,6 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this, platform); - // Remove this in like a year - try { - // Should only exist on 1.0 - Class.forName("org.geysermc.floodgate.FloodgateAPI"); - geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", - "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/")); - return; - } 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")); diff --git a/core/src/main/java/org/geysermc/connector/GeyserConnector.java b/core/src/main/java/org/geysermc/connector/GeyserConnector.java deleted file mode 100644 index 381282a2a..000000000 --- a/core/src/main/java/org/geysermc/connector/GeyserConnector.java +++ /dev/null @@ -1,91 +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.connector; - -import org.geysermc.api.Geyser; -import org.geysermc.geyser.api.util.PlatformType; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.geyser.GeyserImpl; - -import java.util.UUID; - -/** - * Deprecated, please use {@link Geyser} or {@link GeyserImpl}. - * - * @deprecated legacy code - */ -@Deprecated -public class GeyserConnector { - public static final String NAME = GeyserImpl.NAME; - public static final String GIT_VERSION = GeyserImpl.GIT_VERSION; // A fallback for running in IDEs - public static final String VERSION = GeyserImpl.VERSION; // A fallback for running in IDEs - - public static final String OAUTH_CLIENT_ID = GeyserImpl.OAUTH_CLIENT_ID; - - private static final GeyserConnector INSTANCE = new GeyserConnector(); - - public static GeyserConnector getInstance() { - return INSTANCE; - } - - public boolean isShuttingDown() { - return GeyserImpl.getInstance().isShuttingDown(); - } - - public PlatformType getPlatformType() { - return GeyserImpl.getInstance().getPlatformType(); - } - - public void shutdown() { - GeyserImpl.getInstance().shutdown(); - } - - public void reload() { - GeyserImpl.getInstance().reload(); - } - - public GeyserSession getPlayerByXuid(String xuid) { - org.geysermc.geyser.session.GeyserSession session = GeyserImpl.getInstance().connectionByXuid(xuid); - if (session != null) { - return new GeyserSession(session); - } else { - return null; - } - } - - public GeyserSession getPlayerByUuid(UUID uuid) { - org.geysermc.geyser.session.GeyserSession session = GeyserImpl.getInstance().connectionByUuid(uuid); - if (session != null) { - return new GeyserSession(session); - } else { - return null; - } - } - - public boolean isProductionEnvironment() { - return GeyserImpl.getInstance().isProductionEnvironment(); - } -} diff --git a/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java deleted file mode 100644 index 6298a41f6..000000000 --- a/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ /dev/null @@ -1,161 +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.connector.network.session; - -import com.github.steveice10.packetlib.packet.Packet; -import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; -import org.geysermc.connector.network.session.auth.AuthData; - -/** - * Deprecated, legacy code. Serves as a wrapper around - * the class used now. - * - * @deprecated legacy code - */ -@Deprecated -public class GeyserSession { - private final org.geysermc.geyser.session.GeyserSession handle; - - public GeyserSession(org.geysermc.geyser.session.GeyserSession handle) { - this.handle = handle; - } - - public AuthData getAuthData() { - return new AuthData(this.handle.getAuthData()); - } - - public boolean isMicrosoftAccount() { - return this.handle.isMicrosoftAccount(); - } - - public boolean isClosed() { - return this.handle.isClosed(); - } - - public String getRemoteAddress() { - return this.handle.remoteServer().address(); - } - - public int getRemotePort() { - return this.handle.remoteServer().port(); - } - - public int getRenderDistance() { - return this.handle.getServerRenderDistance(); - } - - public boolean isSentSpawnPacket() { - return this.handle.isSentSpawnPacket(); - } - - public boolean isLoggedIn() { - return this.handle.isLoggedIn(); - } - - public boolean isLoggingIn() { - return this.handle.isLoggingIn(); - } - - public boolean isSpawned() { - return this.handle.isSpawned(); - } - - public boolean isInteracting() { - return this.handle.isInteracting(); - } - - public boolean isCanFly() { - return this.handle.isCanFly(); - } - - public boolean isFlying() { - return this.handle.isFlying(); - } - - public void connect() { - this.handle.connect(); - } - - public void login() { - throw new UnsupportedOperationException(); - } - - public void authenticate(String username) { - this.handle.authenticate(username); - } - - public void authenticate(String username, String password) { - this.handle.authenticate(username, password); - } - - public void authenticateWithMicrosoftCode() { - this.handle.authenticateWithMicrosoftCode(); - } - - public void disconnect(String reason) { - this.handle.disconnect(reason); - } - - public void close() { - throw new UnsupportedOperationException(); - } - - public void executeInEventLoop(Runnable runnable) { - this.handle.executeInEventLoop(runnable); - } - - public String getName() { - return this.handle.bedrockUsername(); - } - - public boolean isConsole() { - return this.handle.isConsole(); - } - - public String getLocale() { - return this.handle.locale(); - } - - public void sendUpstreamPacket(BedrockPacket packet) { - this.handle.sendUpstreamPacket(packet); - } - - public void sendUpstreamPacketImmediately(BedrockPacket packet) { - this.handle.sendUpstreamPacketImmediately(packet); - } - - public void sendDownstreamPacket(Packet packet) { - this.handle.sendDownstreamPacket(packet); - } - - public boolean hasPermission(String permission) { - return this.handle.hasPermission(permission); - } - - public void sendAdventureSettings() { - this.handle.sendAdventureSettings(); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index df60e13f6..151cd9770 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -43,7 +43,6 @@ 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.geyser.api.util.PlatformType; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.erosion.packet.Packets; @@ -58,6 +57,7 @@ import org.geysermc.geyser.api.event.lifecycle.GeyserShutdownEvent; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.BedrockListener; import org.geysermc.geyser.api.network.RemoteServer; +import org.geysermc.geyser.api.util.PlatformType; import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.entity.EntityDefinitions; @@ -485,12 +485,6 @@ public class GeyserImpl implements GeyserApi { } if (config.getRemote().authType() == AuthType.ONLINE) { - if (config.getUserAuths() != null && !config.getUserAuths().isEmpty()) { - getLogger().warning("The 'userAuths' config section is now deprecated, and will be removed in the near future! " + - "Please migrate to the new 'saved-user-logins' config option: " + - "https://wiki.geysermc.org/geyser/understanding-the-config/"); - } - // May be written/read to on multiple threads from each GeyserSession as well as writing the config savedRefreshTokens = new ConcurrentHashMap<>(); diff --git a/core/src/main/java/org/geysermc/geyser/GeyserMain.java b/core/src/main/java/org/geysermc/geyser/GeyserMain.java index 8726c1b24..4e60a79b8 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserMain.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserMain.java @@ -28,6 +28,7 @@ package org.geysermc.geyser; import javax.swing.*; import java.io.InputStream; import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; import java.util.Locale; import java.util.Scanner; @@ -60,7 +61,7 @@ public class GeyserMain { helpStream = GeyserMain.class.getClassLoader().getResourceAsStream("languages/run-help/en_US.txt"); } - Scanner help = new Scanner(helpStream).useDelimiter("\\Z"); + Scanner help = new Scanner(helpStream, StandardCharsets.UTF_8).useDelimiter("\\Z"); String line = ""; while (help.hasNext()) { line = help.next(); diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java index ea2da51df..1ff12dea3 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java @@ -44,7 +44,7 @@ public class StatisticsCommand extends GeyserCommand { session.setWaitingForStatistics(true); ServerboundClientCommandPacket ServerboundClientCommandPacket = new ServerboundClientCommandPacket(ClientCommand.STATS); - session.sendDownstreamPacket(ServerboundClientCommandPacket); + session.sendDownstreamGamePacket(ServerboundClientCommandPacket); } @Override 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 6ff7f5fb2..aa8460872 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java @@ -36,7 +36,6 @@ import org.geysermc.geyser.text.GeyserLocale; import java.nio.file.Path; import java.util.List; -import java.util.Map; public interface GeyserConfiguration { /** @@ -55,9 +54,6 @@ public interface GeyserConfiguration { List<String> getSavedUserLogins(); - @Deprecated - Map<String, ? extends IUserAuthenticationInfo> getUserAuths(); - boolean isCommandSuggestions(); @JsonIgnore @@ -149,8 +145,6 @@ public interface GeyserConfiguration { void setPort(int port); - boolean isPasswordAuthentication(); - boolean isUseProxyProtocol(); boolean isForwardHost(); @@ -173,18 +167,6 @@ public interface GeyserConfiguration { boolean replaceSpaces(); } - interface IUserAuthenticationInfo { - String getEmail(); - - String getPassword(); - - /** - * Will be removed after Microsoft accounts are fully migrated - */ - @Deprecated - boolean isMicrosoftAccount(); - } - interface IMetricsInfo { boolean isEnabled(); 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 00cb92fae..56ca605db 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -44,7 +44,6 @@ import java.io.IOException; import java.nio.file.Path; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.UUID; import java.util.stream.Collectors; @@ -79,8 +78,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration public abstract Path getFloodgateKeyPath(); - private Map<String, UserAuthenticationInfo> userAuths; - @JsonProperty("command-suggestions") private boolean commandSuggestions = true; @@ -287,10 +284,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration return false; } - @Getter - @JsonProperty("allow-password-authentication") - private boolean passwordAuthentication = true; - @Getter @JsonProperty("use-proxy-protocol") private boolean useProxyProtocol = false; @@ -300,19 +293,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration private boolean forwardHost = false; } - @Getter - @JsonIgnoreProperties(ignoreUnknown = true) // DO NOT REMOVE THIS! Otherwise, after we remove microsoft-account configs will not load - public static class UserAuthenticationInfo implements IUserAuthenticationInfo { - @AsteriskSerializer.Asterisk() - private String email; - - @AsteriskSerializer.Asterisk() - private String password; - - @JsonProperty("microsoft-account") - private boolean microsoftAccount = false; - } - @Getter @JsonIgnoreProperties(ignoreUnknown = true) public static class MetricsInfo implements IMetricsInfo { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java index c88f90f19..0917465d4 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java @@ -68,7 +68,7 @@ public class InteractionEntity extends Entity { animatePacket.setAction(AnimatePacket.Action.SWING_ARM); session.sendUpstreamPacket(animatePacket); - session.sendDownstreamPacket(new ServerboundSwingPacket(hand)); + session.sendDownstreamGamePacket(new ServerboundSwingPacket(hand)); return InteractionResult.SUCCESS; } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java index 30d6ac856..dca11dfcd 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionClassLoader.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.extension; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; @@ -39,14 +40,17 @@ import java.nio.file.Path; public class GeyserExtensionClassLoader extends URLClassLoader { private final GeyserExtensionLoader loader; + private final ExtensionDescription description; private final Object2ObjectMap<String, Class<?>> classes = new Object2ObjectOpenHashMap<>(); + private boolean warnedForExternalClassAccess; - public GeyserExtensionClassLoader(GeyserExtensionLoader loader, ClassLoader parent, Path path) throws MalformedURLException { + public GeyserExtensionClassLoader(GeyserExtensionLoader loader, ClassLoader parent, Path path, ExtensionDescription description) throws MalformedURLException { super(new URL[] { path.toUri().toURL() }, parent); this.loader = loader; + this.description = description; } - public Extension load(ExtensionDescription description) throws InvalidExtensionException { + public Extension load() throws InvalidExtensionException { try { Class<?> jarClass; try { @@ -76,22 +80,32 @@ public class GeyserExtensionClassLoader extends URLClassLoader { } protected Class<?> findClass(String name, boolean checkGlobal) throws ClassNotFoundException { - if (name.startsWith("org.geysermc.geyser.") || name.startsWith("net.minecraft.")) { - throw new ClassNotFoundException(name); - } - Class<?> result = this.classes.get(name); if (result == null) { - result = super.findClass(name); - if (result == null && checkGlobal) { - result = this.loader.classByName(name); + // Try to find class in current extension + try { + result = super.findClass(name); + } catch (ClassNotFoundException ignored) { + // If class is not found in current extension, check in the global class loader + // This is used for classes that are not in the extension, but are in other extensions + if (checkGlobal) { + if (!warnedForExternalClassAccess) { + GeyserImpl.getInstance().getLogger().warning("Extension " + this.description.name() + " loads class " + name + " from an external source. " + + "This can change at any time and break the extension, additionally to potentially causing unexpected behaviour!"); + warnedForExternalClassAccess = true; + } + result = this.loader.classByName(name); + } } if (result != null) { + // If class is found, cache it this.loader.setClass(name, result); + this.classes.put(name, result); + } else { + // If class is not found, throw exception + throw new ClassNotFoundException(name); } - - this.classes.put(name, result); } return result; } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index 7e998e413..da0fbffda 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -43,9 +43,9 @@ import java.io.Reader; import java.nio.file.*; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.regex.Pattern; -import java.util.stream.Stream; @RequiredArgsConstructor public class GeyserExtensionLoader extends ExtensionLoader { @@ -66,26 +66,38 @@ public class GeyserExtensionLoader extends ExtensionLoader { } Path parentFile = path.getParent(); - Path dataFolder = parentFile.resolve(description.name()); + + // Extension folders used to be created by name; this changes them to the ID + Path oldDataFolder = parentFile.resolve(description.name()); + Path dataFolder = parentFile.resolve(description.id()); + + if (Files.exists(oldDataFolder) && Files.isDirectory(oldDataFolder) && !oldDataFolder.equals(dataFolder)) { + try { + Files.move(oldDataFolder, dataFolder, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + throw new InvalidExtensionException("Failed to move data folder for extension " + description.name(), e); + } + } + if (Files.exists(dataFolder) && !Files.isDirectory(dataFolder)) { throw new InvalidExtensionException("The folder " + dataFolder + " is not a directory and is the data folder for the extension " + description.name() + "!"); } final GeyserExtensionClassLoader loader; try { - loader = new GeyserExtensionClassLoader(this, getClass().getClassLoader(), path); + loader = new GeyserExtensionClassLoader(this, getClass().getClassLoader(), path, description); } catch (Throwable e) { throw new InvalidExtensionException(e); } - this.classLoaders.put(description.name(), loader); + this.classLoaders.put(description.id(), loader); - final Extension extension = loader.load(description); + final Extension extension = loader.load(); return this.setup(extension, description, dataFolder, new GeyserExtensionEventBus(GeyserImpl.getInstance().eventBus(), extension)); } private GeyserExtensionContainer setup(Extension extension, GeyserExtensionDescription description, Path dataFolder, ExtensionEventBus eventBus) { - GeyserExtensionLogger logger = new GeyserExtensionLogger(GeyserImpl.getInstance().getLogger(), description.name()); + GeyserExtensionLogger logger = new GeyserExtensionLogger(GeyserImpl.getInstance().getLogger(), description.id()); return new GeyserExtensionContainer(extension, dataFolder, description, this, logger, eventBus); } @@ -136,46 +148,46 @@ public class GeyserExtensionLoader extends ExtensionLoader { Map<String, GeyserExtensionContainer> loadedExtensions = new LinkedHashMap<>(); Pattern[] extensionFilters = this.extensionFilters(); - try (Stream<Path> entries = Files.walk(extensionsDirectory)) { - entries.forEach(path -> { - if (Files.isDirectory(path)) { + List<Path> extensionPaths = Files.walk(extensionsDirectory).toList(); + extensionPaths.forEach(path -> { + if (Files.isDirectory(path)) { + return; + } + + for (Pattern filter : extensionFilters) { + if (!filter.matcher(path.getFileName().toString()).matches()) { + return; + } + } + + try { + GeyserExtensionDescription description = this.extensionDescription(path); + + String name = description.name(); + String id = description.id(); + if (extensions.containsKey(id) || extensionManager.extension(id) != null) { + GeyserImpl.getInstance().getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.extensions.load.duplicate", name, path.toString())); return; } - for (Pattern filter : extensionFilters) { - if (!filter.matcher(path.getFileName().toString()).matches()) { - return; - } + // Completely different API version + if (description.majorApiVersion() != Geyser.api().majorApiVersion()) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion())); + return; } - try { - GeyserExtensionDescription description = this.extensionDescription(path); - - String name = description.name(); - if (extensions.containsKey(name) || extensionManager.extension(name) != null) { - GeyserImpl.getInstance().getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.extensions.load.duplicate", name, path.toString())); - return; - } - - // Completely different API version - if (description.majorApiVersion() != Geyser.api().majorApiVersion()) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion())); - return; - } - - // If the extension requires new API features, being backwards compatible - if (description.minorApiVersion() > Geyser.api().minorApiVersion()) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion())); - return; - } - - extensions.put(name, path); - loadedExtensions.put(name, this.loadExtension(path, description)); - } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_with_name", path.getFileName(), path.toAbsolutePath()), e); + // If the extension requires new API features, being backwards compatible + if (description.minorApiVersion() > Geyser.api().minorApiVersion()) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_api_version", name, description.apiVersion())); + return; } - }); - } + + extensions.put(id, path); + loadedExtensions.put(id, this.loadExtension(path, description)); + } catch (Exception e) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.extensions.load.failed_with_name", path.getFileName(), path.toAbsolutePath()), e); + } + }); for (GeyserExtensionContainer container : loadedExtensions.values()) { this.extensionContainers.put(container.extension(), container); diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java index 5dd924301..3c41c4329 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java @@ -52,8 +52,8 @@ public class GeyserExtensionManager extends ExtensionManager { } @Override - public Extension extension(@NonNull String name) { - return this.extensions.get(name); + public Extension extension(@NonNull String id) { + return this.extensions.get(id); } @Override @@ -83,7 +83,7 @@ public class GeyserExtensionManager extends ExtensionManager { if (!extension.isEnabled()) { extension.setEnabled(true); GeyserImpl.getInstance().eventBus().register(extension, extension); - GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.enable.success", extension.description().name())); + GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.enable.success", extension.name())); } } @@ -98,7 +98,7 @@ public class GeyserExtensionManager extends ExtensionManager { GeyserImpl.getInstance().eventBus().unregisterAll(extension); extension.setEnabled(false); - GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.disable.success", extension.description().name())); + GeyserImpl.getInstance().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.extensions.disable.success", extension.name())); } } @@ -121,6 +121,6 @@ public class GeyserExtensionManager extends ExtensionManager { @Override public void register(@NonNull Extension extension) { - this.extensions.put(extension.name(), extension); + this.extensions.put(extension.description().id(), extension); } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java index 5b0800e44..e99b901a4 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java @@ -82,14 +82,14 @@ public class AnvilContainer extends Container { correctRename = plainNewName; // Java Edition sends a packet every time an item is renamed even slightly in GUI. Fortunately, this works out for us now ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(plainNewName); - session.sendDownstreamPacket(renameItemPacket); + session.sendDownstreamGamePacket(renameItemPacket); } else { // Restore formatting for item since we're not renaming correctRename = MessageTranslator.convertMessageLenient(originalName); // Java Edition sends the original custom name when not renaming, // if there isn't a custom name an empty string is sent ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(plainOriginalName); - session.sendDownstreamPacket(renameItemPacket); + session.sendDownstreamGamePacket(renameItemPacket); } useJavaLevelCost = false; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java index bfe5a7d9d..f31f6d82f 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java @@ -152,7 +152,7 @@ public final class ClickPlan { changedItems ); - session.sendDownstreamPacket(clickPacket); + session.sendDownstreamGamePacket(clickPacket); } session.getPlayerInventory().setCursor(simulatedCursor, session); diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java b/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java index ddc44fbc4..e45667fe2 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java @@ -31,7 +31,7 @@ import java.util.Locale; /** * Potion identifiers and their respective Bedrock IDs used with arrows. - * https://minecraft.gamepedia.com/Arrow#Item_Data + * https://minecraft.wiki/w/Arrow#Data_values */ @Getter public enum TippedArrowPotion { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java index ea4ef674b..aa7897038 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java @@ -120,7 +120,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater { // does not result in a FilterTextPacket String originalName = MessageTranslator.convertToPlainTextLenient(ItemUtils.getCustomName(input.getNbt()), session.locale()); ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(originalName); - session.sendDownstreamPacket(renameItemPacket); + session.sendDownstreamGamePacket(renameItemPacket); anvilContainer.setNewName(null); } diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java b/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java index fc3c86dd4..936248afe 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java @@ -52,11 +52,6 @@ public class GeyserAdvancement { return this.advancement.getId(); } - @NonNull - public List<String> getCriteria() { - return this.advancement.getCriteria(); - } - @NonNull public List<List<String>> getRequirements() { return this.advancement.getRequirements(); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index a686ba552..97ab18c6b 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -173,8 +173,8 @@ public final class BlockStateValues { } if (javaId.contains("wall_skull") || javaId.contains("wall_head")) { - String direction = javaId.substring(javaId.lastIndexOf("facing=") + 7); - int rotation = switch (direction.substring(0, direction.length() - 1)) { + String direction = javaId.substring(javaId.lastIndexOf("facing=") + 7, javaId.lastIndexOf("powered=") - 1); + int rotation = switch (direction) { case "north" -> 180; case "west" -> 90; case "east" -> 270; diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 63cce329c..fb9684f77 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -46,7 +46,9 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v618.CODEC; + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v618.CODEC.toBuilder() + .minecraftVersion("1.20.31") + .build(); /** * A list of all supported Bedrock versions that can join Geyser @@ -66,7 +68,9 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(Bedrock_v594.CODEC.toBuilder() .minecraftVersion("1.20.10/1.20.15") .build()); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.20.30/1.20.31") + .build()); } /** diff --git a/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java b/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java index 35d2d7f33..f19a46e6a 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java +++ b/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java @@ -47,6 +47,10 @@ public class GeyserServerInitializer extends BedrockServerInitializer { this.geyser = geyser; } + public DefaultEventLoopGroup getEventLoopGroup() { + return eventLoopGroup; + } + @Override public void initSession(@Nonnull BedrockServerSession bedrockServerSession) { try { @@ -72,4 +76,4 @@ public class GeyserServerInitializer extends BedrockServerInitializer { protected BedrockPeer createPeer(Channel channel) { return new GeyserBedrockPeer(channel, this::createSession); } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java index 6b43422e5..361aaffb9 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -52,7 +52,6 @@ import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.pack.PackCodec; import org.geysermc.geyser.api.pack.ResourcePack; import org.geysermc.geyser.api.pack.ResourcePackManifest; -import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.event.type.SessionLoadResourcePacksEventImpl; import org.geysermc.geyser.pack.GeyserResourcePack; import org.geysermc.geyser.registry.BlockRegistries; @@ -257,21 +256,9 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { return true; } } - if (geyser.getConfig().getUserAuths() != null) { - GeyserConfiguration.IUserAuthenticationInfo info = geyser.getConfig().getUserAuths().get(bedrockUsername); - - if (info != null) { - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.stored_credentials", session.getAuthData().name())); - session.setMicrosoftAccount(info.isMicrosoftAccount()); - session.authenticate(info.getEmail(), info.getPassword()); - return true; - } - } PendingMicrosoftAuthentication.AuthenticationTask task = geyser.getPendingMicrosoftAuthentication().getTask(session.getAuthData().xuid()); if (task != null) { - if (task.getAuthentication().isDone() && session.onMicrosoftLoginComplete(task)) { - return true; - } + return task.getAuthentication().isDone() && session.onMicrosoftLoginComplete(task); } return false; diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index df9e1e9d9..6fbb29157 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -39,6 +39,7 @@ import io.netty.channel.kqueue.KQueueEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.util.concurrent.Future; import lombok.Getter; import net.jodah.expiringmap.ExpirationPolicy; import net.jodah.expiringmap.ExpiringMap; @@ -58,6 +59,7 @@ import org.geysermc.geyser.network.netty.handler.RakPingHandler; import org.geysermc.geyser.network.netty.proxy.ProxyServerHandler; import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.ping.IGeyserPingPassthrough; +import org.geysermc.geyser.skin.SkinProvider; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -83,14 +85,21 @@ public final class GeyserServer { private static final Transport TRANSPORT = compatibleTransport(); + /** + * See {@link EventLoopGroup#shutdownGracefully(long, long, TimeUnit)} + */ + private static final int SHUTDOWN_QUIET_PERIOD_MS = 100; + private static final int SHUTDOWN_TIMEOUT_MS = 500; + private final GeyserImpl geyser; - private final EventLoopGroup group; + private EventLoopGroup group; private final ServerBootstrap bootstrap; + private EventLoopGroup playerGroup; @Getter private final ExpiringMap<InetSocketAddress, InetSocketAddress> proxiedAddresses; - private ChannelFuture future; + private ChannelFuture bootstrapFuture; public GeyserServer(GeyserImpl geyser, int threadCount) { this.geyser = geyser; @@ -109,7 +118,7 @@ public final class GeyserServer { public CompletableFuture<Void> bind(InetSocketAddress address) { CompletableFuture<Void> future = new CompletableFuture<>(); - this.future = this.bootstrap.bind(address).addListener(bindResult -> { + this.bootstrapFuture = this.bootstrap.bind(address).addListener(bindResult -> { if (bindResult.cause() != null) { future.completeExceptionally(bindResult.cause()); return; @@ -117,7 +126,7 @@ public final class GeyserServer { future.complete(null); }); - Channel channel = this.future.channel(); + Channel channel = this.bootstrapFuture.channel(); // Add our ping handler channel.pipeline() @@ -132,8 +141,19 @@ public final class GeyserServer { } public void shutdown() { - this.group.shutdownGracefully(); - this.future.channel().closeFuture().syncUninterruptibly(); + try { + Future<?> future1 = this.group.shutdownGracefully(SHUTDOWN_QUIET_PERIOD_MS, SHUTDOWN_TIMEOUT_MS, TimeUnit.MILLISECONDS); + this.group = null; + Future<?> future2 = this.playerGroup.shutdownGracefully(SHUTDOWN_QUIET_PERIOD_MS, SHUTDOWN_TIMEOUT_MS, TimeUnit.MILLISECONDS); + this.playerGroup = null; + future1.sync(); + future2.sync(); + + SkinProvider.shutdown(); + } catch (InterruptedException e) { + GeyserImpl.getInstance().getLogger().severe("Exception in shutdown process", e); + } + this.bootstrapFuture.channel().closeFuture().syncUninterruptibly(); } private ServerBootstrap createBootstrap(EventLoopGroup group) { @@ -149,11 +169,13 @@ public final class GeyserServer { } } + GeyserServerInitializer serverInitializer = new GeyserServerInitializer(this.geyser); + playerGroup = serverInitializer.getEventLoopGroup(); return new ServerBootstrap() .channelFactory(RakChannelFactory.server(TRANSPORT.datagramChannel())) .group(group) .option(RakChannelOption.RAK_HANDLE_PING, true) - .childHandler(new GeyserServerInitializer(this.geyser)); + .childHandler(serverInitializer); } public boolean onConnectionRequest(InetSocketAddress inetSocketAddress) { @@ -217,7 +239,7 @@ public final class GeyserServer { .version(GameProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()) // Required to not be empty as of 1.16.210.59. Can only contain . and numbers. .ipv4Port(this.geyser.getConfig().getBedrock().port()) .ipv6Port(this.geyser.getConfig().getBedrock().port()) - .serverId(future.channel().config().getOption(RakChannelOption.RAK_GUID)); + .serverId(bootstrapFuture.channel().config().getOption(RakChannelOption.RAK_GUID)); if (config.isPassthroughMotd() && pingInfo != null && pingInfo.getDescription() != null) { String[] motd = MessageTranslator.convertMessageLenient(pingInfo.getDescription()).split("\n"); 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 dbc8e2e26..e37f8aa64 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java @@ -27,9 +27,9 @@ package org.geysermc.geyser.registry; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDelimiterPacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundTabListPacket; +import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundChunkBatchStartPacket; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLightUpdatePacket; import io.netty.channel.EventLoop; -import org.cloudburstmc.protocol.bedrock.packet.RequestPermissionsPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.registry.loader.RegistryLoaders; import org.geysermc.geyser.session.GeyserSession; @@ -44,10 +44,10 @@ public class PacketTranslatorRegistry<T> extends AbstractMappedRegistry<Class<? private static final Set<Class<?>> IGNORED_PACKETS = Collections.newSetFromMap(new IdentityHashMap<>()); static { + IGNORED_PACKETS.add(ClientboundChunkBatchStartPacket.class); // we don't track chunk batch sizes/periods + IGNORED_PACKETS.add(ClientboundDelimiterPacket.class); // Not implemented, spams logs IGNORED_PACKETS.add(ClientboundLightUpdatePacket.class); // Light is handled on Bedrock for us IGNORED_PACKETS.add(ClientboundTabListPacket.class); // Cant be implemented in Bedrock - IGNORED_PACKETS.add(ClientboundDelimiterPacket.class); // Not implemented, spams logs - IGNORED_PACKETS.add(RequestPermissionsPacket.class); // Bedrock client asks permission to switch default game mode, but we handle this ourselves } protected PacketTranslatorRegistry() { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java index c9ed51166..e4bf43b93 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/CustomBlockRegistryPopulator.java @@ -72,9 +72,9 @@ public class CustomBlockRegistryPopulator { private static Set<CustomBlockData> CUSTOM_BLOCKS; private static Set<String> CUSTOM_BLOCK_NAMES; - private static Int2ObjectMap<CustomBlockState> BLOCK_STATE_OVERRIDES; private static Map<String, CustomBlockData> CUSTOM_BLOCK_ITEM_OVERRIDES; private static Map<JavaBlockState, CustomBlockState> NON_VANILLA_BLOCK_STATE_OVERRIDES; + private static Map<String, CustomBlockState> BLOCK_STATE_OVERRIDES_QUEUE; /** * Initializes custom blocks defined by API @@ -82,9 +82,9 @@ public class CustomBlockRegistryPopulator { private static void populateBedrock() { CUSTOM_BLOCKS = new ObjectOpenHashSet<>(); CUSTOM_BLOCK_NAMES = new ObjectOpenHashSet<>(); - BLOCK_STATE_OVERRIDES = new Int2ObjectOpenHashMap<>(); CUSTOM_BLOCK_ITEM_OVERRIDES = new HashMap<>(); NON_VANILLA_BLOCK_STATE_OVERRIDES = new HashMap<>(); + BLOCK_STATE_OVERRIDES_QUEUE = new HashMap<>(); GeyserImpl.getInstance().getEventBus().fire(new GeyserDefineCustomBlocksEvent() { @Override @@ -103,18 +103,11 @@ public class CustomBlockRegistryPopulator { @Override public void registerOverride(@NonNull String javaIdentifier, @NonNull CustomBlockState customBlockState) { - int id = BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(javaIdentifier, -1); - if (id == -1) { - throw new IllegalArgumentException("Unknown Java block state. Identifier: " + javaIdentifier); - } if (!CUSTOM_BLOCKS.contains(customBlockState.block())) { throw new IllegalArgumentException("Custom block is unregistered. Name: " + customBlockState.name()); } - CustomBlockState oldBlockState = BLOCK_STATE_OVERRIDES.put(id, customBlockState); - if (oldBlockState != null) { - GeyserImpl.getInstance().getLogger().debug("Duplicate block state override for Java Identifier: " + - javaIdentifier + " Old override: " + oldBlockState.name() + " New override: " + customBlockState.name()); - } + // We can't register these yet as we don't have the java block id registry populated + BLOCK_STATE_OVERRIDES_QUEUE.put(javaIdentifier, customBlockState); } @Override @@ -139,10 +132,28 @@ public class CustomBlockRegistryPopulator { * Registers all vanilla custom blocks and skulls defined by API and mappings */ private static void populateVanilla() { + Int2ObjectMap<CustomBlockState> blockStateOverrides = new Int2ObjectOpenHashMap<>(); + for (CustomSkull customSkull : BlockRegistries.CUSTOM_SKULLS.get().values()) { CUSTOM_BLOCKS.add(customSkull.getCustomBlockData()); } + for(Map.Entry<String, CustomBlockState> entry : BLOCK_STATE_OVERRIDES_QUEUE.entrySet()) { + int id = BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(entry.getKey(), -1); + if (id == -1) { + GeyserImpl.getInstance().getLogger().warning("Custom block state override for Java Identifier: " + + entry.getKey() + " could not be registered as it is not a valid block state."); + continue; + } + + CustomBlockState oldBlockState = blockStateOverrides.put(id, entry.getValue()); + if (oldBlockState != null) { + GeyserImpl.getInstance().getLogger().warning("Duplicate block state override for Java Identifier: " + + entry.getKey() + " Old override: " + oldBlockState.name() + " New override: " + entry.getValue().name()); + } + } + BLOCK_STATE_OVERRIDES_QUEUE = null; + Map<CustomBlockData, Set<Integer>> extendedCollisionBoxes = new HashMap<>(); Map<BoxComponent, CustomBlockData> extendedCollisionBoxSet = new HashMap<>(); MappingsConfigReader mappingsConfigReader = new MappingsConfigReader(); @@ -153,7 +164,7 @@ public class CustomBlockRegistryPopulator { } block.states().forEach((javaIdentifier, customBlockState) -> { int id = BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(javaIdentifier, -1); - BLOCK_STATE_OVERRIDES.put(id, customBlockState.state()); + blockStateOverrides.put(id, customBlockState.state()); BoxComponent extendedCollisionBox = customBlockState.extendedCollisionBox(); if (extendedCollisionBox != null) { CustomBlockData extendedCollisionBlock = extendedCollisionBoxSet.computeIfAbsent(extendedCollisionBox, box -> { @@ -167,9 +178,9 @@ public class CustomBlockRegistryPopulator { }); }); - BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.set(BLOCK_STATE_OVERRIDES); - if (BLOCK_STATE_OVERRIDES.size() != 0) { - GeyserImpl.getInstance().getLogger().info("Registered " + BLOCK_STATE_OVERRIDES.size() + " custom block overrides."); + BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.set(blockStateOverrides); + if (blockStateOverrides.size() != 0) { + GeyserImpl.getInstance().getLogger().info("Registered " + blockStateOverrides.size() + " custom block overrides."); } BlockRegistries.CUSTOM_BLOCK_ITEM_OVERRIDES.set(CUSTOM_BLOCK_ITEM_OVERRIDES); 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 f0d08f178..5a8512c2b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -26,10 +26,7 @@ package org.geysermc.geyser.session; import com.github.steveice10.mc.auth.data.GameProfile; -import com.github.steveice10.mc.auth.exception.request.InvalidCredentialsException; import com.github.steveice10.mc.auth.exception.request.RequestException; -import com.github.steveice10.mc.auth.service.AuthenticationService; -import com.github.steveice10.mc.auth.service.MojangAuthenticationService; import com.github.steveice10.mc.auth.service.MsaAuthenticationService; import com.github.steveice10.mc.protocol.MinecraftConstants; import com.github.steveice10.mc.protocol.MinecraftProtocol; @@ -45,15 +42,15 @@ import com.github.steveice10.mc.protocol.data.game.setting.ChatVisibility; import com.github.steveice10.mc.protocol.data.game.setting.SkinPart; import com.github.steveice10.mc.protocol.data.game.statistic.CustomStatistic; import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; +import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundClientInformationPacket; import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientIntentionPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientInformationPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; -import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket; +import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket; import com.github.steveice10.packetlib.BuiltinFlags; import com.github.steveice10.packetlib.Session; import com.github.steveice10.packetlib.event.session.ConnectedEvent; @@ -253,10 +250,6 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti @Setter private RemoteServer remoteServer; - @Deprecated - @Setter - private boolean microsoftAccount; - private final SessionPlayerEntity playerEntity; private final AdvancementsCache advancementsCache; @@ -355,7 +348,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti private Vector2i lastChunkPosition = null; @Setter private int clientRenderDistance = -1; - private int serverRenderDistance; + private int serverRenderDistance = -1; // Exposed for GeyserConnect usage protected boolean sentSpawnPacket; @@ -764,76 +757,20 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti } public void authenticate(String username) { - authenticate(username, ""); - } - - public void authenticate(String username, String password) { if (loggedIn) { geyser.getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.auth.already_loggedin", username)); return; } loggingIn = true; + // Always replace spaces with underscores to avoid illegal nicknames, e.g. with GeyserConnect + protocol = new MinecraftProtocol(username.replace(' ', '_')); - // Use a future to prevent timeouts as all the authentication is handled sync - CompletableFuture.supplyAsync(() -> { - try { - if (password != null && !password.isEmpty()) { - AuthenticationService authenticationService; - if (microsoftAccount) { - authenticationService = new MsaAuthenticationService(GeyserImpl.OAUTH_CLIENT_ID); - } else { - authenticationService = new MojangAuthenticationService(); - } - authenticationService.setUsername(username); - authenticationService.setPassword(password); - authenticationService.login(); - - GameProfile profile = authenticationService.getSelectedProfile(); - if (profile == null) { - // Java account is offline - disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.remote.invalid_account", clientData.getLanguageCode())); - return null; - } - - protocol = new MinecraftProtocol(profile, authenticationService.getAccessToken()); - } else { - // always replace spaces when using Floodgate, - // as usernames with spaces cause issues with Bungeecord's login cycle. - // However, this doesn't affect the final username as Floodgate is still in charge of that. - // So if you have (for example) replace spaces enabled on Floodgate the spaces will re-appear. - String validUsername = username; - if (this.remoteServer.authType() == AuthType.FLOODGATE) { - validUsername = username.replace(' ', '_'); - } - - protocol = new MinecraftProtocol(validUsername); - } - } catch (InvalidCredentialsException | IllegalArgumentException e) { - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.login.invalid", username)); - disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.invalid.kick", getClientData().getLanguageCode())); - } catch (RequestException ex) { - disconnect(ex.getMessage()); - } - return null; - }).whenComplete((aVoid, ex) -> { - if (ex != null) { - disconnect(ex.toString()); - } - if (this.closed) { - if (ex != null) { - geyser.getLogger().error("", ex); - } - // Client disconnected during the authentication attempt - return; - } - - try { - connectDownstream(); - } catch (Throwable t) { - t.printStackTrace(); - } - }); + try { + connectDownstream(); + } catch (Throwable t) { + t.printStackTrace(); + } } public void authenticateWithRefreshToken(String refreshToken) { @@ -1240,7 +1177,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti if (position != null) { ServerboundMovePlayerPosPacket packet = new ServerboundMovePlayerPosPacket(playerEntity.isOnGround(), position.getX(), position.getY(), position.getZ()); - sendDownstreamPacket(packet); + sendDownstreamGamePacket(packet); } lastMovementTimestamp = System.currentTimeMillis(); } @@ -1422,7 +1359,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti return false; } - sendDownstreamPacket(useItemPacket); + sendDownstreamGamePacket(useItemPacket); playerEntity.setFlag(EntityFlag.BLOCKING, true); // Metadata should be updated later return true; @@ -1456,7 +1393,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti if (playerEntity.getFlag(EntityFlag.BLOCKING)) { ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, Vector3i.ZERO, Direction.DOWN, 0); - sendDownstreamPacket(releaseItemPacket); + sendDownstreamGamePacket(releaseItemPacket); playerEntity.setFlag(EntityFlag.BLOCKING, false); return true; } @@ -1466,7 +1403,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti public void requestOffhandSwap() { ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO, Direction.DOWN, 0); - sendDownstreamPacket(swapHandsPacket); + sendDownstreamGamePacket(swapHandsPacket); } @Override @@ -1501,14 +1438,14 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti * Sends a chat message to the Java server. */ public void sendChat(String message) { - sendDownstreamPacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, null, 0, new BitSet())); + sendDownstreamGamePacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, null, 0, new BitSet())); } /** * Sends a command to the Java server. */ public void sendCommand(String command) { - sendDownstreamPacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), 0, new BitSet())); + sendDownstreamGamePacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyList(), 0, new BitSet())); } public void setServerRenderDistance(int renderDistance) { @@ -1660,6 +1597,39 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti upstream.sendPacketImmediately(packet); } + /** + * Send a packet to the remote server if in the game state. + * + * @param packet the java edition packet from MCProtocolLib + */ + public void sendDownstreamGamePacket(Packet packet) { + sendDownstreamPacket(packet, ProtocolState.GAME); + } + + /** + * Send a packet to the remote server if in the login state. + * + * @param packet the java edition packet from MCProtocolLib + */ + public void sendDownstreamLoginPacket(Packet packet) { + sendDownstreamPacket(packet, ProtocolState.LOGIN); + } + + /** + * Send a packet to the remote server if in the specified state. + * + * @param packet the java edition packet from MCProtocolLib + * @param intendedState the state the client should be in + */ + public void sendDownstreamPacket(Packet packet, ProtocolState intendedState) { + if (protocol.getState() != intendedState) { + geyser.getLogger().debug("Tried to send " + packet.getClass().getSimpleName() + " packet while not in " + intendedState.name() + " state"); + return; + } + + sendDownstreamPacket(packet); + } + /** * Send a packet to the remote server. * @@ -1687,7 +1657,8 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti } private void sendDownstreamPacket0(Packet packet) { - if (protocol.getState().equals(ProtocolState.GAME) || packet.getClass() == ServerboundCustomQueryPacket.class) { + ProtocolState state = protocol.getState(); + if (state == ProtocolState.GAME || state == ProtocolState.CONFIGURATION || packet.getClass() == ServerboundCustomQueryAnswerPacket.class) { downstream.sendPacket(packet); } else { geyser.getLogger().debug("Tried to send downstream packet " + packet.getClass().getSimpleName() + " before connected to the server"); @@ -1802,7 +1773,7 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti // We're "flying locked" in this gamemode flying = true; ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(true); - sendDownstreamPacket(abilitiesPacket); + sendDownstreamGamePacket(abilitiesPacket); } abilities.add(Ability.FLYING); } @@ -1846,8 +1817,11 @@ public class GeyserSession extends FloodgateConnection implements GeyserConnecti if (clientRenderDistance != -1) { // The client has sent a render distance return clientRenderDistance; + } else if (serverRenderDistance != -1) { + // only known once ClientboundLoginPacket is received + return serverRenderDistance; } - return serverRenderDistance; + return 2; // unfortunate default until we got more info } // We need to send our skin parts to the server otherwise java sees us with no hat, jacket etc diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java index 1e1cc8b00..3562f0d4d 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java @@ -97,7 +97,7 @@ public class AdvancementsCache { } else { // Send a packet indicating that we intend to open this particular advancement window ServerboundSeenAdvancementsPacket packet = new ServerboundSeenAdvancementsPacket(id); - session.sendDownstreamPacket(packet); + session.sendDownstreamGamePacket(packet); // Wait for a response there } } @@ -137,7 +137,7 @@ public class AdvancementsCache { builder.closedResultHandler(() -> { // Indicate that we have closed the current advancement tab - session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket()); + session.sendDownstreamGamePacket(new ServerboundSeenAdvancementsPacket()); }).validResultHandler((response) -> { if (response.clickedButtonId() < visibleAdvancements.size()) { @@ -146,7 +146,7 @@ public class AdvancementsCache { } else { buildAndShowMenuForm(); // Indicate that we have closed the current advancement tab - session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket()); + session.sendDownstreamGamePacket(new ServerboundSeenAdvancementsPacket()); } }); diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/BookEditCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/BookEditCache.java index 35bea7295..d1ebd0c78 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/BookEditCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/BookEditCache.java @@ -68,7 +68,7 @@ public class BookEditCache { packet = null; return; } - session.sendDownstreamPacket(packet); + session.sendDownstreamGamePacket(packet); packet = null; lastBookUpdate = System.currentTimeMillis(); } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java index ab1dfbe2b..5acfc1f09 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java @@ -25,9 +25,10 @@ package org.geysermc.geyser.session.cache; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateTagsPacket; +import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntLists; +import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.type.Item; @@ -112,7 +113,7 @@ public class TagCache { } } - private IntList load(int[] tags) { + private IntList load(int @Nullable[] tags) { if (tags == null) { return IntLists.EMPTY_LIST; } diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java index 41f750990..f491473be 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java @@ -58,7 +58,7 @@ import java.util.function.Predicate; public class SkinProvider { private static final boolean ALLOW_THIRD_PARTY_CAPES = GeyserImpl.getInstance().getConfig().isAllowThirdPartyCapes(); - static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(ALLOW_THIRD_PARTY_CAPES ? 21 : 14); + static ExecutorService EXECUTOR_SERVICE; static final Skin EMPTY_SKIN; static final Cape EMPTY_CAPE = new Cape("", "no-cape", ByteArrays.EMPTY_ARRAY, -1, true); @@ -133,6 +133,20 @@ public class SkinProvider { WEARING_CUSTOM_SKULL_SLIM = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkullSlim\"}}", wearingCustomSkullSlim, false); } + private static ExecutorService getExecutorService() { + if (EXECUTOR_SERVICE == null) { + EXECUTOR_SERVICE = Executors.newFixedThreadPool(ALLOW_THIRD_PARTY_CAPES ? 21 : 14); + } + return EXECUTOR_SERVICE; + } + + public static void shutdown() { + if (EXECUTOR_SERVICE != null) { + EXECUTOR_SERVICE.shutdown(); + EXECUTOR_SERVICE = null; + } + } + public static void registerCacheImageTask(GeyserImpl geyser) { // Schedule Daily Image Expiry if we are caching them if (geyser.getConfig().getCacheImages() > 0) { @@ -302,7 +316,7 @@ public class SkinProvider { GeyserImpl.getInstance().getLogger().debug("Took " + (System.currentTimeMillis() - time) + "ms for " + playerId); return skinAndCape; - }, EXECUTOR_SERVICE); + }, getExecutorService()); } static CompletableFuture<Skin> requestSkin(UUID playerId, String textureUrl, boolean newThread) { @@ -320,7 +334,7 @@ public class SkinProvider { CompletableFuture<Skin> future; if (newThread) { - future = CompletableFuture.supplyAsync(() -> supplySkin(playerId, textureUrl), EXECUTOR_SERVICE) + future = CompletableFuture.supplyAsync(() -> supplySkin(playerId, textureUrl), getExecutorService()) .whenCompleteAsync((skin, throwable) -> { skin.updated = true; CACHED_JAVA_SKINS.put(textureUrl, skin); @@ -349,7 +363,7 @@ public class SkinProvider { CompletableFuture<Cape> future; if (newThread) { - future = CompletableFuture.supplyAsync(() -> supplyCape(capeUrl, provider), EXECUTOR_SERVICE) + future = CompletableFuture.supplyAsync(() -> supplyCape(capeUrl, provider), getExecutorService()) .whenCompleteAsync((cape, throwable) -> { CACHED_JAVA_CAPES.put(capeUrl, cape); requestedCapes.remove(capeUrl); @@ -388,7 +402,7 @@ public class SkinProvider { CompletableFuture<Skin> future; if (newThread) { - future = CompletableFuture.supplyAsync(() -> supplyEars(skin, earsUrl), EXECUTOR_SERVICE) + future = CompletableFuture.supplyAsync(() -> supplyEars(skin, earsUrl), getExecutorService()) .whenCompleteAsync((outSkin, throwable) -> { }); } else { Skin ears = supplyEars(skin, earsUrl); // blocking @@ -620,7 +634,7 @@ public class SkinProvider { } return null; } - }, EXECUTOR_SERVICE); + }, getExecutorService()); } /** @@ -646,7 +660,7 @@ public class SkinProvider { } return null; } - }, EXECUTOR_SERVICE).thenCompose(uuid -> { + }, getExecutorService()).thenCompose(uuid -> { if (uuid == null) { return CompletableFuture.completedFuture(null); } diff --git a/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java b/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java index 260b45136..00866eda3 100644 --- a/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java +++ b/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java @@ -76,7 +76,7 @@ public class MinecraftLocale { public static void downloadAndLoadLocale(String locale) { locale = locale.toLowerCase(Locale.ROOT); if (locale.equals("nb_no")) { - // Different locale code - https://minecraft.fandom.com/wiki/Language + // Different locale code - https://minecraft.wiki/w/Language locale = "no_no"; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java index db0702e13..00323ce83 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java @@ -114,12 +114,12 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator // Input a beacon payment BeaconPaymentAction beaconPayment = (BeaconPaymentAction) request.getActions()[0]; ServerboundSetBeaconPacket packet = new ServerboundSetBeaconPacket(toJava(beaconPayment.getPrimaryEffect()), toJava(beaconPayment.getSecondaryEffect())); - session.sendDownstreamPacket(packet); + session.sendDownstreamGamePacket(packet); return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet())); } private OptionalInt toJava(int effectChoice) { - return effectChoice == 0 ? OptionalInt.empty() : OptionalInt.of(effectChoice); + return effectChoice == 0 ? OptionalInt.empty() : OptionalInt.of(effectChoice - 1); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java index a1c928c6b..0085a7550 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java @@ -129,7 +129,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla return rejectRequest(request); } ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), javaSlot); - session.sendDownstreamPacket(packet); + session.sendDownstreamGamePacket(packet); return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet())); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index ec0d4534d..92cd8a0d4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -102,7 +102,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { if (session.isDroppingLecternBook()) { // We have to enter the inventory GUI to eject the book ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), 3); - session.sendDownstreamPacket(packet); + session.sendDownstreamGamePacket(packet); session.setDroppingLecternBook(false); InventoryUtils.closeInventory(session, inventory.getJavaId(), false); } else if (lecternContainer.getBlockEntityTag() == null) { @@ -153,7 +153,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { session.getLecternCache().add(position); // Close the window - we will reopen it once the client has this data synced ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(lecternContainer.getJavaId()); - session.sendDownstreamPacket(closeWindowPacket); + session.sendDownstreamGamePacket(closeWindowPacket); InventoryUtils.closeInventory(session, inventory.getJavaId(), false); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index 8fb98a284..0e43ba660 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -149,7 +149,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { // And the Java loom window has a fixed row/width of four // So... Number / 4 = row (so we don't have to bother there), and number % 4 is our column, which leads us back to our index. :) ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), index); - session.sendDownstreamPacket(packet); + session.sendDownstreamGamePacket(packet); GeyserItemStack inputCopy = inventory.getItem(0).copy(1); inputCopy.setNetId(session.getNextItemNetId()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java index e159827e8..c4f958ba1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java @@ -155,7 +155,7 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { private ItemStackResponse handleTrade(GeyserSession session, Inventory inventory, ItemStackRequest request, int tradeChoice) { ServerboundSelectTradePacket packet = new ServerboundSelectTradePacket(tradeChoice); - session.sendDownstreamPacket(packet); + session.sendDownstreamGamePacket(packet); if (session.isEmulatePost1_13Logic()) { // 1.18 Java cooperates nicer than older versions diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index b9468ac4f..613121dfd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -359,7 +359,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket(-1, sourceItem.getItemStack(dropAction.getCount())); - session.sendDownstreamPacket(creativeDropPacket); + session.sendDownstreamGamePacket(creativeDropPacket); sourceItem.sub(dropAction.getCount()); } @@ -494,7 +494,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { dropStack = new ItemStack(javaCreativeItem.getId(), dropAction.getCount(), javaCreativeItem.getNbt()); } ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket(-1, dropStack); - session.sendDownstreamPacket(creativeDropPacket); + session.sendDownstreamGamePacket(creativeDropPacket); break; } default: @@ -515,7 +515,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { ItemStack itemStack = item.isEmpty() ? new ItemStack(-1, 0, null) : item.getItemStack(); ServerboundSetCreativeModeSlotPacket creativePacket = new ServerboundSetCreativeModeSlotPacket(slot, itemStack); - session.sendDownstreamPacket(creativePacket); + session.sendDownstreamGamePacket(creativePacket); } private static boolean isCraftingGrid(ItemStackRequestSlotData slotInfoData) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java index 0663866ed..50c040a0b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java @@ -69,7 +69,7 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl if (container.getStonecutterButton() != button) { // Getting the index of the item in the Java stonecutter list ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getJavaId(), button); - session.sendDownstreamPacket(packet); + session.sendDownstreamGamePacket(packet); container.setStonecutterButton(button); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java index e60342b27..1774d9c76 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DecoratedPotBlockEntityTranslator.java @@ -41,6 +41,10 @@ public class DecoratedPotBlockEntityTranslator extends BlockEntityTranslator { @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + if (tag == null) { + return; + } + // exact same format if (tag.get("sherds") instanceof ListTag sherds) { List<String> translated = new ArrayList<>(4); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java index 60ff187f5..33fbaed30 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java @@ -64,7 +64,7 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> { // and Bedrock 1.19.51. // Note for the future: we should probably largely ignore this packet and instead replicate // all actions on our end, and send swings where needed. - session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); + session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); session.activateArmAnimationTicking(); } }, @@ -77,12 +77,12 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> { // Packet value is a float of how long one has been rowing, so we convert that into a boolean session.setSteeringLeft(packet.getRowingTime() > 0.0); ServerboundPaddleBoatPacket steerLeftPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); - session.sendDownstreamPacket(steerLeftPacket); + session.sendDownstreamGamePacket(steerLeftPacket); } case ROW_RIGHT -> { session.setSteeringRight(packet.getRowingTime() > 0.0); ServerboundPaddleBoatPacket steerRightPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); - session.sendDownstreamPacket(steerRightPacket); + session.sendDownstreamGamePacket(steerRightPacket); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java index f280f144f..bab5e59a5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java @@ -108,7 +108,7 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti if (iterator < lines.length) lines[iterator] = newMessage.toString(); Vector3i pos = Vector3i.from(tag.getInt("x"), tag.getInt("y"), tag.getInt("z")); ServerboundSignUpdatePacket signUpdatePacket = new ServerboundSignUpdatePacket(pos, lines, session.getWorldCache().isEditingSignOnFront()); - session.sendDownstreamPacket(signUpdatePacket); + session.sendDownstreamGamePacket(signUpdatePacket); } else if (id.equals("JigsawBlock")) { // Client has just sent a jigsaw block update @@ -120,7 +120,7 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti String joint = tag.getString("joint"); ServerboundSetJigsawBlockPacket jigsawPacket = new ServerboundSetJigsawBlockPacket(pos, name, target, pool, finalState, joint); - session.sendDownstreamPacket(jigsawPacket); + session.sendDownstreamGamePacket(jigsawPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandBlockUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandBlockUpdateTranslator.java index 42e9277d3..b9561518e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandBlockUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockCommandBlockUpdateTranslator.java @@ -53,13 +53,13 @@ public class BedrockCommandBlockUpdateTranslator extends PacketTranslator<Comman boolean automatic = !packet.isRedstoneMode(); // Automatic = Always Active option in Java ServerboundSetCommandBlockPacket commandBlockPacket = new ServerboundSetCommandBlockPacket( packet.getBlockPosition(), command, mode, outputTracked, isConditional, automatic); - session.sendDownstreamPacket(commandBlockPacket); + session.sendDownstreamGamePacket(commandBlockPacket); } else { ServerboundSetCommandMinecartPacket commandMinecartPacket = new ServerboundSetCommandMinecartPacket( session.getEntityCache().getEntityByGeyserId(packet.getMinecartRuntimeEntityId()).getEntityId(), command, outputTracked ); - session.sendDownstreamPacket(commandMinecartPacket); + session.sendDownstreamGamePacket(commandMinecartPacket); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java index 62dd39b12..e2552802f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockContainerCloseTranslator.java @@ -55,7 +55,7 @@ public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerC if (openInventory != null) { if (bedrockId == openInventory.getBedrockId()) { ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(openInventory.getJavaId()); - session.sendDownstreamPacket(closeWindowPacket); + session.sendDownstreamGamePacket(closeWindowPacket); InventoryUtils.closeInventory(session, openInventory.getJavaId(), false); } else if (openInventory.isPending()) { InventoryUtils.displayInventory(session, openInventory); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java index a614663ed..bf437311d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java @@ -137,7 +137,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve ServerboundContainerClickPacket dropPacket = new ServerboundContainerClickPacket( inventory.getJavaId(), inventory.getStateId(), hotbarSlot, clickType.actionType, clickType.action, inventory.getCursor().getItemStack(), changedItem); - session.sendDownstreamPacket(dropPacket); + session.sendDownstreamGamePacket(dropPacket); return; } if (session.getPlayerInventory().getItemInHand().isEmpty()) { @@ -150,7 +150,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve Direction.DOWN, 0 ); - session.sendDownstreamPacket(dropPacket); + session.sendDownstreamGamePacket(dropPacket); if (dropAll) { session.getPlayerInventory().setItemInHand(GeyserItemStack.EMPTY); @@ -309,7 +309,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(), false, session.getWorldCache().nextPredictionSequence()); - session.sendDownstreamPacket(blockPacket); + session.sendDownstreamGamePacket(blockPacket); Item item = session.getPlayerInventory().getItemInHand().asItem(); if (packet.getItemInHand() != null) { @@ -384,7 +384,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve } ServerboundUseItemPacket useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence()); - session.sendDownstreamPacket(useItemPacket); + session.sendDownstreamGamePacket(useItemPacket); List<LegacySetItemSlotData> legacySlots = packet.getLegacySlots(); if (packet.getActions().size() == 1 && legacySlots.size() > 0) { @@ -453,13 +453,13 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve if (itemFrameEntity != null) { ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(), InteractAction.ATTACK, session.isSneaking()); - session.sendDownstreamPacket(attackPacket); + session.sendDownstreamGamePacket(attackPacket); break; } PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING; ServerboundPlayerActionPacket breakPacket = new ServerboundPlayerActionPacket(action, packet.getBlockPosition(), Direction.VALUES[packet.getBlockFace()], sequence); - session.sendDownstreamPacket(breakPacket); + session.sendDownstreamGamePacket(breakPacket); } } break; @@ -468,7 +468,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve // Followed to the Minecraft Protocol specification outlined at wiki.vg ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, Vector3i.ZERO, Direction.DOWN, 0); - session.sendDownstreamPacket(releaseItemPacket); + session.sendDownstreamGamePacket(releaseItemPacket); } break; case ITEM_USE_ON_ENTITY: @@ -490,7 +490,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve } ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entityId, InteractAction.ATTACK, session.isSneaking()); - session.sendDownstreamPacket(attackPacket); + session.sendDownstreamGamePacket(attackPacket); // Since 1.19.10, LevelSoundEventPackets are no longer sent by the client when attacking entities CooldownUtils.sendCooldown(session); @@ -510,7 +510,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve Vector3f clickPosition = packet.getClickPosition().sub(entityPosition); boolean isSpectator = session.getGameMode() == GameMode.SPECTATOR; for (Hand hand : EntityUtils.HANDS) { - session.sendDownstreamPacket(new ServerboundInteractPacket(entity.getEntityId(), + session.sendDownstreamGamePacket(new ServerboundInteractPacket(entity.getEntityId(), InteractAction.INTERACT_AT, clickPosition.getX(), clickPosition.getY(), clickPosition.getZ(), hand, session.isSneaking())); @@ -522,7 +522,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve } if (!result.consumesAction()) { - session.sendDownstreamPacket(new ServerboundInteractPacket(entity.getEntityId(), + session.sendDownstreamGamePacket(new ServerboundInteractPacket(entity.getEntityId(), InteractAction.INTERACT, hand, session.isSneaking())); if (!isSpectator) { result = entity.interact(hand); @@ -532,7 +532,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve if (result.consumesAction()) { if (result.shouldSwing() && hand == Hand.OFF_HAND) { // Currently, Bedrock will send us the arm swing packet in most cases. But it won't for offhand. - session.sendDownstreamPacket(new ServerboundSwingPacket(hand)); + session.sendDownstreamGamePacket(new ServerboundSwingPacket(hand)); // Note here to look into sending the animation packet back to Bedrock } return; @@ -629,7 +629,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve lookAt(session, target); ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence()); - session.sendDownstreamPacket(itemPacket); + session.sendDownstreamGamePacket(itemPacket); return true; } @@ -671,7 +671,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve ServerboundMovePlayerPosRotPacket returnPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), entity.getYaw(), entity.getPitch()); // This matches Java edition behavior ServerboundMovePlayerPosRotPacket movementPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), yaw, pitch); - session.sendDownstreamPacket(movementPacket); + session.sendDownstreamGamePacket(movementPacket); if (session.getLookBackScheduledFuture() != null) { session.getLookBackScheduledFuture().cancel(false); @@ -683,7 +683,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve // The player moved/rotated so there is no need to change their rotation back return; } - session.sendDownstreamPacket(returnPacket); + session.sendDownstreamGamePacket(returnPacket); }, 150, TimeUnit.MILLISECONDS)); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java index 908599f51..f11fd202c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java @@ -49,7 +49,7 @@ public class BedrockItemFrameDropItemTranslator extends PacketTranslator<ItemFra if (entity != null) { ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(entity.getEntityId(), InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); - session.sendDownstreamPacket(interactPacket); + session.sendDownstreamGamePacket(interactPacket); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockLecternUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockLecternUpdateTranslator.java index d28aafcb9..b2a34d904 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockLecternUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockLecternUpdateTranslator.java @@ -58,7 +58,7 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator<LecternUpda 0, 0, 0, // Java doesn't care about these when dealing with a lectern false, session.getWorldCache().nextPredictionSequence()); - session.sendDownstreamPacket(blockPacket); + session.sendDownstreamGamePacket(blockPacket); } else { // Bedrock wants to either move a page or exit if (!(session.getOpenInventory() instanceof LecternContainer lecternContainer)) { @@ -69,7 +69,7 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator<LecternUpda if (lecternContainer.getCurrentBedrockPage() == packet.getPage()) { // The same page means Bedrock is closing the window ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(lecternContainer.getJavaId()); - session.sendDownstreamPacket(closeWindowPacket); + session.sendDownstreamGamePacket(closeWindowPacket); InventoryUtils.closeInventory(session, lecternContainer.getJavaId(), false); } else { // Each "page" Bedrock gives to us actually represents two pages (think opening a book and seeing two pages) @@ -83,12 +83,12 @@ public class BedrockLecternUpdateTranslator extends PacketTranslator<LecternUpda if (newJavaPage > currentJavaPage) { for (int i = currentJavaPage; i < newJavaPage; i++) { ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 2); - session.sendDownstreamPacket(clickButtonPacket); + session.sendDownstreamGamePacket(clickButtonPacket); } } else { for (int i = currentJavaPage; i > newJavaPage; i--) { ServerboundContainerButtonClickPacket clickButtonPacket = new ServerboundContainerButtonClickPacket(session.getOpenInventory().getJavaId(), 1); - session.sendDownstreamPacket(clickButtonPacket); + session.sendDownstreamGamePacket(clickButtonPacket); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java index d045a6c24..f5086e29a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMobEquipmentTranslator.java @@ -58,7 +58,7 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment session.getPlayerInventory().setHeldItemSlot(newSlot); ServerboundSetCarriedItemPacket setCarriedItemPacket = new ServerboundSetCarriedItemPacket(newSlot); - session.sendDownstreamPacket(setCarriedItemPacket); + session.sendDownstreamGamePacket(setCarriedItemPacket); GeyserItemStack newItem = session.getPlayerInventory().getItemInHand(); @@ -66,7 +66,7 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment // Activate shield since we are already sneaking // (No need to send a release item packet - Java doesn't do this when swapping items) // Required to do it a tick later or else it doesn't register - session.scheduleInEventLoop(() -> session.sendDownstreamPacket(new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence())), + session.scheduleInEventLoop(() -> session.sendDownstreamGamePacket(new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getWorldCache().nextPredictionSequence())), 50, TimeUnit.MILLISECONDS); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java index 4b5107bda..8a8749e34 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java @@ -72,6 +72,6 @@ public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator<MoveEn packet.getPosition().getX(), y, packet.getPosition().getZ(), packet.getRotation().getY() - 90, packet.getRotation().getX() ); - session.sendDownstreamPacket(ServerboundMoveVehiclePacket); + session.sendDownstreamGamePacket(ServerboundMoveVehiclePacket); } } 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 1ccd5ced9..412a97e3a 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 @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundKeepAlivePacket; +import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundKeepAlivePacket; import org.cloudburstmc.protocol.bedrock.data.AttributeData; import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockPlayerInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockPlayerInputTranslator.java index 79833e6ae..1737364ff 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockPlayerInputTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockPlayerInputTranslator.java @@ -50,7 +50,7 @@ public class BedrockPlayerInputTranslator extends PacketTranslator<PlayerInputPa packet.getInputMotion().getX(), packet.getInputMotion().getY(), packet.isJumping(), packet.isSneaking() ); - session.sendDownstreamPacket(playerInputPacket); + session.sendDownstreamGamePacket(playerInputPacket); // Bedrock only sends movement vehicle packets while moving // This allows horses to take damage while standing on magma @@ -83,7 +83,7 @@ public class BedrockPlayerInputTranslator extends PacketTranslator<PlayerInputPa vehiclePosition.getX(), vehiclePosition.getY(), vehiclePosition.getZ(), vehicle.getYaw() - 90, vehicle.getPitch() ); - session.sendDownstreamPacket(moveVehiclePacket); + session.sendDownstreamGamePacket(moveVehiclePacket); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java index 00cd5e5fd..be2b1f28a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java @@ -42,6 +42,7 @@ public class BedrockRequestAbilityTranslator extends PacketTranslator<RequestAbi @Override public void translate(GeyserSession session, RequestAbilityPacket packet) { + // TODO: Since 1.20.30, this was replaced by a START_FLYING and STOP_FLYING case in BedrockActionTranslator if (packet.getAbility() == Ability.FLYING) { boolean isFlying = packet.isBoolValue(); if (!isFlying && session.getGameMode() == GameMode.SPECTATOR) { @@ -57,7 +58,7 @@ public class BedrockRequestAbilityTranslator extends PacketTranslator<RequestAbi session.setFlying(isFlying); ServerboundPlayerAbilitiesPacket abilitiesPacket = new ServerboundPlayerAbilitiesPacket(isFlying); - session.sendDownstreamPacket(abilitiesPacket); + session.sendDownstreamGamePacket(abilitiesPacket); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRespawnTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRespawnTranslator.java index c89f7b6e0..7c4798f80 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRespawnTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRespawnTranslator.java @@ -39,7 +39,7 @@ public class BedrockRespawnTranslator extends PacketTranslator<RespawnPacket> { public void translate(GeyserSession session, RespawnPacket packet) { if (packet.getState() == RespawnPacket.State.CLIENT_READY) { ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN); - session.sendDownstreamPacket(javaRespawnPacket); + session.sendDownstreamGamePacket(javaRespawnPacket); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockShowCreditsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockShowCreditsTranslator.java index 0aec2a5d9..3314975ef 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockShowCreditsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockShowCreditsTranslator.java @@ -39,7 +39,7 @@ public class BedrockShowCreditsTranslator extends PacketTranslator<ShowCreditsPa public void translate(GeyserSession session, ShowCreditsPacket packet) { if (packet.getStatus() == ShowCreditsPacket.Status.END_CREDITS) { ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN); - session.sendDownstreamPacket(javaRespawnPacket); + session.sendDownstreamGamePacket(javaRespawnPacket); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/BedrockEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/BedrockEntityEventTranslator.java index f8b65bf9b..58d5c2018 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/BedrockEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/BedrockEntityEventTranslator.java @@ -49,7 +49,7 @@ public class BedrockEntityEventTranslator extends PacketTranslator<EntityEventPa case COMPLETE_TRADE -> { // Not sent as of 1.18.10 ServerboundSelectTradePacket selectTradePacket = new ServerboundSelectTradePacket(packet.getData()); - session.sendDownstreamPacket(selectTradePacket); + session.sendDownstreamGamePacket(selectTradePacket); session.scheduleInEventLoop(() -> { Inventory openInventory = session.getOpenInventory(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java index 1917ad6d1..bff097248 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java @@ -26,10 +26,6 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; @@ -97,7 +93,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket case START_SWIMMING: if (!entity.getFlag(EntityFlag.SWIMMING)) { ServerboundPlayerCommandPacket startSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING); - session.sendDownstreamPacket(startSwimPacket); + session.sendDownstreamGamePacket(startSwimPacket); session.setSwimming(true); } @@ -106,7 +102,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket // Prevent packet spam when Bedrock players are crawling near the edge of a block if (!session.getCollisionManager().mustPlayerCrawlHere()) { ServerboundPlayerCommandPacket stopSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING); - session.sendDownstreamPacket(stopSwimPacket); + session.sendDownstreamGamePacket(stopSwimPacket); session.setSwimming(false); } @@ -114,45 +110,45 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket case START_GLIDE: // Otherwise gliding will not work in creative ServerboundPlayerAbilitiesPacket playerAbilitiesPacket = new ServerboundPlayerAbilitiesPacket(false); - session.sendDownstreamPacket(playerAbilitiesPacket); + session.sendDownstreamGamePacket(playerAbilitiesPacket); case STOP_GLIDE: ServerboundPlayerCommandPacket glidePacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_ELYTRA_FLYING); - session.sendDownstreamPacket(glidePacket); + session.sendDownstreamGamePacket(glidePacket); break; case START_SNEAK: ServerboundPlayerCommandPacket startSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING); - session.sendDownstreamPacket(startSneakPacket); + session.sendDownstreamGamePacket(startSneakPacket); session.startSneaking(); break; case STOP_SNEAK: ServerboundPlayerCommandPacket stopSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SNEAKING); - session.sendDownstreamPacket(stopSneakPacket); + session.sendDownstreamGamePacket(stopSneakPacket); session.stopSneaking(); break; case START_SPRINT: if (!entity.getFlag(EntityFlag.SWIMMING)) { ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING); - session.sendDownstreamPacket(startSprintPacket); + session.sendDownstreamGamePacket(startSprintPacket); session.setSprinting(true); } break; case STOP_SPRINT: if (!entity.getFlag(EntityFlag.SWIMMING)) { ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING); - session.sendDownstreamPacket(stopSprintPacket); + session.sendDownstreamGamePacket(stopSprintPacket); } session.setSprinting(false); break; case DROP_ITEM: ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM, vector, Direction.VALUES[packet.getFace()], 0); - session.sendDownstreamPacket(dropItemPacket); + session.sendDownstreamGamePacket(dropItemPacket); break; case STOP_SLEEP: ServerboundPlayerCommandPacket stopSleepingPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.LEAVE_BED); - session.sendDownstreamPacket(stopSleepingPacket); + session.sendDownstreamGamePacket(stopSleepingPacket); break; case START_BREAK: { // Ignore START_BREAK when the player is CREATIVE to avoid Spigot receiving 2 packets it interpets as block breaking. https://github.com/GeyserMC/Geyser/issues/4021 @@ -189,12 +185,12 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) { ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, fireBlockPos, Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence()); - session.sendDownstreamPacket(startBreakingPacket); + session.sendDownstreamGamePacket(startBreakingPacket); } ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, vector, Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence()); - session.sendDownstreamPacket(startBreakingPacket); + session.sendDownstreamGamePacket(startBreakingPacket); break; } case CONTINUE_BREAK: @@ -236,7 +232,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket // Break the block ServerboundPlayerActionPacket finishBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.FINISH_DIGGING, vector, Direction.VALUES[packet.getFace()], session.getWorldCache().nextPredictionSequence()); - session.sendDownstreamPacket(finishBreakingPacket); + session.sendDownstreamGamePacket(finishBreakingPacket); session.setBlockBreakStartTime(0); break; } @@ -253,13 +249,13 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket if (itemFrameEntity != null) { ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(), InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); - session.sendDownstreamPacket(interactPacket); + session.sendDownstreamGamePacket(interactPacket); break; } } ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, 0); - session.sendDownstreamPacket(abortBreakingPacket); + session.sendDownstreamGamePacket(abortBreakingPacket); LevelEventPacket stopBreak = new LevelEventPacket(); stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK); stopBreak.setPosition(vector.toFloat()); @@ -287,7 +283,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket case MISSED_SWING: // TODO Re-evaluate after pre-1.20.10 is no longer supported? if (session.getArmAnimationTicks() == -1) { - session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); + session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); session.activateArmAnimationTicking(); // Send packet to Bedrock so it knows @@ -297,6 +293,40 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket session.sendUpstreamPacket(animatePacket); } break; + case START_FLYING: // Since 1.20.30 + if (session.isCanFly()) { + if (session.getGameMode() == GameMode.SPECTATOR) { + // should already be flying + session.sendAdventureSettings(); + break; + } + + if (session.getPlayerEntity().getFlag(EntityFlag.SWIMMING) && session.getCollisionManager().isPlayerInWater()) { + // As of 1.18.1, Java Edition cannot fly while in water, but it can fly while crawling + // If this isn't present, swimming on a 1.13.2 server and then attempting to fly will put you into a flying/swimming state that is invalid on JE + session.sendAdventureSettings(); + break; + } + + session.setFlying(true); + session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(true)); + } else { + // update whether we can fly + session.sendAdventureSettings(); + // stop flying + PlayerActionPacket stopFlyingPacket = new PlayerActionPacket(); + stopFlyingPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); + stopFlyingPacket.setAction(PlayerActionType.STOP_FLYING); + stopFlyingPacket.setBlockPosition(Vector3i.ZERO); + stopFlyingPacket.setResultPosition(Vector3i.ZERO); + stopFlyingPacket.setFace(0); + session.sendUpstreamPacket(stopFlyingPacket); + } + break; + case STOP_FLYING: + session.setFlying(false); + session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(false)); + break; } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java index 49ce28167..bf59bd7bc 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java @@ -68,16 +68,16 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket> } ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(entity.getEntityId(), InteractAction.INTERACT, Hand.MAIN_HAND, session.isSneaking()); - session.sendDownstreamPacket(interactPacket); + session.sendDownstreamGamePacket(interactPacket); break; case DAMAGE: ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entity.getEntityId(), InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); - session.sendDownstreamPacket(attackPacket); + session.sendDownstreamGamePacket(attackPacket); break; case LEAVE_VEHICLE: ServerboundPlayerCommandPacket sneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING); - session.sendDownstreamPacket(sneakPacket); + session.sendDownstreamGamePacket(sneakPacket); Entity currentVehicle = session.getPlayerEntity().getVehicle(); if (currentVehicle != null) { @@ -123,7 +123,7 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket> if (ridingEntity instanceof AbstractHorseEntity || (ridingEntity != null && ridingEntity.getDefinition().entityType() == EntityType.CHEST_BOAT)) { // This mob has an inventory of its own that we should open instead. ServerboundPlayerCommandPacket openVehicleWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_VEHICLE_INVENTORY); - session.sendDownstreamPacket(openVehicleWindowPacket); + session.sendDownstreamGamePacket(openVehicleWindowPacket); } else { session.setOpenInventory(session.getPlayerInventory()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java index cae25e2a3..d81c0abab 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java @@ -83,7 +83,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack entity.setHeadYaw(headYaw); entity.setOnGround(packet.isOnGround()); - session.sendDownstreamPacket(playerRotationPacket); + session.sendDownstreamGamePacket(playerRotationPacket); } else { if (session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), true)) { return; @@ -130,7 +130,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack entity.setOnGround(onGround); // Send final movement changes - session.sendDownstreamPacket(movePacket); + session.sendDownstreamGamePacket(movePacket); if (teleportThroughVoidFloor) { // Work around there being a floor at the bottom of the world and teleport the player below it diff --git a/core/src/main/java/org/geysermc/connector/network/session/auth/AuthData.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockRequestPermissionsPacket.java similarity index 60% rename from core/src/main/java/org/geysermc/connector/network/session/auth/AuthData.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockRequestPermissionsPacket.java index cca7aa48c..0eb648c43 100644 --- a/core/src/main/java/org/geysermc/connector/network/session/auth/AuthData.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockRequestPermissionsPacket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2023 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 @@ -23,33 +23,21 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.session.auth; +package org.geysermc.geyser.translator.protocol.bedrock.entity.player; -import java.util.UUID; +import org.cloudburstmc.protocol.bedrock.packet.RequestPermissionsPacket; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; /** - * Deprecated, legacy code. Serves as a wrapper around - * the class used now. - * - * @deprecated legacy code + * Sent occasionally by a BDS client when opening the client side server settings menu. */ -@Deprecated -public class AuthData { - private final org.geysermc.geyser.session.auth.AuthData handle; +@Translator(packet = RequestPermissionsPacket.class) +public class BedrockRequestPermissionsPacket extends PacketTranslator<RequestPermissionsPacket> { - public AuthData(org.geysermc.geyser.session.auth.AuthData handle) { - this.handle = handle; - } - - public String getName() { - return this.handle.name(); - } - - public UUID getUUID() { - return this.handle.uuid(); - } - - public String getXboxUUID() { - return this.handle.xuid(); + @Override + public void translate(GeyserSession session, RequestPermissionsPacket packet) { + session.sendAdventureSettings(); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockRiderJumpTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockRiderJumpTranslator.java index 0d0ec4703..f7ac81219 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockRiderJumpTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockRiderJumpTranslator.java @@ -41,7 +41,7 @@ public class BedrockRiderJumpTranslator extends PacketTranslator<RiderJumpPacket Entity vehicle = session.getPlayerEntity().getVehicle(); if (vehicle instanceof AbstractHorseEntity) { ServerboundPlayerCommandPacket playerCommandPacket = new ServerboundPlayerCommandPacket(vehicle.getEntityId(), PlayerState.START_HORSE_JUMP, packet.getJumpStrength()); - session.sendDownstreamPacket(playerCommandPacket); + session.sendDownstreamGamePacket(playerCommandPacket); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java index c818cc910..df28f7ca7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDefaultGameTypeTranslator.java @@ -41,7 +41,7 @@ public class BedrockSetDefaultGameTypeTranslator extends PacketTranslator<SetDef */ @Override public void translate(GeyserSession session, SetDefaultGameTypePacket packet) { - if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) { + if (session.getOpPermissionLevel() >= 2 && session.hasPermission("geyser.settings.server")) { session.getGeyser().getWorldManager().setDefaultGameMode(session, GameMode.byId(packet.getGamemode())); } // Stop the client from updating their own Gamemode without telling the server diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java index a36aa77df..b996a96b1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetDifficultyTranslator.java @@ -39,7 +39,7 @@ public class BedrockSetDifficultyTranslator extends PacketTranslator<SetDifficul */ @Override public void translate(GeyserSession session, SetDifficultyPacket packet) { - if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) { + if (session.getOpPermissionLevel() >= 2 && session.hasPermission("geyser.settings.server")) { if (packet.getDifficulty() != session.getWorldCache().getDifficulty().ordinal()) { session.getGeyser().getWorldManager().setDifficulty(session, Difficulty.from(packet.getDifficulty())); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java index a1c2c2987..2d8d420f8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java @@ -45,7 +45,7 @@ public class BedrockSetPlayerGameTypeTranslator extends PacketTranslator<SetPlay @Override public void translate(GeyserSession session, SetPlayerGameTypePacket packet) { // yes, if you are OP - if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) { + if (session.getOpPermissionLevel() >= 2 && session.hasPermission("geyser.settings.server")) { if (packet.getGamemode() != session.getGameMode().ordinal()) { // Bedrock has more Gamemodes than Java, leading to cases 5 (for "default") and 6 (for "spectator") being sent // https://github.com/CloudburstMC/Protocol/blob/3.0/bedrock-codec/src/main/java/org/cloudburstmc/protocol/bedrock/data/GameType.java diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java index 2b48801d8..76cd82feb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java @@ -57,7 +57,7 @@ public class BedrockLevelSoundEventTranslator extends PacketTranslator<LevelSoun // ATTACK_NODAMAGE = player clicked air // This should only be revisited if Bedrock packets get full Java parity, or Bedrock starts sending arm // animation packets after ATTACK_NODAMAGE, OR ATTACK_NODAMAGE gets removed/isn't sent in the same spot - session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); + session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); session.activateArmAnimationTicking(); // Send packet to Bedrock so it knows diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundResourcePacksPacket.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundResourcePacksPacket.java new file mode 100644 index 000000000..cc2733076 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundResourcePacksPacket.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019-2023 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.translator.protocol.java; + +import com.github.steveice10.mc.protocol.data.game.ResourcePackStatus; +import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundResourcePackPacket; +import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundResourcePackPacket; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; + +@Translator(packet = ClientboundResourcePackPacket.class) +public class JavaClientboundResourcePacksPacket extends PacketTranslator<ClientboundResourcePackPacket> { + + @Override + public void translate(GeyserSession session, ClientboundResourcePackPacket packet) { + // We need to "answer" this to avoid timeout issues related to resource packs + // If packs are required, we need to lie to the server that we accepted them, as we get kicked otherwise. + if (packet.isRequired()) { + session.sendDownstreamPacket(new ServerboundResourcePackPacket(ResourcePackStatus.SUCCESSFULLY_LOADED)); + } else { + session.sendDownstreamPacket(new ServerboundResourcePackPacket(ResourcePackStatus.DECLINED)); + } + } +} 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 80f21a1b3..2282d2d7b 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 @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCustomPayloadPacket; +import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundCustomPayloadPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomQueryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomQueryTranslator.java index 89df63898..6096af12d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomQueryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomQueryTranslator.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.translator.protocol.java; import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundCustomQueryPacket; -import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket; +import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -40,8 +40,8 @@ public class JavaCustomQueryTranslator extends PacketTranslator<ClientboundCusto public void translate(GeyserSession session, ClientboundCustomQueryPacket packet) { // A vanilla client doesn't know any PluginMessage in the Login state, so we don't know any either. // Note: Fabric Networking API v1 will not let the client log in without sending this - session.sendDownstreamPacket( - new ServerboundCustomQueryPacket(packet.getMessageId(), null) + session.sendDownstreamLoginPacket( + new ServerboundCustomQueryAnswerPacket(packet.getMessageId(), null) ); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisconnectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisconnectTranslator.java index 96b0e3dbd..8bf5ae4ba 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisconnectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaDisconnectTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundDisconnectPacket; +import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundDisconnectPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java index 7f8500ce4..12f96360b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaGameProfileTranslator.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.translator.protocol.java; import com.github.steveice10.mc.auth.data.GameProfile; +import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; import com.github.steveice10.mc.protocol.packet.login.clientbound.ClientboundGameProfilePacket; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.entity.type.player.PlayerEntity; @@ -33,7 +34,11 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.SkinManager; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.geyser.util.PluginMessageUtils; +/** + * ClientboundGameProfilePacket triggers protocol change LOGIN -> CONFIGURATION + */ @Translator(packet = ClientboundGameProfilePacket.class) public class JavaGameProfileTranslator extends PacketTranslator<ClientboundGameProfilePacket> { @@ -65,5 +70,9 @@ public class JavaGameProfileTranslator extends PacketTranslator<ClientboundGameP // We no longer need these variables; they're just taking up space in memory now session.setCertChainData(null); session.getClientData().setOriginalString(null); + + // configuration phase stuff that the vanilla client replies with after receiving the GameProfilePacket + session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData())); + session.sendJavaClientSettings(); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java index dc7b7f316..da8358da2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundKeepAlivePacket; +import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundKeepAlivePacket; import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; 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 30a76a912..05d08a9e0 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 @@ -25,30 +25,20 @@ package org.geysermc.geyser.translator.protocol.java; +import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerSpawnInfo; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; import org.cloudburstmc.protocol.bedrock.data.GameRuleData; import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket; import org.cloudburstmc.protocol.bedrock.packet.SetPlayerGameTypePacket; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler; -import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.TextDecoration; -import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.EntityUtils; -import org.geysermc.geyser.util.JavaCodecUtil; -import org.geysermc.geyser.util.PluginMessageUtils; - -import java.util.Map; @Translator(packet = ClientboundLoginPacket.class) public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket> { @@ -63,42 +53,22 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket session.setErosionHandler(new GeyserboundHandshakePacketHandler(session)); } - Map<String, JavaDimension> dimensions = session.getDimensions(); - dimensions.clear(); - - JavaDimension.load(packet.getRegistry(), dimensions); - - Int2ObjectMap<TextDecoration> chatTypes = session.getChatTypes(); - chatTypes.clear(); - for (CompoundTag tag : JavaCodecUtil.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) { - // The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. - int id = ((IntTag) tag.get("id")).getValue(); - CompoundTag element = tag.get("element"); - CompoundTag chat = element.get("chat"); - TextDecoration textDecoration = null; - if (chat != null) { - textDecoration = new TextDecoration(chat); - } - chatTypes.put(id, textDecoration); - } + PlayerSpawnInfo spawnInfo = packet.getCommonPlayerSpawnInfo(); // If the player is already initialized and a join game packet is sent, they // are swapping servers if (session.isSpawned()) { - String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), packet.getDimension()); + String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), spawnInfo.getDimension()); DimensionUtils.switchDimension(session, fakeDim); session.getWorldCache().removeScoreboard(); } - session.setWorldName(packet.getWorldName()); + session.setWorldName(spawnInfo.getWorldName()); session.setLevels(packet.getWorldNames()); - BiomeTranslator.loadServerBiomes(session, packet.getRegistry()); - session.getTagCache().clear(); + session.setGameMode(spawnInfo.getGameMode()); - session.setGameMode(packet.getGameMode()); - - String newDimension = packet.getDimension(); + String newDimension = spawnInfo.getDimension(); boolean needsSpawnPacket = !session.isSentSpawnPacket(); if (needsSpawnPacket) { @@ -113,11 +83,11 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket if (!needsSpawnPacket) { SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); - playerGameTypePacket.setGamemode(EntityUtils.toBedrockGamemode(packet.getGameMode()).ordinal()); + playerGameTypePacket.setGamemode(EntityUtils.toBedrockGamemode(spawnInfo.getGameMode()).ordinal()); session.sendUpstreamPacket(playerGameTypePacket); } - entity.setLastDeathPosition(packet.getLastDeathPos()); + entity.setLastDeathPosition(spawnInfo.getLastDeathPos()); entity.updateBedrockMetadata(); @@ -130,16 +100,10 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket session.setServerRenderDistance(packet.getViewDistance()); - // TODO customize + // send this again now that we know the server render distance + // as the bedrock client isn't required to send a render distance session.sendJavaClientSettings(); - session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData())); - - // TODO don't send two packets -// if (true) { -// session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", Constants.PLUGIN_MESSAGE.getBytes(StandardCharsets.UTF_8))); -// } - // register the plugin messaging channels used in Floodgate if (session.remoteServer().authType() == AuthType.FLOODGATE) { //todo // session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", PluginMessageChannels.getFloodgateRegisterData())); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPingTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPingTranslator.java index faff85fec..c966f3abb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPingTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaPingTranslator.java @@ -25,8 +25,8 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPingPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundPongPacket; +import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundPingPacket; +import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundPongPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRegistryDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRegistryDataTranslator.java new file mode 100644 index 000000000..f5c0dfde2 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRegistryDataTranslator.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019-2023 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.translator.protocol.java; + +import com.github.steveice10.mc.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.geysermc.geyser.level.JavaDimension; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.TextDecoration; +import org.geysermc.geyser.translator.level.BiomeTranslator; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.geyser.util.JavaCodecUtil; + +import java.util.Map; + +@Translator(packet = ClientboundRegistryDataPacket.class) +public class JavaRegistryDataTranslator extends PacketTranslator<ClientboundRegistryDataPacket> { + + @Override + public void translate(GeyserSession session, ClientboundRegistryDataPacket packet) { + Map<String, JavaDimension> dimensions = session.getDimensions(); + dimensions.clear(); + JavaDimension.load(packet.getRegistry(), dimensions); + + Int2ObjectMap<TextDecoration> chatTypes = session.getChatTypes(); + chatTypes.clear(); + for (CompoundTag tag : JavaCodecUtil.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) { + // The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla. + int id = ((IntTag) tag.get("id")).getValue(); + CompoundTag element = tag.get("element"); + CompoundTag chat = element.get("chat"); + TextDecoration textDecoration = null; + if (chat != null) { + textDecoration = new TextDecoration(chat); + } + chatTypes.put(id, textDecoration); + } + + BiomeTranslator.loadServerBiomes(session, packet.getRegistry()); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java index 71f5dc8fc..fb7536b19 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; +import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerSpawnInfo; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundRespawnPacket; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; @@ -46,6 +47,7 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa @Override public void translate(GeyserSession session, ClientboundRespawnPacket packet) { SessionPlayerEntity entity = session.getPlayerEntity(); + PlayerSpawnInfo spawnInfo = packet.getCommonPlayerSpawnInfo(); session.setSpawned(false); @@ -56,13 +58,13 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa session.setOpenInventory(null); session.setClosingInventory(false); - entity.setLastDeathPosition(packet.getLastDeathPos()); + entity.setLastDeathPosition(spawnInfo.getLastDeathPos()); entity.updateBedrockMetadata(); SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); - playerGameTypePacket.setGamemode(EntityUtils.toBedrockGamemode(packet.getGamemode()).ordinal()); + playerGameTypePacket.setGamemode(EntityUtils.toBedrockGamemode(spawnInfo.getGameMode()).ordinal()); session.sendUpstreamPacket(playerGameTypePacket); - session.setGameMode(packet.getGamemode()); + session.setGameMode(spawnInfo.getGameMode()); if (session.isRaining()) { LevelEventPacket stopRainPacket = new LevelEventPacket(); @@ -82,14 +84,14 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa session.setThunder(false); } - String newDimension = packet.getDimension(); - if (!session.getDimension().equals(newDimension) || !packet.getWorldName().equals(session.getWorldName())) { + String newDimension = spawnInfo.getDimension(); + if (!session.getDimension().equals(newDimension) || !spawnInfo.getWorldName().equals(session.getWorldName())) { // Switching to a new world (based off the world name change or new dimension); send a fake dimension change if (DimensionUtils.javaToBedrock(session.getDimension()) == DimensionUtils.javaToBedrock(newDimension)) { String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), newDimension); DimensionUtils.switchDimension(session, fakeDim); } - session.setWorldName(packet.getWorldName()); + session.setWorldName(spawnInfo.getWorldName()); DimensionUtils.switchDimension(session, newDimension); ChunkUtils.loadDimension(session); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateTagsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateTagsTranslator.java index a899077f8..ae59cf0f8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateTagsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateTagsTranslator.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateTagsPacket; +import com.github.steveice10.mc.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index 50582974d..4b1483bbf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -120,7 +120,7 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit if (fishingHook.getBedrockTargetId() == session.getPlayerEntity().getGeyserId()) { Entity hookOwner = session.getEntityCache().getEntityByGeyserId(fishingHook.getBedrockOwnerId()); if (hookOwner != null) { - // https://minecraft.gamepedia.com/Fishing_Rod#Hooking_mobs_and_other_entities + // https://minecraft.wiki/w/Fishing_Rod#Hooking_mobs_and_other_entities SetEntityMotionPacket motionPacket = new SetEntityMotionPacket(); motionPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); motionPacket.setMotion(hookOwner.getPosition().sub(session.getPlayerEntity().getPosition()).mul(0.1f)); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java index 128b051a9..e56a272ab 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaUpdateMobEffectTranslator.java @@ -42,8 +42,9 @@ public class JavaUpdateMobEffectTranslator extends PacketTranslator<ClientboundU if (entity == session.getPlayerEntity()) { session.getEffectCache().setEffect(packet.getEffect(), packet.getAmplifier()); } - if (entity == null) + if (entity == null) { return; + } int duration = packet.getDuration(); if (duration < 0) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java index e711a517e..3debb7f5f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java @@ -29,6 +29,7 @@ import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.protocol.data.game.PlayerListEntry; import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; import org.geysermc.geyser.GeyserImpl; @@ -41,6 +42,7 @@ import org.geysermc.geyser.translator.protocol.Translator; import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.UUID; @Translator(packet = ClientboundPlayerInfoUpdatePacket.class) public class JavaPlayerInfoUpdateTranslator extends PacketTranslator<ClientboundPlayerInfoUpdatePacket> { @@ -50,13 +52,24 @@ public class JavaPlayerInfoUpdateTranslator extends PacketTranslator<Clientbound if (actions.contains(PlayerListEntryAction.ADD_PLAYER)) { for (PlayerListEntry entry : packet.getEntries()) { - GameProfile profile = entry.getProfile(); + @Nullable GameProfile profile = entry.getProfile(); + + UUID id = entry.getProfileId(); + String name = null; + String texturesProperty = null; + + if (profile != null) { + name = profile.getName(); + + GameProfile.Property textures = profile.getProperty("textures"); + if (textures != null) { + texturesProperty = textures.getValue(); + } + } + + boolean self = id.equals(session.getPlayerEntity().getUuid()); + PlayerEntity playerEntity; - boolean self = profile.getId().equals(session.getPlayerEntity().getUuid()); - - GameProfile.Property textures = profile.getProperty("textures"); - String texturesProperty = textures == null ? null : textures.getValue(); - if (self) { // Entity is ourself playerEntity = session.getPlayerEntity(); @@ -66,17 +79,17 @@ public class JavaPlayerInfoUpdateTranslator extends PacketTranslator<Clientbound session, -1, session.getEntityCache().getNextEntityId().incrementAndGet(), - profile.getId(), + id, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, - profile.getName(), + name, texturesProperty ); session.getEntityCache().addPlayerEntity(playerEntity); } - playerEntity.setUsername(profile.getName()); + playerEntity.setUsername(name); playerEntity.setTexturesProperty(texturesProperty); if (self) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java index a2fc0c07c..f2c566a23 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java @@ -133,9 +133,9 @@ public class JavaPlayerPositionTranslator extends PacketTranslator<ClientboundPl private void acceptTeleport(GeyserSession session, double x, double y, double z, float yaw, float pitch, int id) { // Confirm the teleport when we receive it to match Java edition ServerboundAcceptTeleportationPacket teleportConfirmPacket = new ServerboundAcceptTeleportationPacket(id); - session.sendDownstreamPacket(teleportConfirmPacket); + session.sendDownstreamGamePacket(teleportConfirmPacket); // Servers (especially ones like Hypixel) expect exact coordinates given back to them. ServerboundMovePlayerPosRotPacket positionPacket = new ServerboundMovePlayerPosRotPacket(false, x, y, z, yaw, pitch); - session.sendDownstreamPacket(positionPacket); + session.sendDownstreamGamePacket(positionPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java index 6d25500b0..c17c9955d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java @@ -31,11 +31,14 @@ import com.github.steveice10.mc.protocol.data.game.entity.object.ProjectileData; import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; import org.cloudburstmc.math.vector.Vector3f; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.*; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.skin.SkinManager; +import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -44,15 +47,44 @@ public class JavaAddEntityTranslator extends PacketTranslator<ClientboundAddEnti @Override public void translate(GeyserSession session, ClientboundAddEntityPacket packet) { + EntityDefinition<?> definition = Registries.ENTITY_DEFINITIONS.get(packet.getType()); + if (definition == null) { + session.getGeyser().getLogger().warning("Could not find an entity definition with type " + packet.getType()); + return; + } + Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); Vector3f motion = Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ()); float yaw = packet.getYaw(); float pitch = packet.getPitch(); float headYaw = packet.getHeadYaw(); - EntityDefinition<?> definition = Registries.ENTITY_DEFINITIONS.get(packet.getType()); - if (definition == null) { - session.getGeyser().getLogger().warning("Could not find an entity definition with type " + packet.getType()); + if (packet.getType() == EntityType.PLAYER) { + + PlayerEntity entity; + if (packet.getUuid().equals(session.getPlayerEntity().getUuid())) { + // Server is sending a fake version of the current player + entity = new PlayerEntity(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), + session.getPlayerEntity().getUuid(), position, motion, yaw, pitch, headYaw, session.getPlayerEntity().getUsername(), + session.getPlayerEntity().getTexturesProperty()); + } else { + entity = session.getEntityCache().getPlayerEntity(packet.getUuid()); + if (entity == null) { + GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.entity.player.failed_list", packet.getUuid())); + return; + } + + entity.setEntityId(packet.getEntityId()); + entity.setPosition(position); + entity.setYaw(yaw); + entity.setPitch(pitch); + entity.setHeadYaw(headYaw); + entity.setMotion(motion); + } + session.getEntityCache().cacheEntity(entity); + + entity.sendPlayer(); + SkinManager.requestAndHandleSkinAndCape(entity, session, null); return; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPlayerTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPlayerTranslator.java deleted file mode 100644 index 20a5f8213..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPlayerTranslator.java +++ /dev/null @@ -1,72 +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.geyser.translator.protocol.java.entity.spawn; - -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddPlayerPacket; -import org.cloudburstmc.math.vector.Vector3f; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.entity.type.player.PlayerEntity; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.skin.SkinManager; -import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; - -@Translator(packet = ClientboundAddPlayerPacket.class) -public class JavaAddPlayerTranslator extends PacketTranslator<ClientboundAddPlayerPacket> { - - @Override - public void translate(GeyserSession session, ClientboundAddPlayerPacket packet) { - Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); - float yaw = packet.getYaw(); - float pitch = packet.getPitch(); - float headYaw = packet.getYaw(); - - PlayerEntity entity; - if (packet.getUuid().equals(session.getPlayerEntity().getUuid())) { - // Server is sending a fake version of the current player - entity = new PlayerEntity(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), - session.getPlayerEntity().getUuid(), position, Vector3f.ZERO, yaw, pitch, headYaw, session.getPlayerEntity().getUsername(), - session.getPlayerEntity().getTexturesProperty()); - } else { - entity = session.getEntityCache().getPlayerEntity(packet.getUuid()); - if (entity == null) { - GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.entity.player.failed_list", packet.getUuid())); - return; - } - - entity.setEntityId(packet.getEntityId()); - entity.setPosition(position); - entity.setYaw(yaw); - entity.setPitch(pitch); - entity.setHeadYaw(headYaw); - } - session.getEntityCache().cacheEntity(entity); - - entity.sendPlayer(); - SkinManager.requestAndHandleSkinAndCape(entity, session, null); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenScreenTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenScreenTranslator.java index 3a18e0b78..8951f7171 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenScreenTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenScreenTranslator.java @@ -63,7 +63,7 @@ public class JavaOpenScreenTranslator extends PacketTranslator<ClientboundOpenSc InventoryUtils.closeInventory(session, openInventory.getJavaId(), true); } ServerboundContainerClosePacket closeWindowPacket = new ServerboundContainerClosePacket(packet.getContainerId()); - session.sendDownstreamPacket(closeWindowPacket); + session.sendDownstreamGamePacket(closeWindowPacket); return; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaChunkBatchFinishedTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaChunkBatchFinishedTranslator.java new file mode 100644 index 000000000..115222c6c --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaChunkBatchFinishedTranslator.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019-2023 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.translator.protocol.java.level; + +import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundChunkBatchFinishedPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundChunkBatchReceivedPacket; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; + +@Translator(packet = ClientboundChunkBatchFinishedPacket.class) +public class JavaChunkBatchFinishedTranslator extends PacketTranslator<ClientboundChunkBatchFinishedPacket> { + + @Override + public void translate(GeyserSession session, ClientboundChunkBatchFinishedPacket packet) { + // server just sent a batch of LevelChunkWithLightPackets + // the vanilla client uses a ChunkBatchSizeCalculator to calculate the desiredChunksPerTick, + // but currently we just send an arbitrary value. server clamps the value between 0.01 and 64. + session.sendDownstreamGamePacket(new ServerboundChunkBatchReceivedPacket(20)); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java index 9174df756..fb78983bf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java @@ -131,7 +131,7 @@ public class JavaGameEventTranslator extends PacketTranslator<ClientboundGameEve switch ((EnterCreditsValue) packet.getValue()) { case SEEN_BEFORE -> { ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN); - session.sendDownstreamPacket(javaRespawnPacket); + session.sendDownstreamGamePacket(javaRespawnPacket); } case FIRST_TIME -> { ShowCreditsPacket showCreditsPacket = new ShowCreditsPacket(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java index d59b40b8f..aecb304db 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java @@ -31,6 +31,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.Clientb import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.protocol.bedrock.data.ParticleType; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelEventGenericPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; @@ -103,6 +104,10 @@ public class JavaLevelEventTranslator extends PacketTranslator<ClientboundLevelE effectPacket.setPosition(pos); effectPacket.setData(0); switch (levelEvent) { + case BRUSH_BLOCK_COMPLETE -> { + effectPacket.setType(ParticleType.BRUSH_DUST); + session.playSoundEvent(SoundEvent.BRUSH_COMPLETED, pos); // todo 1.20.2 verify this + } case COMPOSTER -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_CROP_GROWTH); @@ -224,6 +229,7 @@ public class JavaLevelEventTranslator extends PacketTranslator<ClientboundLevelE BonemealGrowEventData growEventData = (BonemealGrowEventData) packet.getData(); effectPacket.setData(growEventData.getParticleCount()); } + case EGG_CRACK -> effectPacket.setType(ParticleType.VILLAGER_HAPPY); // both the lil green sparkle case ENDERDRAGON_FIREBALL_EXPLODE -> { effectPacket.setType(org.cloudburstmc.protocol.bedrock.data.LevelEvent.PARTICLE_EYE_OF_ENDER_DEATH); // TODO diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetTimeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetTimeTranslator.java index f45d4bb97..b86b4247c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetTimeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetTimeTranslator.java @@ -40,7 +40,7 @@ public class JavaSetTimeTranslator extends PacketTranslator<ClientboundSetTimePa // Java just sends a negative long if there is no daylight cycle long time = packet.getTime(); - // https://minecraft.gamepedia.com/Day-night_cycle#24-hour_Minecraft_day + // https://minecraft.wiki/w/Day-night_cycle#24-hour_Minecraft_day SetTimePacket setTimePacket = new SetTimePacket(); // We use modulus to prevent an integer overflow // 24000 is the range of ticks that a Minecraft day can be; we times by 8 so all moon phases are visible diff --git a/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java b/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java index 2958de436..17502eae8 100644 --- a/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java @@ -32,7 +32,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.attribute.ModifierOper public class AttributeUtils { /** * Retrieve the base attribute value with all modifiers applied. - * https://minecraft.gamepedia.com/Attribute#Modifiers + * https://minecraft.wiki/w/Attribute#Modifiers * @param attribute The attribute to calculate the total value. * @return The finished attribute with all modifiers applied. */ diff --git a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java index 4f0eccfcb..23949d020 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java @@ -64,7 +64,7 @@ public final class BlockUtils { if (toolType.equals("shears")) return isShearsEffective ? 5.0 : 15.0; if (toolType.equals("")) return 1.0; return switch (toolTier) { - // https://minecraft.gamepedia.com/Breaking#Speed + // https://minecraft.wiki/w/Breaking#Speed case "wooden" -> 2.0; case "stone" -> 4.0; case "iron" -> 6.0; @@ -100,7 +100,7 @@ public final class BlockUtils { return true; } - // https://minecraft.gamepedia.com/Breaking + // https://minecraft.wiki/w/Breaking private static double calculateBreakTime(double blockHardness, String toolTier, boolean canHarvestWithHand, boolean correctTool, boolean canTierMineBlock, String toolType, boolean isShearsEffective, int toolEfficiencyLevel, int hasteLevel, int miningFatigueLevel, boolean insideOfWaterWithoutAquaAffinity, boolean onGround) { diff --git a/core/src/main/java/org/geysermc/geyser/util/FileUtils.java b/core/src/main/java/org/geysermc/geyser/util/FileUtils.java index acd2278fc..99e8f8d7d 100644 --- a/core/src/main/java/org/geysermc/geyser/util/FileUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/FileUtils.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.util; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import org.geysermc.geyser.GeyserBootstrap; @@ -53,7 +55,8 @@ public class FileUtils { * @throws IOException if the config could not be loaded */ public static <T> T loadConfig(File src, Class<T> valueType) throws IOException { - ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); + ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()) + .setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY)); return objectMapper.readValue(src, valueType); } diff --git a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java index 9141ee7ab..0348eca11 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -260,7 +260,7 @@ public class InventoryUtils { // If this is the item we're looking for if (geyserItem.getJavaId() == itemStack.getId() && Objects.equals(geyserItem.getNbt(), itemStack.getNbt())) { ServerboundPickItemPacket packetToSend = new ServerboundPickItemPacket(i); // https://wiki.vg/Protocol#Pick_Item - session.sendDownstreamPacket(packetToSend); + session.sendDownstreamGamePacket(packetToSend); return; } } @@ -274,7 +274,7 @@ public class InventoryUtils { if ((slot - 36) != inventory.getHeldItemSlot()) { setHotbarItem(session, slot); } - session.sendDownstreamPacket(actionPacket); + session.sendDownstreamGamePacket(actionPacket); } } @@ -325,7 +325,7 @@ public class InventoryUtils { } ServerboundPickItemPacket packetToSend = new ServerboundPickItemPacket(i); // https://wiki.vg/Protocol#Pick_Item - session.sendDownstreamPacket(packetToSend); + session.sendDownstreamGamePacket(packetToSend); return; } @@ -340,7 +340,7 @@ public class InventoryUtils { if ((slot - 36) != inventory.getHeldItemSlot()) { setHotbarItem(session, slot); } - session.sendDownstreamPacket(actionPacket); + session.sendDownstreamGamePacket(actionPacket); } else { session.getGeyser().getLogger().debug("Cannot find item for block " + itemName); } diff --git a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java index eabfe3a88..478a6ef96 100644 --- a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java @@ -34,14 +34,12 @@ import org.cloudburstmc.protocol.bedrock.packet.ServerToClientHandshakePacket; import org.cloudburstmc.protocol.bedrock.util.ChainValidationResult; import org.cloudburstmc.protocol.bedrock.util.ChainValidationResult.IdentityData; import org.cloudburstmc.protocol.bedrock.util.EncryptionUtils; -import org.geysermc.cumulus.form.CustomForm; import org.geysermc.cumulus.form.ModalForm; import org.geysermc.cumulus.form.SimpleForm; import org.geysermc.cumulus.response.SimpleFormResponse; import org.geysermc.cumulus.response.result.FormResponseResult; import org.geysermc.cumulus.response.result.ValidFormResponseResult; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.auth.AuthData; import org.geysermc.geyser.session.auth.BedrockClientData; @@ -137,26 +135,16 @@ public class LoginEncryptionUtils { // Set DoDaylightCycle to false so the time doesn't accelerate while we're here session.setDaylightCycle(false); - GeyserConfiguration config = session.getGeyser().getConfig(); - boolean isPasswordAuthEnabled = config.getRemote().isPasswordAuthentication(); - session.sendForm( SimpleForm.builder() .translator(GeyserLocale::getPlayerLocaleString, session.locale()) .title("geyser.auth.login.form.notice.title") .content("geyser.auth.login.form.notice.desc") - .optionalButton("geyser.auth.login.form.notice.btn_login.mojang", isPasswordAuthEnabled) .button("geyser.auth.login.form.notice.btn_login.microsoft") .button("geyser.auth.login.form.notice.btn_disconnect") .closedOrInvalidResultHandler(() -> buildAndShowLoginWindow(session)) .validResultHandler((response) -> { if (response.clickedButtonId() == 0) { - session.setMicrosoftAccount(false); - buildAndShowLoginDetailsWindow(session); - return; - } - - if (response.clickedButtonId() == 1) { session.authenticateWithMicrosoftCode(); return; } @@ -212,19 +200,6 @@ public class LoginEncryptionUtils { }; } - public static void buildAndShowLoginDetailsWindow(GeyserSession session) { - session.sendForm( - CustomForm.builder() - .translator(GeyserLocale::getPlayerLocaleString, session.locale()) - .title("geyser.auth.login.form.details.title") - .label("geyser.auth.login.form.details.desc") - .input("geyser.auth.login.form.details.email", "account@geysermc.org", "") - .input("geyser.auth.login.form.details.pass", "123456", "") - .invalidResultHandler(() -> buildAndShowLoginDetailsWindow(session)) - .closedResultHandler(() -> buildAndShowLoginWindow(session)) - .validResultHandler((response) -> session.authenticate(response.next(), response.next()))); - } - /** * Shows the code that a user must input into their browser */ diff --git a/core/src/main/java/org/geysermc/geyser/util/PluginMessageUtils.java b/core/src/main/java/org/geysermc/geyser/util/PluginMessageUtils.java index 032dd2af7..f6b91388f 100644 --- a/core/src/main/java/org/geysermc/geyser/util/PluginMessageUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/PluginMessageUtils.java @@ -25,7 +25,7 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; +import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; import com.google.common.base.Charsets; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; diff --git a/core/src/main/resources/bedrock/skin/geometry.humanoid.wearingCustomSkull.json b/core/src/main/resources/bedrock/skin/geometry.humanoid.wearingCustomSkull.json index b18d1205b..b3c5533da 100644 --- a/core/src/main/resources/bedrock/skin/geometry.humanoid.wearingCustomSkull.json +++ b/core/src/main/resources/bedrock/skin/geometry.humanoid.wearingCustomSkull.json @@ -145,10 +145,9 @@ { "origin": [ -0.1, 0.0, -2.0 ], "size": [ 4, 12, 4 ], - "uv": [ 0, 16 ] + "uv": [ 16, 48 ] } - ], - "mirror": true + ] }, { @@ -219,4 +218,4 @@ } } ] -} \ No newline at end of file +} diff --git a/core/src/main/resources/bedrock/skin/geometry.humanoid.wearingCustomSkullSlim.json b/core/src/main/resources/bedrock/skin/geometry.humanoid.wearingCustomSkullSlim.json index 3855c92ec..94559e3f7 100644 --- a/core/src/main/resources/bedrock/skin/geometry.humanoid.wearingCustomSkullSlim.json +++ b/core/src/main/resources/bedrock/skin/geometry.humanoid.wearingCustomSkullSlim.json @@ -145,10 +145,9 @@ { "origin": [ -0.1, 0.0, -2.0 ], "size": [ 4, 12, 4 ], - "uv": [ 0, 16 ] + "uv": [ 16, 48 ] } - ], - "mirror": true + ] }, { @@ -219,4 +218,4 @@ } } ] -} \ No newline at end of file +} diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 0034cac05..3f5a2f2e8 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -5,6 +5,10 @@ # # GitHub: https://github.com/GeyserMC/Geyser # Discord: https://discord.gg/geysermc +# Wiki: https://wiki.geysermc.org/ +# +# NOTICE: See https://wiki.geysermc.org/geyser/setup/ for the setup guide. Many video tutorials are outdated. +# In most cases, especially with server hosting providers, further hosting-specific configuration is required. # -------------------------------- bedrock: diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 587220aaf..31ce17e12 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 587220aafb55e80f2a70d6eac2d4b89dc0a005bd +Subproject commit 31ce17e12e991bd841270b99f461641093f42564 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e79236297..3e4c20940 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-connection = "3.0.0.Beta1-20230908.171156-105" raknet = "1.0.0.CR1-20230703.195238-9" blockstateupdater="1.20.30-20230918.203831-4" mcauthlib = "d9d773e" -mcprotocollib = "1.20-2-20230827.192136-1" +mcprotocollib = "1.20.2-1-20231003.141424-6" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" @@ -25,13 +25,13 @@ jline = "3.21.0" terminalconsoleappender = "1.2.0" folia = "1.19.4-R0.1-SNAPSHOT" viaversion = "4.0.0" -adapters = "1.9-SNAPSHOT" +adapters = "1.10-SNAPSHOT" commodore = "2.2" bungeecord = "master-SNAPSHOT" velocity = "3.1.1" -fabric-minecraft = "1.20" +fabric-minecraft = "1.20.2" fabric-loader = "0.14.21" -fabric-api = "0.83.0+1.20" +fabric-api = "0.89.0+1.20.2" [libraries] base-api = { group = "org.geysermc.api", name = "base-api", version.ref = "base-api" }