From 575fe98c0f67e71eef9479eef03b9d89e0b947c2 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 20 Apr 2022 21:39:35 -0400 Subject: [PATCH] Fix anvils for 1.18.30 Bedrock --- .../geyser/inventory/AnvilContainer.java | 37 +++++++++++++++++++ .../updater/AnvilInventoryUpdater.java | 8 ++-- .../inventory/AnvilInventoryTranslator.java | 27 ++++++++++++++ .../bedrock/BedrockFilterTextTranslator.java | 26 +------------ 4 files changed, 69 insertions(+), 29 deletions(-) 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 a2b7ff9d6..688151a9e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java @@ -26,8 +26,14 @@ package org.geysermc.geyser.inventory; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import lombok.Getter; import lombok.Setter; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.geyser.util.ItemUtils; + +import javax.annotation.Nullable; /** * Used to determine if rename packets should be sent and stores @@ -48,6 +54,7 @@ public class AnvilContainer extends Container { /** * The new name of the item as received from Bedrock */ + @Nullable private String newName = null; private GeyserItemStack lastInput = GeyserItemStack.EMPTY; @@ -59,6 +66,36 @@ public class AnvilContainer extends Container { super(title, id, size, containerType, playerInventory); } + /** + * @return the name to use instead for renaming. + */ + public String checkForRename(GeyserSession session, String rename) { + String correctRename; + newName = rename; + + String originalName = ItemUtils.getCustomName(getInput().getNbt()); + + String plainOriginalName = MessageTranslator.convertToPlainText(originalName, session.getLocale()); + String plainNewName = MessageTranslator.convertToPlainText(rename, session.getLocale()); + if (!plainOriginalName.equals(plainNewName)) { + // Strip out formatting since Java Edition does not allow it + 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); + } 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); + } + + useJavaLevelCost = false; + return correctRename; + } + public GeyserItemStack getInput() { return getItem(0); } 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 d6f72b8d0..655d0f215 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 @@ -384,19 +384,19 @@ public class AnvilInventoryUpdater extends InventoryUpdater { if (enchantTag.get("id") instanceof StringTag javaEnchId) { JavaEnchantment enchantment = JavaEnchantment.getByJavaIdentifier(javaEnchId.getValue()); if (enchantment == null) { - GeyserImpl.getInstance().getLogger().debug("Unknown java enchantment: " + javaEnchId.getValue()); + GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment in anvil: " + javaEnchId.getValue()); continue; } Tag javaEnchLvl = enchantTag.get("lvl"); - if (!(javaEnchLvl instanceof ShortTag || javaEnchLvl instanceof IntTag)) + if (javaEnchLvl == null || !(javaEnchLvl.getValue() instanceof Number number)) continue; // Handle duplicate enchantments if (bedrock) { - enchantments.putIfAbsent(enchantment, ((Number) javaEnchLvl.getValue()).intValue()); + enchantments.putIfAbsent(enchantment, number.intValue()); } else { - enchantments.mergeInt(enchantment, ((Number) javaEnchLvl.getValue()).intValue(), Math::max); + enchantments.mergeInt(enchantment, number.intValue(), Math::max); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java index b09fcb7d4..e56586b14 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java @@ -27,7 +27,12 @@ package org.geysermc.geyser.translator.inventory; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; 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.CraftRecipeOptionalStackRequestActionData; +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 org.geysermc.geyser.inventory.AnvilContainer; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; @@ -35,12 +40,34 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.updater.AnvilInventoryUpdater; +import java.util.Objects; + public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { public AnvilInventoryTranslator() { super(3, "minecraft:anvil[facing=north]", com.nukkitx.protocol.bedrock.data.inventory.ContainerType.ANVIL, AnvilInventoryUpdater.INSTANCE, "minecraft:chipped_anvil", "minecraft:damaged_anvil"); } + @Override + protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { + return action.getType() == StackRequestActionType.CRAFT_RECIPE_OPTIONAL; + } + + @Override + protected ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { + // Guarded by shouldHandleRequestFirst check + CraftRecipeOptionalStackRequestActionData data = (CraftRecipeOptionalStackRequestActionData) request.getActions()[0]; + AnvilContainer container = (AnvilContainer) inventory; + + // Required as of 1.18.30 - FilterTextPackets no longer appear to be sent + String name = request.getFilterStrings()[data.getFilteredStringIndex()]; + if (!Objects.equals(name, container.getNewName())) { + container.checkForRename(session, name); + } + + return super.translateRequest(session, inventory, request); + } + @Override public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { return switch (slotInfoData.getContainer()) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockFilterTextTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockFilterTextTranslator.java index 818829e8f..4e729bc59 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockFilterTextTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockFilterTextTranslator.java @@ -25,15 +25,12 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import com.nukkitx.protocol.bedrock.packet.FilterTextPacket; import org.geysermc.geyser.inventory.AnvilContainer; import org.geysermc.geyser.inventory.CartographyContainer; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.ItemUtils; /** * Used to send strings to the server and filter out unwanted words. @@ -50,28 +47,7 @@ public class BedrockFilterTextTranslator extends PacketTranslator