From e923325246eb2af3323762f6734723cb469a2d31 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 20 Apr 2022 21:22:02 -0400 Subject: [PATCH] Fix stonecutters for Bedrock 1.18.30 Also add an option in debug mode to not log pings in the event they're spammy. --- .../recipe/GeyserStonecutterData.java | 35 ++++++++++++++++ .../network/ConnectorServerEventHandler.java | 4 +- .../geyser/session/GeyserSession.java | 3 +- .../inventory/InventoryTranslator.java | 2 +- .../StonecutterInventoryTranslator.java | 41 +++++++------------ .../item/nbt/EnchantmentTranslator.java | 2 +- .../java/JavaUpdateRecipesTranslator.java | 14 ++++--- 7 files changed, 65 insertions(+), 36 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java new file mode 100644 index 000000000..04a772c31 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java @@ -0,0 +1,35 @@ +/* + * 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.inventory.recipe; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; + +/** + * @param buttonId the button that needs to be pressed for Java Edition to accept this item. + * @param output the expected output of this item when cut. + */ +public record GeyserStonecutterData(int buttonId, ItemStack output) { +} diff --git a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java index 892ddcb64..d41871cdb 100644 --- a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java @@ -47,6 +47,8 @@ import java.nio.charset.StandardCharsets; import java.util.List; public class ConnectorServerEventHandler implements BedrockServerEventHandler { + private static final boolean PRINT_DEBUG_PINGS = Boolean.parseBoolean(System.getProperty("Geyser.PrintPingsInDebugMode", "true")); + /* The following constants are all used to ensure the ping does not reach a length where it is unparsable by the Bedrock client */ @@ -88,7 +90,7 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { @Override public BedrockPong onQuery(InetSocketAddress inetSocketAddress) { - if (geyser.getConfig().isDebugMode()) { + if (geyser.getConfig().isDebugMode() && PRINT_DEBUG_PINGS) { geyser.getLogger().debug(GeyserLocale.getLocaleStringLog("geyser.network.pinged", inetSocketAddress)); } 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 f35378af3..72eaaf0f7 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -98,6 +98,7 @@ import org.geysermc.geyser.entity.type.player.SkullPlayerEntity; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.network.netty.LocalSession; @@ -365,7 +366,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { * The key is the Java ID of the item; the values are all the possible outputs' Java IDs sorted by their string identifier */ @Setter - private Int2ObjectMap stonecutterRecipes; + private Int2ObjectMap stonecutterRecipes; /** * Whether to work around 1.13's different behavior in villager trading menus. diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java index b48709595..6f4ca7ee4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java @@ -144,7 +144,7 @@ public abstract class InventoryTranslator { /** * If {@link #shouldHandleRequestFirst(StackRequestActionData, Inventory)} returns true, this will be called */ - public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { + protected ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { return rejectRequest(request); } 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 ae25a9ffd..e0e2e27bd 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 @@ -31,20 +31,14 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.Ser import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ItemStackRequest; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; -import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.CraftResultsDeprecatedStackRequestActionData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.CraftRecipeStackRequestActionData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; -import it.unimi.dsi.fastutil.ints.IntList; -import org.geysermc.geyser.inventory.GeyserItemStack; -import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.inventory.PlayerInventory; -import org.geysermc.geyser.inventory.StonecutterContainer; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.inventory.BedrockContainerSlot; -import org.geysermc.geyser.inventory.SlotType; +import org.geysermc.geyser.inventory.*; +import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.session.GeyserSession; public class StonecutterInventoryTranslator extends AbstractBlockInventoryTranslator { public StonecutterInventoryTranslator() { @@ -53,31 +47,26 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl @Override protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { - // First is pre-1.18. TODO remove after 1.17.40 support is dropped and refactor stonecutter support to use CraftRecipeStackRequestActionData's recipe ID - return action.getType() == StackRequestActionType.CRAFT_NON_IMPLEMENTED_DEPRECATED || action.getType() == StackRequestActionType.CRAFT_RECIPE; + return action.getType() == StackRequestActionType.CRAFT_RECIPE; } @Override - public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { - // TODO: Also surely to change in the future - StackRequestActionData data = request.getActions()[1]; - if (!(data instanceof CraftResultsDeprecatedStackRequestActionData craftData)) { + protected ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { + // Guarded by shouldHandleRequestFirst + CraftRecipeStackRequestActionData data = (CraftRecipeStackRequestActionData) request.getActions()[0]; + + // Look up all possible options of cutting from this ID + GeyserStonecutterData craftingData = session.getStonecutterRecipes().get(data.getRecipeNetworkId()); + if (craftingData == null) { return rejectRequest(request); } StonecutterContainer container = (StonecutterContainer) inventory; - // Get the ID of the item we are cutting - int id = inventory.getItem(0).getJavaId(); - // Look up all possible options of cutting from this ID - IntList results = session.getStonecutterRecipes().get(id); - if (results == null) { - return rejectRequest(request); - } - - ItemStack javaOutput = ItemTranslator.translateToJava(craftData.getResultItems()[0], session.getItemMappings()); - int button = results.indexOf(javaOutput.getId()); + int button = craftingData.buttonId(); // If we've already pressed the button with this item, no need to press it again! if (container.getStonecutterButton() != button) { + ItemStack javaOutput = craftingData.output(); + // Getting the index of the item in the Java stonecutter list ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getId(), button); session.sendDownstreamPacket(packet); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java index 55d45f67e..cd6d5d6ff 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java @@ -127,7 +127,7 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue()); if (enchantment == null) { - GeyserImpl.getInstance().getLogger().debug("Unknown java enchantment: " + javaEnchId.getValue()); + GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment while NBT item translating: " + javaEnchId.getValue()); return null; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 09ddfce4c..1c5a15b0b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -45,6 +45,7 @@ import lombok.EqualsAndHashCode; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -167,7 +168,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); + Int2ObjectMap stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); for (Int2ObjectMap.Entry> data : unsortedStonecutterData.int2ObjectEntrySet()) { // Sort the list by each output item's Java identifier - this is how it's sorted on Java, and therefore // We can get the correct order for button pressing @@ -176,11 +177,13 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator new IntArrayList()); - outputs.add(stoneCuttingData.getResult().getId()); + // Add the net ID as the key and the button required + output for the value + stonecutterRecipeMap.put(netId++, new GeyserStonecutterData(buttonId++, javaOutput)); } }